pax_global_header00006660000000000000000000000064143026416550014520gustar00rootroot0000000000000052 comment=1cb9b7bf470149cf17c10b6e2c7504c4aa3634be alire-1.2.1/000077500000000000000000000000001430264165500126155ustar00rootroot00000000000000alire-1.2.1/.gitattributes000066400000000000000000000004571430264165500155160ustar00rootroot00000000000000# Set the default behavior, in case people don't have core.autocrlf set. * text eol=lf # Declare files that will always have LF line endings on checkout. *.adb text eol=lf *.adc text eol=lf *.ads text eol=lf *.gpr text eol=lf # Mark some misidentified files as always binaries *.pdf -text *.png -text alire-1.2.1/.github/000077500000000000000000000000001430264165500141555ustar00rootroot00000000000000alire-1.2.1/.github/workflows/000077500000000000000000000000001430264165500162125ustar00rootroot00000000000000alire-1.2.1/.github/workflows/ci-docker.yml000066400000000000000000000023151430264165500205760ustar00rootroot00000000000000name: CI Docker on: pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rst' - '**.txt' jobs: build: name: CI on ${{ matrix.tag }} runs-on: ubuntu-latest strategy: matrix: tag: # Those are our dockerhub alire/gnat:tag machines - centos-latest-community-latest # Test unsupported package manager - debian-stable # Test current stable Debian compiler - fedora-latest # Test current Fedora compiler - ubuntu-lts # Test current LTS Ubuntu compiler - arch-rolling # Test Arch compiler (closest to FSF?) steps: - name: Check out repository uses: actions/checkout@v2 with: submodules: true - name: Pull docker image run: docker pull alire/gnat:${{ matrix.tag }} - name: Run test script run: > docker run -v${PWD}:/alire -w /alire alire/gnat:${{ matrix.tag }} scripts/ci-github.sh - name: Upload logs (if failed) if: failure() uses: actions/upload-artifact@master with: name: e3-log-docker-${{ matrix.tag }}.zip path: testsuite/out alire-1.2.1/.github/workflows/ci-linux.yml000066400000000000000000000065201430264165500204700ustar00rootroot00000000000000name: CI linux on: pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rst' - '**.txt' release: types: [created] env: alire_index: "" # Empty index: test with master of community index # Otherwise: test with particular commit/branch # e.g.: index: "git+https://github.com/alire-project/alire-index@deadbeef" jobs: build: name: CI on Linux runs-on: ubuntu-18.04 steps: - name: Check out repository uses: actions/checkout@v2 with: submodules: true - name: Install toolchain uses: ada-actions/toolchain@ce2021 with: distrib: community - name: Install Python 3.x (required for the testsuite) uses: actions/setup-python@v2 with: python-version: '3.x' - name: Run test script run: scripts/ci-github.sh shell: bash env: BRANCH: ${{ github.base_ref }} INDEX: "" - name: Upload binaries uses: actions/upload-artifact@v2 with: name: alr-bin-linux.zip path: | bin/alr LICENSE.txt - name: Upload logs (if failed) if: failure() uses: actions/upload-artifact@master with: name: e3-log-linux.zip path: testsuite/out # Release steps start here. These only run during a release creation. - name: Package binaries if: (github.event_name == 'release') run: zip alr-bin-linux.zip bin/alr LICENSE.txt - name: Retrieve upload URL for the release if: (github.event_name == 'release') id: get_release uses: bruceadams/get-release@v1.2.1 env: GITHUB_TOKEN: ${{ github.token }} - name: Get release version if: (github.event_name == 'release') id: get_version uses: battila7/get-version-action@v2 - name: Upload binary assets if: (github.event_name == 'release') uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url }} asset_path: alr-bin-linux.zip asset_name: alr-${{ steps.get_version.outputs.version-without-v }}-bin-x86_64-linux.zip asset_content_type: application/zip ############ # AppImage # ############ - name: Install AppImage's linuxdeploy if: (github.event_name == 'release') uses: miurahr/install-linuxdeploy-action@v1 with: plugins: appimage - name: Copy license into AppImage if: (github.event_name == 'release') run: | mkdir -p AppDir cp LICENSE.txt AppDir/ - name: Create AppImage if: (github.event_name == 'release') run: > linuxdeploy-x86_64.AppImage --appdir AppDir -e bin/alr -d resources/alr.desktop -i resources/alr.png --output appimage - name: Rename AppImage if: (github.event_name == 'release') run: mv alr*AppImage alr.AppImage - name: Upload AppImage asset if: (github.event_name == 'release') uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url }} asset_path: alr.AppImage asset_name: alr-${{ steps.get_version.outputs.version-without-v }}-x86_64.AppImage asset_content_type: application/x-elf alire-1.2.1/.github/workflows/ci-macos.yml000066400000000000000000000040201430264165500204240ustar00rootroot00000000000000name: CI macOS on: pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rst' - '**.txt' release: types: [created] jobs: build: name: CI on macOS runs-on: macos-latest steps: - name: Check out repository uses: actions/checkout@v2 with: submodules: true - name: Install toolchain uses: ada-actions/toolchain@ce2020 with: distrib: community - name: Install Python 3.x (required for the testsuite) uses: actions/setup-python@v2 with: python-version: '3.x' - name: Run test script run: scripts/ci-github.sh shell: bash env: BRANCH: ${{ github.base_ref }} INDEX: "" - name: Upload binaries uses: actions/upload-artifact@v2 with: name: alr-bin-macos.zip path: | bin/alr LICENSE.txt - name: Upload logs (if failed) if: failure() uses: actions/upload-artifact@master with: name: testsuite-log-macos.zip path: testsuite/out # Release steps start here. These only run during a release creation. - name: Retrieve upload URL for the release if: github.event_name == 'release' id: get_release uses: bruceadams/get-release@v1.2.1 env: GITHUB_TOKEN: ${{ github.token }} - name: Get release version id: get_version if: github.event_name == 'release' uses: battila7/get-version-action@v2 - name: Package release binaries if: github.event_name == 'release' run: zip alr-bin-macos.zip bin/alr LICENSE.txt - name: Upload release assets if: github.event_name == 'release' uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url }} asset_path: alr-bin-macos.zip asset_name: alr-${{ steps.get_version.outputs.version-without-v }}-bin-x86_64-macos.zip asset_content_type: application/zip alire-1.2.1/.github/workflows/ci-toolchain.yml000066400000000000000000000026361430264165500213150ustar00rootroot00000000000000name: CI self+toolchain # Build Alire with `alr build` and using a toolchain installed from Alire # NOTE that tests are not run, this test only checks alr is able to self build. # (Should we also run self-tests here or is it overkill?) on: pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rst' - '**.txt' jobs: build: name: ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: - macos-latest - ubuntu-latest - windows-latest steps: - name: Check out uses: actions/checkout@v2 - uses: actions/cache@v2 with: path: ./cache/gnat-ce-2020 key: ${{ runner.os }}-gnat-ce-2020 - name: Install toolchain uses: ada-actions/toolchain@ce2020 # macOS hasn't 2021 with: distrib: community install_dir: ./cache/gnat-ce-2020 - name: Build alr with default indexed toolchain uses: alire-project/setup-alire@v1 with: branch: master - name: Show dependencies/pins run: alr -n -q with --solve - name: Show build environment run: alr -n printenv - run: alr -n build # For some reason I cannot pinpoint, the Windows build is seeing two # different environments that mess things up. The build succeeds though. - name: Show built version if: matrix.os != 'windows-latest' run: ./bin/alr -n version alire-1.2.1/.github/workflows/ci-unsupported.yml000066400000000000000000000020021430264165500217100ustar00rootroot00000000000000# The purpose of this CI is to run tests in a platform where there is no # detected native package manager name: CI unsupported on: pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rst' - '**.txt' jobs: build: name: CI on unsupported Linux runs-on: ubuntu-18.04 steps: - name: Check out repository uses: actions/checkout@v2 with: submodules: true - name: Install toolchain uses: ada-actions/toolchain@ce2021 with: distrib: community - name: Install Python 3.x (required for the testsuite) uses: actions/setup-python@v2 with: python-version: '3.x' - name: Run test script run: scripts/ci-github.sh shell: bash env: BRANCH: ${{ github.base_ref }} ALIRE_DISABLE_DISTRO: true - name: Upload logs (if failed) if: failure() uses: actions/upload-artifact@master with: name: e3-log-unsupported.zip path: testsuite/out alire-1.2.1/.github/workflows/ci-windows.yml000066400000000000000000000104101430264165500210140ustar00rootroot00000000000000name: CI Windows on: pull_request: paths-ignore: - 'doc/**' - '**.md' - '**.rst' - '**.txt' release: types: [created] jobs: build: name: CI on Windows runs-on: windows-latest steps: - name: Check out repository uses: actions/checkout@v2 with: submodules: true - name: Install toolchain uses: ada-actions/toolchain@ce2021 with: distrib: community - name: Build alr run: gprbuild -j0 -p -P alr_env - name: alr first run to install msys2 run: ./bin/alr --non-interactive help get - name: install tar from msys2 (Git tar in Actions VM does not seem to work) run: C:\Users\runneradmin\.cache\alire\msys64\usr\bin\pacman --noconfirm -S tar - name: Install Python 3.x (required for the testsuite) uses: actions/setup-python@v2 with: python-version: '3.x' - name: Run test script run: scripts/ci-github.sh shell: bash env: BRANCH: ${{ github.base_ref }} INDEX: "" - name: Install alr run: gprinstall -p -P alr_env --prefix=${{ runner.temp }}/alr_install - name: Install qt-installer-framework in msys2 run: C:\Users\runneradmin\.cache\alire\msys64\usr\bin\pacman --noconfirm -S mingw64/mingw-w64-x86_64-qt-installer-framework - name: Add msys2 /mingw64/bin to the path (for qt-installer-framework) run: echo 'C:\Users\runneradmin\.cache\alire\msys64\mingw64\bin' >> $GITHUB_PATH shell: bash - name: Install zip in msys2 run: C:\Users\runneradmin\.cache\alire\msys64\usr\bin\pacman --noconfirm -S zip - name: Add msys2 /usr/bin to the path (for zip) run: echo 'C:\Users\runneradmin\.cache\alire\msys64\usr\bin' >> $GITHUB_PATH shell: bash - name: Run installer build script run: bash make-alire-installer shell: bash working-directory: scripts/installer/ env: ALR_INSTALL_DIR: ${{ runner.temp }}/alr_install ALR_INSTALL_OS: ${{ runner.os }} - name: Upload installer uses: actions/upload-artifact@main with: name: installer-release-package path: scripts/installer/alire-*.exe - name: Upload zip archive uses: actions/upload-artifact@main with: name: zip-release-package path: scripts/installer/alire-*.zip - name: Upload tar archive uses: actions/upload-artifact@main with: name: tar-release-package path: scripts/installer/alire-*.tar.xz - name: Upload logs (if failed) if: failure() uses: actions/upload-artifact@master with: name: testsuite-log-windows.zip path: testsuite/out # Release steps start here. These only run during a release creation. - name: Retrieve upload URL for the release if: github.event_name == 'release' id: get_release uses: bruceadams/get-release@v1.2.1 env: GITHUB_TOKEN: ${{ github.token }} - name: Rename installer if: github.event_name == 'release' run: copy scripts/installer/alire-*.exe scripts/installer/alire-install.exe - name: Get release version if: github.event_name == 'release' id: get_version uses: battila7/get-version-action@v2 - name: Upload installer asset if: github.event_name == 'release' uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url }} asset_path: scripts/installer/alire-install.exe asset_name: alr-${{ steps.get_version.outputs.version-without-v }}-installer-x86_64-windows.exe asset_content_type: application/vnd.microsoft.portable-executable - name: Package binaries if: github.event_name == 'release' run: zip alr-bin-windows.zip bin/alr.exe LICENSE.txt - name: Upload binary asset if: github.event_name == 'release' uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url }} asset_path: alr-bin-windows.zip asset_name: alr-${{ steps.get_version.outputs.version-without-v }}-bin-x86_64-windows.zip asset_content_type: application/zip alire-1.2.1/.github/workflows/spellcheck.yml000066400000000000000000000007211430264165500210520ustar00rootroot00000000000000name: spellcheck on: pull_request: paths: - '**.md' jobs: spellcheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: misspell uses: reviewdog/action-misspell@v1 with: github_token: ${{ secrets.github_token }} reporter: github-pr-review locale: "US" # exclude: '*.lock' # It seems exclusion is not working: # https://github.com/reviewdog/action-hadolint/issues/35 alire-1.2.1/.github/workflows/tarball-full.yml000066400000000000000000000023231430264165500213160ustar00rootroot00000000000000name: Full sources on: release: types: [created] jobs: tar: name: Full sources asset runs-on: ubuntu-latest steps: - name: Install Python 3.x uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install git-archive-all run: pip install git-archive-all - name: Check out repository uses: actions/checkout@v2 with: submodules: true - name: Get release version id: get_version uses: battila7/get-version-action@v2 - name: Create full tarball run: git-archive-all -9 alr-${{ steps.get_version.outputs.version-without-v }}.zip - name: Retrieve upload URL for the release id: get_release uses: bruceadams/get-release@v1.2.1 env: GITHUB_TOKEN: ${{ github.token }} - name: Upload asset uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url }} asset_path: alr-${{ steps.get_version.outputs.version-without-v }}.zip asset_name: alr-${{ steps.get_version.outputs.version-without-v }}-full-sources.zip asset_content_type: application/zipalire-1.2.1/.gitignore000066400000000000000000000003571430264165500146120ustar00rootroot00000000000000# Add any directories, files, or patterns you don't want to be tracked by version control .clang-format .clangd/ *.cgpr *.db *.db-??? *.idea *.lock *.xml *.pyc .*sw? /alire/ bin/ /config/ lib/ obj/ out/ stress/*/ /testsuite/out/ venv/ alire-1.2.1/.gitmodules000066400000000000000000000034331430264165500147750ustar00rootroot00000000000000[submodule "deps/xmlezout"] path = deps/xmlezout url = https://github.com/alire-project/xmlezout.git [submodule "deps/ajunitgen"] path = deps/ajunitgen url = https://github.com/mosteo/ajunitgen.git [submodule "deps/aaa"] path = deps/aaa url = https://github.com/mosteo/aaa.git [submodule "deps/semantic_versioning"] path = deps/semantic_versioning url = https://github.com/alire-project/semantic_versioning.git [submodule "deps/simple_logging"] path = deps/simple_logging url = https://github.com/alire-project/simple_logging.git [submodule "deps/ada-toml"] path = deps/ada-toml url = https://github.com/pmderodat/ada-toml.git [submodule "deps/gnatcoll-slim"] path = deps/gnatcoll-slim url = https://github.com/alire-project/gnatcoll-core.git branch = slim [submodule "testsuite/fixtures/crates/libhello_git"] path = testsuite/fixtures/crates/libhello_git url = https://github.com/alire-project/libhello.git [submodule "deps/ansi"] path = deps/ansi url = https://github.com/mosteo/ansi-ada [submodule "deps/uri-ada"] path = deps/uri-ada url = https://github.com/mosteo/uri-ada.git [submodule "deps/minirest"] path = deps/minirest url = https://github.com/mosteo/minirest [submodule "deps/spdx"] path = deps/spdx url = https://github.com/Fabien-Chouteau/spdx_ada branch = 319ca7bcc1e2eb1843aad1f64aca3ecba91a2bcc [submodule "deps/optional"] path = deps/optional url = https://github.com/mosteo/optional [submodule "deps/toml_slicer"] path = deps/toml_slicer url = https://github.com/mosteo/toml_slicer [submodule "deps/si_units"] path = deps/si_units url = https://github.com/HeisenbugLtd/si_units.git [submodule "deps/stopwatch"] path = deps/stopwatch url = https://github.com/mosteo/stopwatch [submodule "deps/clic"] path = deps/clic url = https://github.com/alire-project/clic.git alire-1.2.1/.gitpod.Dockerfile000066400000000000000000000023341430264165500161540ustar00rootroot00000000000000FROM gitpod/workspace-base:latest ENV PATH=$HOME/gnat/bin:$PATH:/workspace/alire/bin\ GPR_PROJECT_PATH=/home/gitpod/adalib/share/gpr COPY scripts/gnat_install.qs /tmp/ RUN sudo apt-get update \ && sudo apt-get install -y \ libx11-xcb1 \ python3 python3-pip \ && curl -SL https://community.download.adacore.com/v1/a639696a9fd3bdf0be21376cc2dc3129323cbe42?filename=gnat-2020-20200818-x86_64-linux-bin \ --output /tmp/gnat-2020-20200818-x86_64-linux-bin \ && chmod +x /tmp/gnat-2020-20200818-x86_64-linux-bin \ && /tmp/gnat-2020-20200818-x86_64-linux-bin \ --platform minimal --script /tmp/gnat_install.qs InstallPrefix=$HOME/gnat \ && gprinstall --uninstall gpr \ && gprinstall --uninstall aunit \ && gprinstall --uninstall aws \ && gprinstall --uninstall gnatcoll \ && sh -c "rm -rvf /opt/gnat/maintenancetool*" \ && rm -rf $HOME/gnat/share/doc \ && rm -rf $HOME/gnat/share/examples \ && rm -rf $HOME/gnat/share/gps \ && rm -rf $HOME/gnat/share/man \ && find $HOME/gnat/ -type d -empty -delete \ && rm -rf /tmp/gnat-2020-20200818-x86_64-linux-bin \ && sudo apt-get purge -y --auto-remove libx11-xcb1 \ && sudo apt-get clean \ && sudo rm -rf /var/lib/apt/lists/* \ && sudo /usr/bin/pip3 install e3-testsuite alire-1.2.1/.gitpod.yml000066400000000000000000000001531430264165500147030ustar00rootroot00000000000000image: file: .gitpod.Dockerfile vscode: extensions: - adacore.ada@22.0.5:b56gZDvQ5KBm6u34IBzm1g== alire-1.2.1/.vscode/000077500000000000000000000000001430264165500141565ustar00rootroot00000000000000alire-1.2.1/.vscode/settings.json000066400000000000000000000000511430264165500167050ustar00rootroot00000000000000{ "ada.projectFile": "alr_env.gpr" } alire-1.2.1/.vscode/tasks.json000066400000000000000000000014161430264165500162000ustar00rootroot00000000000000{ "version": "2.0.0", "tasks": [ { "type": "shell", "command": "gprbuild -j0 -p -P alr_env.gpr", "problemMatcher": [ "$ada" ], "label": "Alire: Build alr", "group": { "kind": "build", "isDefault": true } }, { "type": "shell", "command": "gprbuild -ws -c -f -s -u -P alr_env.gpr ${file}", "problemMatcher": [ "$ada" ], "label": "Alire: Compile current file", }, { "type": "shell", "command": "gprclean -r -P alr_env.gpr", "problemMatcher": [ "$ada" ], "label": "Alire: Clean all projects", }, { "type": "shell", "command": "/usr/bin/python3 testsuite/run.py", "problemMatcher": [], "label": "Alire: Run testsuite", "group": { "kind": "test", "isDefault": true } } ] }alire-1.2.1/LICENSE.txt000066400000000000000000001045151430264165500144460ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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. This program 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. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . alire-1.2.1/README.md000066400000000000000000000104761430264165500141040ustar00rootroot00000000000000[![Linux CI](https://github.com/alire-project/alire/workflows/CI%20linux/badge.svg)](https://github.com/alire-project/alire/actions) [![Windows CI](https://github.com/alire-project/alire/workflows/CI%20Windows/badge.svg)](https://github.com/alire-project/alire/actions) [![MacOS CI](https://github.com/alire-project/alire/workflows/CI%20macOS/badge.svg)](https://github.com/alire-project/alire/actions) [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/ada-lang/Alire) [![Gitpod ready](https://img.shields.io/badge/Gitpod-ready-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/alire-project/alire) # ALR # ALIRE: Ada LIbrary REpository. A catalog of ready-to-use Ada libraries plus a command-line tool (`alr`) to obtain, build, and incorporate them into your own projects. It aims to fulfill a similar role to Rust's `cargo` or OCaml's `opam`. ### Caveat emptor ### Documentation at this time is a work in progress. Expect further efforts in this direction until this warning is removed. Check the latest information at https://alire.ada.dev/ ## TL;DR ## Available for Linux/macOS/Windows. Download the latest stable version from the [Releases](https://github.com/alire-project/alire/releases) page. See the [Getting Started](doc/getting-started.md) guide for binary downloads. If, instead, you want to test the latest development version, see [Building from sources](#building-from-sources). ## Installation and First Steps ## See the [Getting Started](doc/getting-started.md) guide. ## Building from sources ## The build process of `alr` is straighforward and depends only on a recent GNAT Ada 2012 compiler. All dependencies are included as submodules. A project file (`alr_env.gpr`) is provided to drive the build with all necessary configuration (see the macOS extra step below, though). Follow these steps: 1. Clone the repository: `git clone --recurse-submodules https://github.com/alire-project/alire.git` 1. Enter the cloned repository folder. 1. Only on macOS: define the environment variable `OS=macOS` 1. Build the executable: `gprbuild -j0 -P alr_env` The binary will be found at `bin/alr`. You can run `alr version` to see version and diagnostics information. Sourcing the `scripts/alr-completion.bash` file will provide bash tab autocompletion. ## Building with `alr` If you already have a recent enough `alr` binary, you can alternative build `alr` by simply running `alr build` at the root of the repository. This command will retrieve all necessary dependencies prior to launching the build. The master branch should normally be able to build itself in this fashion, as this is one of our integration tests. ## Design principles ## alr is tailored to userspace, in a similar way to Python's virtualenv. A project or workspace will contain all its dependencies. Some crates benefit from using platform packages. In this case the user will be asked to authorize a `sudo` installation through the platform package manager. Properties and dependencies of projects are managed through a TOML file (`alire.toml`, found at the root of Alire workspaces). This file exists locally for working copies of projects, and the Alire community index stores the files corresponding to its projects. The complete build environment is automatically set up by setting the GPR_PROJECT_PATH environment variable before running `gprbuild`, thus freeing the user from concerns about installation paths. The user simply adds the used projects to its own project GPR file with their simple name. You can check the environment `alr` is using with `alr printenv`. ## Supported platforms ## Alire requires a recent Ada 2012 compiler. In practice, this currently means the latest [GNAT Community](https://www.adacore.com/download) or a somewhat recent GNAT FSF. Continuous integration is run against the Windows and macOS Github Actions images, and a suite of Linux [docker images](https://github.com/alire-project/alire/blob/538a3549a1dbbc6c09728cb987c71187578381b2/.github/workflows/ci-docker.yml#L20) that includes at least Debian stable, Ubuntu LTS, CentOS, Arch and Fedora. The packaged GNAT is used when available from the distribution. Note that platform-provided Ada libraries (such as Debian's GtkAda) require the use of the platform Ada compiler. Otherwise these libraries will be unavailable, potentially making dependent crates unavailable too. alire-1.2.1/alire.gpr000066400000000000000000000036721430264165500144330ustar00rootroot00000000000000with "aaa"; with "ada_toml"; with "alire_common"; with "ajunitgen"; with "ansi"; with "clic"; with "gnatcoll"; with "minirest"; with "optional"; with "semantic_versioning"; with "simple_logging"; with "si_units"; with "spdx"; with "stopwatch"; with "toml_slicer"; with "uri"; with "xml_ez_out"; library project Alire is for Library_Name use "alire"; Src_Dirs := ("src/alire"); case Alire_Common.Host_Os is when "windows" => Src_Dirs := Src_Dirs & ("src/alire/os_windows"); when "osx" => Src_Dirs := Src_Dirs & ("src/alire/os_macos"); when "freebsd" => Src_Dirs := Src_Dirs & ("src/alire/os_freebsd"); when others => Src_Dirs := Src_Dirs & ("src/alire/os_linux"); end case; package Naming is case Alire_Common.Host_OS is when "windows" => for body ("Alire.Platforms.Current") use "alire-platforms-current__windows.adb"; for body ("Alire.Platforms.Folders") use "alire-platforms-folders__windows.adb"; when "osx" => for body ("Alire.Platforms.Current") use "alire-platforms-current__macos.adb"; for body ("Alire.Platforms.Folders") use "alire-platforms-folders__macos.adb"; when "freebsd" => for body ("Alire.Platforms.Current") use "alire-platforms-current__freebsd.adb"; for body ("Alire.Platforms.Folders") use "alire-platforms-folders__freebsd.adb"; when others => for body ("Alire.Platforms.Current") use "alire-platforms-current__linux.adb"; for body ("Alire.Platforms.Folders") use "alire-platforms-folders__linux.adb"; end case; end Naming; for Source_Dirs use Src_Dirs; for Library_Dir use "lib"; for Object_Dir use "obj"; for Languages use ("Ada"); package Compiler renames Alire_Common.Compiler; package Builder renames Alire_Common.Builder; package Binder renames Alire_Common.Binder; package Ide renames Alire_Common.Ide; end Alire; alire-1.2.1/alire.toml000066400000000000000000000052041430264165500146070ustar00rootroot00000000000000name = "alr" description = "Command-line tool from the Alire project" version = "1.2.1-dev" authors = ["Alejandro R. Mosteo", "Fabien Chouteau", "Pierre-Marie de Rodat"] maintainers = ["alejandro@mosteo.com", "chouteau@adacore.com"] maintainers-logins = ["mosteo", "Fabien-Chouteau"] # At some point we should have a separate alire/libalire crate for use of # alire.gpr only. For now this crate is not intended as a dependency but to be # used to build alr. auto-gpr-with = false project-files = ["alr.gpr"] executables = ["alr"] [[depends-on]] aaa = "~0.2.7" ada_toml = "~0.3" ajunitgen = "^1.0.1" ansiada = "~0.1" clic = "~0.2" gnatcoll = "^21" minirest = "~0.2" optional = "~0.0.0" semantic_versioning = "^2" simple_logging = "^1.2" si_units = "~0.2" stopwatch = "~0.1" toml_slicer = "~0.1" uri_ada = "^1" spdx = "~0.2" # For some reason static-pic is causing problems in CLIC [gpr-set-externals] CLIC_LIBRARY_TYPE="static" # Building alr requires the explicit setting of this variable [gpr-set-externals."case(os)"] macos = { OS = "macOS" } # Some dependencies require precise versions during the development cycle: [[pins]] aaa = { url = "https://github.com/mosteo/aaa.git", commit = "906d9eaf4fb8efabfbc3d8cfb34d04ceec340e13" } ada_toml = { url = "https://github.com/pmderodat/ada-toml.git", commit = "2a671ffb1039a036f2bb68bdc88afc8d3dc68c10" } ajunitgen = { url = "https://github.com/mosteo/ajunitgen.git", commit = "e5d01db5e7834d15c4066f0a8e33d780deae3cc9" } ansiada = { url = "https://github.com/mosteo/ansi-ada.git", commit = "acf9afca3afe1f8b8843c061f3cef860d7567307" } clic = { url = "https://github.com/alire-project/clic.git", commit = "185519d65b089c3238e24cfe87f1d22db1f3e0d9" } gnatcoll = { url = "https://github.com/alire-project/gnatcoll-core.git", commit = "92bb91130a9ec628b4c48b7ef9fe7f24d9dc25fa" } minirest = { url = "https://github.com/mosteo/minirest.git", commit = "4550aa356d55b9cd55f26acd34701f646021c5ff" } optional = { url = "https://github.com/mosteo/optional.git", commit = "0c7d20c0c8b48ccb6b25fb648d48382e598c25c3" } semantic_versioning = { url = "https://github.com/alire-project/semantic_versioning.git", commit = "fe4e72e40786589a66d53662639f894fcdb3419c" } simple_logging = { url = "https://github.com/alire-project/simple_logging.git", commit = "02a7de7568af6af7cedd1048901fae8e9477b1d9" } stopwatch = { url = "https://github.com/mosteo/stopwatch.git", commit = "86e7302d29f360f98f568b6015755229949b2194" } toml_slicer = { url = "https://github.com/mosteo/toml_slicer.git", commit = "8b9dff0f450394b07ea71f0eb9b39d9c20e21f9c" } uri_ada = { url = "https://github.com/mosteo/uri-ada.git", commit = "b61eba59099b3ab39e59e228fe4529927f9e849e" } alire-1.2.1/alire_common.gpr000066400000000000000000000050301430264165500157710ustar00rootroot00000000000000abstract project Alire_Common is for Create_Missing_Dirs use "True"; Host_OS := external ("ALIRE_OS", "default"); -- Defined in alr_env.gpr. type Any_Build_Mode is ("debug", "release"); Build_Mode : Any_Build_Mode := external ("ALIRE_BUILD_MODE", "debug"); -- Profile for the build, depending on the use case. Debug favors -- debuggability (for developper convenience) while release favors -- optimizations. type Any_Style_Check_Mode is ("enabled", "disabled"); Style_Check_Mode : Any_Style_Check_Mode := external ("ALIRE_STYLE_CHECK_MODE", "enabled"); Style_Check_Switches := (); case Style_Check_Mode is when "enabled" => Style_Check_Switches := ("-gnatyg", -- Standard checks "-gnatyI", -- no IN mode "-gnatyO", -- all overrides "-gnaty-s"); -- relax fwd decl when "disabled" => Style_Check_Switches := (); end case; package Compiler is case Build_Mode is when "debug" => for Default_Switches ("Ada") use ( -- Build with no optimization in debug mode "-g", "-O0", -- Enable lots of extra runtime checks "-gnatVa", "-gnato", "-fstack-check", "-gnata", -- Enable full errors, verbose details "-gnatf", -- Report Elaboration Circularity Details "-gnatd_F", -- Enable all warnings and treat them as errors "-gnatwae") & Style_Check_Switches; for Default_Switches ("C") use ("-g", "-O0", "-Wall"); -- Likewise for C units when "release" => for Default_Switches ("Ada") use ( -- Build with lots of optimizations. Generate debug info -- (useful for tracebacks). "-O2", "-g", -- Generate position-independent code "-fPIC", -- Enable lots of extra runtime checks "-gnatVa", "-gnatwa", "-gnato", "-fstack-check", "-gnata", "-gnatf", "-fPIC") & Style_Check_Switches; for Default_Switches ("C") use ("-g", "-O2", "-Wall", "-fPIC"); -- Likewise for C units end case; end Compiler; package Builder is for Switches ("Ada") use ("-s", "-j0", "-g"); end Builder; package Binder is for Switches ("Ada") use ("-Es", "-g", "-static"); end Binder; package Ide is for Vcs_Kind use "Git"; end Ide; end Alire_Common; alire-1.2.1/alr.gpr000066400000000000000000000016411430264165500141070ustar00rootroot00000000000000with "aaa"; with "ada_toml"; with "alire"; with "alire_common"; with "ajunitgen"; with "semantic_versioning"; with "simple_logging"; with "uri"; with "xml_ez_out"; project Alr is Src_Dirs := ("src/alr"); case Alire_Common.Host_Os is when "windows" => Src_Dirs := Src_Dirs & ("src/alr/os_windows"); when "osx" => Src_Dirs := Src_Dirs & ("src/alr/os_macos"); when others => Src_Dirs := Src_Dirs & ("src/alr/os_linux"); end case; for Source_Dirs use Src_Dirs; for Object_Dir use "obj"; for Exec_Dir use "bin"; for Main use ("alr-main.adb"); for Languages use ("Ada"); package Compiler renames Alire_Common.Compiler; package Builder is for Switches ("Ada") use Alire_Common.Builder'Switches ("Ada"); for Executable ("alr-main.adb") use "alr"; end Builder; package Binder renames Alire_Common.Binder; package Ide renames Alire_Common.Ide; end Alr; alire-1.2.1/alr_env.gpr000066400000000000000000000037141430264165500147620ustar00rootroot00000000000000aggregate project Alr_Env is for Create_Missing_Dirs use "True"; for Project_Path use ( "deps/aaa", "deps/ada-toml", "deps/ajunitgen", "deps/ansi", "deps/clic", "deps/gnatcoll-slim", "deps/minirest", "deps/optional", "deps/semantic_versioning", "deps/si_units", "deps/simple_logging", "deps/spdx", "deps/stopwatch", "deps/toml_slicer", "deps/uri-ada", "deps/xmlezout" ); for Project_Files use ("alr.gpr"); -- Provide defaults for environment variables that GNATcoll requires for External ("LIBRARY_TYPE") use "static"; for External ("BUILD") use "DEBUG"; Host_OS := external ("OS", "default"); -- On Windows an OS environment variable is defined, we can use it to -- determine if we are compiling on Windows. -- -- On macOS, the nearest equivalent is OSTYPE; however this is -- e.g. "darwin18", so not useful here. Set "macOS" by hand. -- ALIRE_OS is used in alire_common.gpr. -- GNATCOLL_OS is used in gnatcoll.gpr. case Host_OS is when "Windows_NT" | "windows_nt" | "windows" | "Windows" => for External ("ALIRE_OS") use "windows"; for External ("GNATCOLL_OS") use "windows"; when "macOS" | "macos" | "OSX" | "osx" => for External ("ALIRE_OS") use "osx"; for External ("GNATCOLL_OS") use "osx"; when "freebsd" => for External ("ALIRE_OS") use "freebsd"; for External ("GNATCOLL_OS") use "unix"; when others => for External ("ALIRE_OS") use "unix"; for External ("GNATCOLL_OS") use "unix"; end case; end Alr_Env; alire-1.2.1/deps/000077500000000000000000000000001430264165500135505ustar00rootroot00000000000000alire-1.2.1/deps/aaa/000077500000000000000000000000001430264165500142725ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/000077500000000000000000000000001430264165500152465ustar00rootroot00000000000000alire-1.2.1/deps/ajunitgen/000077500000000000000000000000001430264165500155345ustar00rootroot00000000000000alire-1.2.1/deps/ansi/000077500000000000000000000000001430264165500145025ustar00rootroot00000000000000alire-1.2.1/deps/clic/000077500000000000000000000000001430264165500144625ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/000077500000000000000000000000001430264165500163155ustar00rootroot00000000000000alire-1.2.1/deps/minirest/000077500000000000000000000000001430264165500154025ustar00rootroot00000000000000alire-1.2.1/deps/optional/000077500000000000000000000000001430264165500153755ustar00rootroot00000000000000alire-1.2.1/deps/semantic_versioning/000077500000000000000000000000001430264165500176165ustar00rootroot00000000000000alire-1.2.1/deps/si_units/000077500000000000000000000000001430264165500154055ustar00rootroot00000000000000alire-1.2.1/deps/simple_logging/000077500000000000000000000000001430264165500165475ustar00rootroot00000000000000alire-1.2.1/deps/spdx/000077500000000000000000000000001430264165500145265ustar00rootroot00000000000000alire-1.2.1/deps/stopwatch/000077500000000000000000000000001430264165500155645ustar00rootroot00000000000000alire-1.2.1/deps/toml_slicer/000077500000000000000000000000001430264165500160645ustar00rootroot00000000000000alire-1.2.1/deps/uri-ada/000077500000000000000000000000001430264165500150725ustar00rootroot00000000000000alire-1.2.1/deps/xmlezout/000077500000000000000000000000001430264165500154375ustar00rootroot00000000000000alire-1.2.1/dev/000077500000000000000000000000001430264165500133735ustar00rootroot00000000000000alire-1.2.1/dev/devbuild.sh000077500000000000000000000001041430264165500155230ustar00rootroot00000000000000#!/bin/bash gprbuild -j0 -r -p -P `dirname $0`/../alr_env.gpr "$@" alire-1.2.1/dev/edit.sh000077500000000000000000000000301430264165500146500ustar00rootroot00000000000000gnatstudio -P alr_env & alire-1.2.1/dev/gpslaunch.sh000077500000000000000000000001711430264165500157150ustar00rootroot00000000000000#!/bin/bash # Launch latest GPL but with platform compiler ~/opt/gnat-gpl-2017/bin/gps -P `dirname $0`/../alr_env.gpr & alire-1.2.1/dev/pull.sh000077500000000000000000000002611430264165500147050ustar00rootroot00000000000000#/bin/bash git pull --all git submodule update --init --recursive git-recurse "git checkout master" git-recurse "git pull --ff-only" echo ' ' git submodule status --recursive alire-1.2.1/dev/push.sh000077500000000000000000000001431430264165500147070ustar00rootroot00000000000000git pull && git rm -f status/g*.md && git commit status -m "Delete old release status" && git push alire-1.2.1/dev/unused.sh000077500000000000000000000004541430264165500152400ustar00rootroot00000000000000#!/bin/bash gprclean -q -r -Palr_env { find . -path '**src**/*.ads' -o -path '**src**/*.adb' | xargs basename -a gprbuild -j0 -p -q -Palr_env -bargs -R | grep -e '\.ad.$' | xargs -n1 } | sort | uniq -u | grep -v alire-index | grep -v demo | grep -v alire-project.ads | grep -v project_skel alire-1.2.1/doc/000077500000000000000000000000001430264165500133625ustar00rootroot00000000000000alire-1.2.1/doc/2018-03.alr-draft.pdf000066400000000000000000007760371430264165500165660ustar00rootroot00000000000000%PDF-1.5 %¿÷¢þ 243 0 obj << /Linearized 1 /L 261151 /H [ 2077 255 ] /O 247 /E 94966 /N 14 /T 259422 >> endobj 244 0 obj << /Type /XRef /Length 90 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Index [ 243 201 ] /Info 49 0 R /Root 245 0 R /Size 444 /Prev 259423 /ID [<11675611c716c6ccbfd7e7cbe7e29b2f><63a39e37a24dfa0e56966c294d97dc0c>] >> stream xœcbd`àg`b``8 "Ù€HÆF0ù,>DrO‘Ò> Ræ=˜| "]uA¤±d ´±Õ¯€H¡í LŒÿgM``%GI|$ãÒwÃ(9tH¯šô endstream endobj 245 0 obj << /Names 349 0 R /OpenAction 353 0 R /Outlines 313 0 R /PageMode /UseOutlines /Pages 312 0 R /Type /Catalog >> endobj 246 0 obj << /Filter /FlateDecode /S 148 /O 203 /Length 167 >> stream xœc```b`àe`a`àöfd€0›$ÊÀ2ñƒ Âz÷†I jFû;GW3ð6èLQÜÿñKÛñØïÿ~;¬ ïššD+¯¦¯žšÞ=7¬zn\úž¹a5@ê$ŒœšŽß( º Ìd@Îb~°ƒæhõ+W · gnT¾éæ?Û/Ç%Å- ‘—SPlNH #…Ý`{IZË!=Š endstream endobj 247 0 obj << /Annots [ 354 0 R 355 0 R 356 0 R 360 0 R ] /Contents 248 0 R /MediaBox [ 0 0 612 792 ] /Parent 266 0 R /Resources 361 0 R /Type /Page >> endobj 248 0 obj << /Filter /FlateDecode /Length 2633 >> stream xÚ…XK“Û¸¾ûWè©jÈáS$½—ØcÇžd×NÙ³‡Äö¢ »$Á%Àk~}ºÑ ŠÒ¨*'ÐèLJnD‹ý"Z|xõöáÕí?ÖÙ¢ «u²^<ìY‘‡ëx±® ©âÅÃvñm¯~<üóUÄk.[Ø _ÄY˜fëw’²“Ú*ÌÊŠ¶xÓ¨a—Kùz$y´Ô4j3ˆáHbèµQV{Z+:±— v«$_ê¥Y$Y˜W‹ .Â*Mé {ħ{ÙQÏèÑíZóÌ›-,kmŽÆÊ7s*ˆã0ÊËÜé “|½Ò<¬²Â_@þ!ºí iý—Úß4l¢i“t½iŠ(Æ=ª4ŒÖÅ" «¼œi¸ªW&iZt ¿\Ù& Ëi>áùbr…3Wç @ ÈŸž—*Á®Ðc®á¤ ˈMrß«ìhùF[VÑ}·Ê¢åã*Ηö«|)jõ=]§¬S¯Ûûn/;%‡ïiž‹ó=Þ b?[ñ=Ê£ûô 4^²r&YV…\2ˆ#ÐË&Z§×¿zC(Í•Uq˜å…WÎóŠ NÊ0‡8Ûí71(Ññ=ß›¿FÕ4š}ÊÜv7ÔË£(.¹ÿ_7ÐÏ‚‡_{¡º«ÚO³EP„q~f¤ºÏÎt';ë]é÷N¡_“Æp~öÂ& ë÷ÜÉÎ\(ÛËzÒõÝïï¼®qFYÌú`O¼³ƒÏ7ù8JS‹+*©¢ÿ£’s8]:XgaY‚%RðálÍQ´1pvmÃË•sueQ˜—koØÏ.˜Ó,sÁŒœfù²Õ¨.ÒY Ê4Ä"I¥sœ}#Ž V"+ÞÊê­8þm•çKC\FïìÓ*ŽN;4í9 tæS ­^†ÈZ,ïtÛ‚§Z% L?¨ný6Ôc·%z?èý Ú–' ºq+p‚3¹>(ù=ŠÒãj/™FëDÅáf•DKKÃ'e¼åAÉK¼”!?w5Ï>G·«xétp¼&è E}p'F…[­’댄´zíÕ¢¡©Vw1˜ üG ÓXïˆE Ø7B5bÓHšž_¸6óíŹ½V°Ù!ÝÖ`øZwÎSºÃë‚o€ÂíaIÃè-ôt8ö“Éœ—!I ½±³UàîŠTŒZ¾æ@}zì{=X0# ð5»"%#9–QûNu“ZtLBPöv$?.ç*q«ô uF3Цñžá8ÙÌ4ª/ b‚©F÷ׄ™âjœ-52?u4¨mL‘hwzh‰vqH9³uœ9§v.ý÷?EÛ7Δ0Š)ì³ÇÆÎM¯† ù.cÛX8aÊ¿ö =à}¾mÃý/£±Üý(ÌŸ(ªl^ìNÇT®<˜pv,>èîØ‡ƒ$ʤc®Ò#Ñ‚m²‘qà£Q$jùg-{ôšÂwÚ™AXÉëåp½7ÏȆóŒÊz4jÁÐr¸êóœ)À5L<É ÎÒüê„ÛÒ¼ØRäATt~â}ìA¢lÕ k”ÿæ|L†ºÔßÄ×4ÁqNœ³\5(ac”`ìYm½¤!à ¼ërË#ÔC”RZˆ²tR1«ÄÑ(9-OXEØ›ÞØ>Œ „±ææš”>­Ò|ùfÇ1h¯ÈP“)ä¢Ni\8'š§l%Fµ»Pwà*q’>ˆÌo[ŒÏ…êj…qñš¦žå ƒš ·ívƒ@)í0Öærr6à|9ÍQ®é :ò˜$…±‡)‘xàà „WOjDµxMÂÌÎÁt~UÝø3Ø#ùDÂQ÷øÁqÊ^;‚ $]ºXH6)ŒЀ—ƒFS ¥;r`í!mÙª}K$ t¶̺•]KŽÄ ~¨›‘#.IY101J@/E›ª ÓËš¡˜–S&%ÇS–mà­ÛpÖþûÄ—?²‘ÂøÂL’*I8s‘gE.õ«ŒdúZ@9~¶à/óÑlFÑ”`ýêk°¸‚zfÂà"¼»PÒNŠb&ÊѰ÷ÕÅ“~°“Dq2‰…V•çT*P6BB*,÷Õ (9ÂúºÚMoG#´AÏ+5¼|¦)ªß“$½‡gjÙ0ŸûJ k@’ìZi™Fôc¯û'0Þñ«"„BNbOˆ ,ª¡vq‘\bŠw$2¼ò˜gItŠl ã“ Ð¡±ƒ<`è(±p‰äð†w½Ú6¼%ßàH7hÁ¹`ì)VÖ‡N7zÏY§+²º­Ëêo|<ŽÆ(¸Ô°‚‡Ã×KŠÃt–¸Î¢$ëí9©#³1r@Ξ“ê<œÂá a¨€‡R8\/Ð:ƒv¹Z8G=Ù9ivï™°#–DZéä 6ªqùÜ Í¾Ag‡Åö@ýZ7Ýz˜–ß_³-?«Ñy¢˜TÕ¼¤Ày_áÔyE§Ò‚æ)Gp»ºT:+aŠÃ(Î%³¼"W?ne”«ç%Ù.//óͼZ‚Tô³Oª&"¥ÐØrêA–Õ*cfE:-?94r}‹ã7Ô=¥ñ9¾áRN‚¼”¶>r{Éù糿«úôP8½QXnÒy'ã¼rrQïyþ±Æîâi™×~0{´¸û4ÈÂ*ËÎ#æ#Þ"ð£ï\e U~™M¡Ç‰Å¢Ê½„•¯“€d0ÁPõ ÖËú‰ÃüM`žG_>saÙ7]¦„î&xFäÐIK”½Ä@hÔ³àýH‰8t6àªû³Ra=Ȥe³›úÔ™ :HCºC™ ]•q%¦ÑxAuÕ¡ûÐtyÃØ¸» ÚÐ:³˜ÇïœrXÓ>/‹`X1U|7̾çòIÉz‘M°)ðÔƒ°4·‘Á5?å:Ò¢±ÃkwLãÈðÏIÐ$×wIÊî~ù`ÇYFÅ”{lðõEnð%Ô^{2“ rƒÄ¯øG?Üç–[FȃÑ)¬"ŒC|eq7Ò>9èHN"êÿvâ5l_–çÏ—êÉš4•¬É 1¢E…%ÅôsÍ+È:0k«ö@—-¼“µ@šÿP$øC¡<óhHŸP°aÝ‚KˆNêÑ4\‡½ø2[‡U‘–.£ƒä.u?îeYú\(!ï*WþÉ‚ŒyÄ$Ô¿P³¬ùümk…‡’kކ€á4:ý½ßÝoÿãjžàÓ]ðéQ!£ñþ4_OÿÀ§;$àU‰©Ûá`mÿúö¶$öÿr@µ&ÔÃþÖƒïíæ¬‚ Ql“e·½…ÃnÏ”õþáÕÿSYÀdendstream endobj 249 0 obj << /Filter /FlateDecode /Length1 1389 /Length2 5917 /Length3 0 /Length 6875 >> stream xÚtTSíÒ.¢HiJ‘â†ÐkiÒ‹ô^¥…  ¡K¯R”& ½ R¤÷"½ˆ €€‘&]äåœóçÞµî]YkgÏÌ3óμó<›“MÏPPÁc‡PÅ q‚!° ¤­­.€Á¢B`°'§‡Büu“qš <°H Zê”<0Þ§ ÃáqÚ4 á‰ ¢D\ rK DÀ`É1R€2Ì ih 4KÆ©„qóõ@::áðÇüëàóIÉ[¿ÓW„CÚ0œÂ"† 1p$çû<2N8œ›”°°···Ì+„ñp”弑8'ÀExx!ì_:0WÄŸÉ„È8#'$ößã€ó†y ¼…„#ÐX|†'Úáà Õµ]7úXë@ø{7Dòïr³B¢'ÃàpŒ« í‹D;HÐUÕÂùàÚþ†Âbðù0/³Ã~wTô~À¿ãaáH7V‹DýQøWü-« í•0®®4Kö«?e¤Ž¿v_á?›uAc¼Ñþ $ÚÞá×öžnÂÆh¤»'B]ù/ï"ûÏ `‰[¢¢Â@øÀ„•7òuCüB~¹ñø»aÜüˆ¤ÿGæ…y!œ‡'"Àÿþi‘A €=ŽìŽH4Ùªã݇?6~ùHà.Ï=þõû÷›ž^ö4Ê÷?ðßûVQP065ãÿ3ñ¿cŠŠÀ_PD ‚ná_þYF†üÛø?¹êh €ÇÿnOÿjÙë/xþªƒøg1 ž¶€ç?,·CÁpüòÿÍõß)ÿ7Šÿªòÿbù7¤ê‰BýóüŽÿa˜+åû€g­'¯m ^èÿ†š"þ¨Vaôtýï¨:†W‚ÚÏfAˆ˜Xì‰UEú ìõ8¸ÓÎüñÿÒ ‰Fèa°È_|ü_1¼Àà.øOÌ?!¯6Üï5þ²x=ý³4cÿKx"Pqæáó%ïoA^¡öŸßÔ„…Ð>ÀÏ8`<È~­* ãÕë ûå&ûGi¸§‡þìߌÀŸû/û·Àœìý$.îü"¼ñ¨ZÉ[pù ÑVú‘™ˆà»Bk\§Ê¨ÍÂCÃ'Y3šeªï; ªÖÎÍ:ŠîGÙ§öü—jnÖúŠÞT]u¼i—8y~paü‘ÿ!3û$å+‚<ÓTEV©N=–XªR9{ÇNCNÊ{Ü/Ú§ys]+U½¥ѨÓÔR]š¥EÇ,iòuÑ÷Ú®Çhú;gÑ5!ìsœåý4 vM™¦c²‡ÞUTóÝ}=³Ô,­±!^¡ËÛ‘8jéfe1â*“Ùü«?rJ¼62hüíÔh•è µóØ Èz”ò“_o1Xþ›9gÝwzD¶Á@ù6?ãK‘&8íXÚ&‘–3Îåão/3§jÜôz*ªo”þð=Ñ|ßмe¸' tÏéYénP`¿‚a¬sz%ÜBPÈ41I›×AÃç “¾Vƒ¤Éødwî¦7EH;‡·õOŵÒv}mY½™K/'P 2yª»¬P+xå´Æ{ÆÆ- "#óÄõJ™ILœb™¯Žú^FÃzò3£—Ê÷¤OI”ÄL©•NLR`ç•qâý Ök’7±Woßɶgq÷·[”¿ù™Æ<8‡`䘤B’pt“ƒÏ=!ø¬½aÚC *–Õ™Šx²zÍý-„‹ÈLb¯…€šáû„Õ/Dß䥧½nn¶}®D(zë» Š½/xf-ñàØŽ¨l‚^¡Ç"¯Ù@lÏ6—Pv’,Û8ÝÏÏuóûœ›¡µ•©ú$Èjb)½±Ñõ.“ùƒ¼Õã‰Z«öäC`ï Æf×ÉÄvJ²©q°t6ø¾¬˜O¦Ã-ÇßKîðŠ%sƒZsšÕÑÚZ–¬2@ʈ$7.ýÜ’¤¨œ9E¼Í_Ux'!Jçb UÉʼn:ÅÀ´²äUåXu;’Ÿû—mÈÅÜ–žÅ ëì«kg9'Úüð2Á,söP;å•ôè#/¯3¡f2»Êž¡3´˜ÂÂ;Hû¨ß|Üzxm‘Höðõ©žTfí©|6¡+ˆ€ûˆþóÞ¬ÃPml;biÊÆ»‹d M½¡!•µ-êÍAõ‘å¤è*6*eeeýËUÎ{…Áß³G^>ž(ã<§ÈÔ¥b¯úêmâý¬ñøçK›™j•Ʀºo»á]”zÔ¤k >}œ{K½§,ÌÏÑϑڜ ˆð;^ð½ }^y¶(&¢þ´.¬öÀuy}ÎÔOˆ)ßq™Í9^áÒ¼{cC^$ÓÔ—Üúçº|Uﺷ½§ìjK#D9G­,—<ÊZaNàu}\Œ½(‹*©f*MyQæøe$ÈÍh¥YžD[ØÿnƒÝ7MˆŽiöÙ[¦ë)m°r K/LJ]é…Ž8³ˆŠõ:Es}¨húå€ý[MX ¡ÿž ¬ãuì)kUôm‰©§”\ó­ÐZ€{W5) bqÓ¼#óâÈ { íý@„Å¿U¯KnrÖå¸ï,þ%•¦g‡1'áÌõÒ ¨¼Í",o‹hÜßøacBf`÷«9BµüÈrH«Ó}¨q‹*xít4\v]Û€þÊ…)Êa¯½{ö!L@f*ô¦AjÊh›b‰yÐ{›¼©¹õ¯Ç Òù&O{M¯ŸðY™=•;¥;$a'дxIà,¯/Á†øØ€[4kx²úJf–îêôñ›—*ÿƒ^¬ aNž«»{„G‡:ëܸ;NX–©s-ö²#Üb‹n\5Ê¡’Eùªt]+Ñü¸UÑùбâ$¢:³$À¶j;ôsVµ}Æ GF‚ÑNAn™vGU3?)×¥ÃÃÓfPÂÝ'ŒRõd·-KU–öÇÊíº‰‰(‰7Þ—-x3ÎÕ>ðÝË;ã~ÌæïPÂã}Ã8@»+\ü ­âÍÇ`™üÍÎÕ\ù˜~íjE° 7ý3Ÿ;l8…åê'ÛcáÐK½>»'GՇΤ“¥¹¨-O’xHµ/ûͺòD_8~£Q0±6v^²[E„‰‹„²ðWIɽڣ¨êå:_ÜVyk¶+|·ñ¬À«5Ó¯^^s§)δÞpDü}–«š(=.ÕÔÏ©²dhžÍ· ÊbbP \ã< þð霊y^•êüT­b„Jç‡Èú 㘇’¡ê‰ãŠ_‚Y â» Ï§Ï>‚,>B¹Ø¹#fª¨#ZŸÝýò%ðjÈBMÃ⋼›†ca“››ãL¾|ù]Z€L«aïpó=^ÛàN”Ú‚ÙôqïÒ‹ƒÝÚ¡€VaÿV…‰“(†Ê:Rú‘jv:}/•Ñ1“·Ìó]æ9òý›m„_˜ù9%ÇÎŒ©Á»Œ]Ÿ>žkÃIÛ;ÂßB¬Ïª®LQÛ—3›3Üã{tV.óã»9u •n¡Œ‚ Ç¥‰Ü½sq­Tº–t¥ÇMŠêJ—–BƒªïyÇI,Ôg޵äîÈ?—RÌ (½T'ž*ÒW`®[Úù“)”±~‡Âj塉N·Â—úø€ˆdïtš<~fN¾´…¸_1‡‘}ê«ÒC›Ð,zÇÜ9O¥°nÓ‡fNw:cži m.rÁ=™±=w•2Ô êcjû¸'ͦí߉Wr§ZïÊÆ&$Ì·xšLù€v³d}]cßLfrÍ_Þ÷ys9g+6™(1‹õ;‰on¤Ëq]Óù¸‹ÏÑ[¢6±Ó÷'^Zƒó,B ‡8çRgÊo§9_öš™š+g寳Eï¿’á 9FL:µ‹Çß/xéTŸ[7¥Xw*O|1*wEDw½×à:Ûƒæ5¾êÙ*Ög鯒qí}Ö_ˆ§¯îl²K³ù˜úÈ.àÔjNÉšÎéQU攉÷ÎÜ${SÕ”Œ O`Ùš ™ÝÙuÍ"6{Ú=€¾¨öÊ ÊñÖ±÷”\®—4Iî¾Ì<ÆWïíL1NÛïxÔ?“˜‡ÉÒZnå4$´Ðî?k¤(вk_ \ièúÒBD m¾Í‹»–½ÚȦÇÖ4„Ї€ýU[qëÜfë…ÙI _4 ;T´/NIŒ.,ãö'û£y~äè‹Þt±(%'Mþ˜¹ž'ö"gi#I7ÄÊå[íC)Œ÷¥‰òE/Êû¸ÈÞóiYšÎ ?2Ö—:Å«;)£ÑÆHmöÝdÂ$î’TD$ÊʹM eàBsBé➘]h¹vF…⟠Óej<‘SM6o!„™~»ãöd=ï…%*{’ô–,ü)ß©2B¥ˆõ©ÃêÜ j^WÅi-‰Â£†¯¶Kl°¿íx2Ìê Ù‚­‚Ïœ> ê”z&ø ³¶ò¡ó_û»¡Ä¹˜µv¦TošAëX—¬F)ÚOj§2†† ;Þy^âÝdýÝÄ/ÞÔ(’ò¸­Æx5òÄh0tCP¿Ùf3ôsÜ®J¼•ˆ¡“õÌtŠ"»É.B³ýzÖ’KùÉ÷°ï ¨ˆ—4d§pÇ [+ó¶5Óg‡¬'´Øu%B÷ËÛˆÑ_àÏúÏKóÑ{*Ðx ±ñQî–âúŠíwÅ‘»„Žãð'éú«¥µkw…¥„ØŸ…7Ôù1ǸX4}>?ÍÉI@k£ê¦Q¢w»ìâëT9eÔlÈü÷L£}5ÿ§»5%geaRÒ{ýrºoü +שt‡y±wº®è»Ñ-_þi}ØQ~§UÃFP”gÏÐêÇ,“,z³íÁ4üVØvÓΫdJ†wïï¼/G3*oîÆžŠÜšæyÆîg$yÏù¹VÝ7:«ƒ™çC yjZŸ ÅJ »Z<Ú¶9‹R¨ô›Ý¥H˜±ß’–öÁKþ±[Z÷®48™.3:ô•³y1ÒÃGhºI²˜Î(¤ü¼ôkñŒ¿Bã¡_:ªgRžL9jÐÖŸp¾ÚuÞÅà,ô õ$ë@>+%)@ûg7¿kŽêMÉ å‰¼þ§Û•K¤ñ(¢üf:¶§3Ëæ†5g‘h‹EK¡q+‹© ˆ7‡x­ºO&õÅ»›ÁRýʽÓ#áOo7®sŸëÓm~„“LòÙ¸‰|­WÏ ª9ï9ß /d÷MB¼ $AGLK(…ú÷Žžœ$dEÉÄ[^-Ö[íìUß½vÁÄò¡qQ``¹Y ýùŽ[ëh|GaËaEA¬¤’'g[ Np{Oþ*»Û‰ÃÂÁbÑkjlr‹zãèô¶(eG˜ºì}ߘE>vB‰Ìþú>èõ±ÏXÎÚß› …I×?â$u¹Bå[å·¬ÛñŽòݯçàχc‹ AÕa½yÍ¢û½Zš€|(‡qÛeµ×lsÙÚ[ãW®^-¡Ÿ/Ù÷ä~óεìô²#¡y-³Ðšgoö /‹¸â¯E\:§³}áj5G¾„òk³rʧ;&O91Uî…ßRÅè±}é§ž,Ë{5uÇr¸±WІJ`NFS8kEä`ŸœÇ'¥œ’gCiëÅ4û ¸”¿xgY$N!d4Œ1Ÿ§š§tòŸÊŽâlÞõI² óJâ“IF+¹ËwÆq­}V:åF›†ÝØ5‘µ¤?Ã@LÙÑÍ1Œß¬|~„z8Ôóâ ¨ °ZïV Oç”°OâmLåƒ@«/ón!uS›šûÌJÞÏ'ã¸ü‰ƒí£ù æh“V÷K¯BrçÙÌÂîb6/xÿ°ù°—ËÏ/ÐZPæjˆåF­zª<¼ÂOP)ð’œ:(ù¬8UÙô§ê öÈ(¥óAyäìÊÝñ4Rù‹›!É7|p^‰ÙeB1´Æ5äÖ>þ®k5¶‘bNn‚VC,>, îœéŸþ4x‘[14Sw©‹â~p4e%ð„3„5ܰ¾ ^hPËÏ_š[‘þpûð[òzµÄÖw£¹Ž{ÏŠJÁ§¦ÏÛbrÝ™Iíe¶®zWä­˜bè2fåàé§æçm2£.òÅœXuK[[õ ’窂)w6?Ó2ÛÙ>[Ø@œH€išŠv8?迎·vËêêð ÅZ%׊e ×0Ñ¿OðlV"^«Ùã½wÍÐ"Ø}ÛÍv¤’±`;$¥\9Ÿ<ú,&hà=ËN‘:£™^o»>ú4ä·Ý#À ¦5¨EBâMüc4/CÓzRgøÁy™ÝN ï|sª~:&¥úâûgã '·BW>ŸSõGó )¨•еA<]¬Slfݶþ¦.³GÅgRq›§_"ÿÄÄ¿ì{kM-7Ì©¬Œ-R«ø˜.-š}}á'ô¢5ŸsOÖcã1šµS8ªÚ›°ÆÖ°.ó¡c™<ì7v”ùŽW£©ÊJ{ãŒ5oÊ·ÐK£ c{YÛ¥¼'i5,ôk^yªŠo´®ª¥Ix‰”7ƒ`P3²/CÝb3áÙß%ìuzåE3-%MqÙ U“FZ‡ÔAÛœR›Kt£™ ÓÃãf%÷©­ü¹lŽW 7ìnøqE–ƒÄ¬n\ë½å©FÉ<½ry¬E™KЊ¶úBî˜ôó$ÝÎtñݦGCßÓÖ1‘ÒÓ°Ôœ4B° b ­‚wývÝlìÓj »—D–?¹ÀÞê=ÀðúÁ"eƒf¾„§»¨mM*§C›w ãYBy+õ&W›ÑºGÏH·:¾1W–iV‡b¾ÆX_ê}èZ?ÉŠ‰mŠ•qÛ"Ñ0•]9@ÀÙ™67—íB€¹æi¹4;ÌD´Žœ½R®"ÜSójy¿R̽­ßŒëx;­«úC$N­g¬pÝìýzæ«ÓèYaEëãVž‹ q)òWÑ ˜QJú­;­çV “Á$ŸkZ'=&—ì XâwfÙŸ‡ol¹¿=âOÇþ#G–Ò¼ Œë9V~H®WµKê÷Pé=P‘{ºøðAœo©’JÿÏOùÓÃ>å£UØÃL¶’ÝÕ<Ã,)ã鲋3ŽX«Ãw,¶Ò™4—Ç+èLn¿šKpryñäQ‚±ÆÑ™6 _ŠÄ€õ{¿ 8âq<Í‹‘Þ2ƒ”+Íliâ—:½ëvò"wn2eŽ‹¦R¿åægÇö6¹®…±¨ÛÞÃ9‡}N¶é“Dx!›T?‰Vô¹è¯ƒ¨f¸EëÆÕí]ô2—ϽÃx>n—t:­v÷p‹c$ÃR Ú—ŸzíÝÉÌéA4™C¡p¥8µîÁorÒÈý0£Ï’é÷âO­t'‰ºm“+ÖÞ×@¨ø££2L¯‡qÛëd|~ßÎW‚úÔ )«TìQf°¶Z(hô#ÙåoÕ«†¤EæÓè?6¦q'‹c-Û¿¦–ñH‘µñœbö‘‰wÞ7Ãý’îcÔ)Wœ½–ZÃxÐÕЈ}«Þ¹:vu8¶‘‘qo‚ÙÙÌ„²õ¤Ž]I&Â4xÊÚL×òZ²F ½ÎÈ£-t^©\Vºð½êÜœ<Þ€ñÒ¯mü`[´ñ[Çâ<|ÒÉqåÛ™HÄ Á9z! Ï-¢8ÔʯCÕFŸv2‡ÕÛ-ð`ø°§ÞÃé˰q,‰à)Z°¼º¨²cÑPìùû¶ºqÿúw“ñEæÛwèÛu¿9…©<ý„ŒËY³¤fä£Qô¹O¨49üôt€'pt»«õÆPÅþ£ö.3Ë’žIßyýwuе¯e6gn\жû†“Ö@Æ»¥ñzï)fÍ+žSŒ1ù>Rd=üü$Ÿ7›¦+òL@±äÖ7JµðçºÊÝ”*Àò;—¦wý–5º=%»æŒqòGNèô)¾’•Úy}¹Œ”°—z* ÊÁ†{–U±'O×¹éÜ¥œ¢êð*¥†“½ˆ=m'}ýG9£>ÚCi•½¦­Öâr§N*G‹Ë4Êø^-æƒfÙ÷F>0ELí Mm ´}Sn0À4JËnìqL¢¢^ ­BºÒ¶ÉÍ/ˆ\¿·ß&LrØ5]uÐÑ&¬áºœ¹üPêófòŒ¸ÌÎO¯æë’ƒn„Tól}{KÈ-këÑ&lÆÊ’AõÒ„gó"Sv1B-¼Í ˆ b§…dÁ]Û¶x’[(î.þ!ENEÍŸþÑûö¶mà*WÊ­ûÇÂ×+³_d|%SyäÃgžIC|¸UÊ1½ÜÖ9Wܲ?–_œ»™½÷-¨,r ’ =ïaȲ”½^ÇŠ}pÏVåÓE Y}ô.€¬½£ÜîB¹‹=—åï¥cíPž>“˜=~ HA-Äm† Èoå[ µ˜å~œëY—Z’¦‰Î¨$ÿ"õK“¶—»½ºæa¦H™™ß¥ç™w¶ût»ki&„#>ýŠŠ<&C$Ñ¿«|£[p¥Â(0:€Ë2&r~&*†Ý¬ '‡ÌC>8¹êWÌíˆ5w–Ævøh=i¦ÖŠUÒOíÑ>Ë q 猪}6Qš”fÆh”)Ê#Z‰)ŸŠŒ÷çÊl ±ñF—#Ätè&Z]j5 bÝ~“u´òÚ–ÐI-X³1’®¸_K:ä†CË}=Ú“¡…êÔó¬ðôŸËeõ´‚0ŠdT«Òëóz‹›ÕÅÿF|Pµendstream endobj 250 0 obj << /Filter /FlateDecode /Length1 1373 /Length2 6096 /Length3 0 /Length 7038 >> stream xÚwTlß7Ò #FÇèî’nPBcÀ6F7‚„4‚ !ˆtJ‰„J7H§Ò! !ñNïûyž÷~¾ïœï;;g»þ×ïw3 ›‘© Š#ª‰€£E„@²5}I$&‰’f0”ô/- Њô‚!à²ÿË®†„‚Q:…qÓGÀ:Þn1€ˆ¤¬ˆ”,dþåˆ@ÊÔÁ>0G€¾@‡z‘Õ~H˜³ Så_G„ "##%ð' âE `8@Œrºc*BÀnSEùý#¼ å!+,ìëë+v÷B y¾0” ÀêEú@¿Ç€Ý¡"Ì\`^©MN(_0 À(Ü`(Ü à w„"˜ÚSm=€¡þ—³Þ_€¿Wùwº¿£'‚Áÿƒ!„»îƒ;œ`nP€¡¦ž €áŽ¿Án^L<Ø s;`þ4hªÀ˜ùþžÎ ‚„y ¼„¼`n¿'þ³d ¸£ÂÝ Gy‘üîO†„B0[÷þs­®p„/<௳ îèô{Goas8ÌÓª­þ·FEò3@RÒ2¨'І¸ÿNnæçýcù­Æôàð8aF€Áœ ˜’/°€BzCƒþ·áŸ‰ˆÀA Î08ɲcÔP§¿dÌÍ#ah€5<è÷çß'[ ¶p7¿ÿ¸ÿ¹\áûf:Væüþ·IUŠ‚‚¢ €ˆˆŒ@ súg#0ìï.@ÿ‰Õ†;!25‹ÙÒ¿öùûöyþ&/àŸ¹ ÄB<ÿ¸ HÁ|‰üÃüOÈÿ Ý¿³ü?þßýhz»¹ý±òü6ÿV°;ÌÍïo;¯Þ( öõÀÿÛÕú]õ¡Ž0o÷ÿ¶j£À¨ÀÝþ½D˜—& u4‚¡ .Aå/½ùo‚¹ÁàP#„ì÷ƒþˆaÄóhxaðøÇÅæŸ%5à„ãov‰JHÀH$ØsÅI ‚¡¡#ýÁa!8… `Æ 8!$¿ïS\ Œy–~+ÿȘ:Â(_Äù… ÞH$†f€€éâ_òNC¡h(„dn‘‹|TÙvV£rÛWpmDa¸fùŒW0`ùÎû‚œ0·:'|ùS%½ÿ=åâW žåyÖ«€í–ÂÇ­©Æo^Ú%›Œ¯½%™£ï-ÚV©ï¾K|GÐLy=ðÊ3Ð"Ì·»C˜ïé-MnTHsæûQ ]ß]¶0=½f¼^-©KzY6!˜`oVò Xà;ÅÈN€¼KÄG}€¦øtòs’:oô†U'™Ÿ$h'A¬8ÀjU4ñ|Ê©ÂLÔ«“‰“ÉŠñ.î õÐ8W€êF†ÃLÀëâäPæý»áÏîi"n<þk&gÈ͹€£²+64M§,ülÊg¨ôA¦-teîójæq uÞY<ëøÁëÇø¿J Î|~ÎŒÒXz^PÓÍi¤ž÷j<@EŠƒÉ{×H6Ì’z˜*ÖªÑr6Y¶¿wW†·ÓêÍ”£Ÿ­Š%I™O¥Ç˜= OC« šSм³ÙãAQ|¥Ò`ñjÉîo0”Ü(9Ì7£!7Ýq3¦ÖÃTX ~(rê'Q²ÔÁíÒâçDRëEE9/$6Z#QÕ QiqJ :ƒöuÍÜ®q=.g”çm™nœ¾ÌáXN|\2~ªe±¶Z/¢ ÌS°Åß´J²§*ÜKæ[Ç –"Ý`A‘Oôt>²>{ê{Ô\€SòäÊ<àA.\hÀ­Ýa”_Yòà•±-³ý›äR¼}¶1‚Tú“®Ï÷}7eÖëMä¢Q•Ù³Œ9©ü¶ÎÉ5[4VŸhû£®É®^¾e©Ææa¼9MÒqU}à'_T‚{}Ñ= ï…·ÙÁ悱²ₘöYoCâLQÙZ¹O¤*nMè¶1Jň¶;åVª½˜…´èÜE¼•Â#¦Äc¹2l·¿Ï?«v¾Ñ ]ôpߢ!l6§®¦piΟ¬Ëëbâô-¶©Öq$”æï4Í×P(é¼{o´HN.(MTOçi X‹GÄPå]ØxJ´!Ÿð†wèq“¤ôDºŽ#~DÞçá"Hnïm„à=¡K’ø©Õ0BNS·¨ ÉD-ë»î… ŽÓÉ£¶“½ÌEÿ·Mãc,‹€œíK—¯ñ^ü«|©Læ‚9Õ¬+6¯xît)¨[;ò*_.ñP¡'¼¯çRbõç2UÎ% 8_3ŠgºVR¸”¯¤¼SòŽ×ª²¿H7Ó§””>*ÙùgÈ·ˆêýÉ ÿ^5™Z踓݋í|ÚôµÇlQ_¦ŸtzðO`ö‹ÇQcô´v»îŸÔ¥{›c›5ýõ.q¾–Þv]_§$ß[Ó7¦(4’$ZôÚÞyPÞ,ªl#©líÞâ}"¬k’ÖUØ[Æ/Ã-ˆuÀ¶‹¼i™nDdH´>‰™ípïG¯+fÜšzÖ`˜{AEWÓÉrŸÍúkøÜl>^¢ýy¿žÓÀ Ï&IÄâìqôÁ¼TÞt»>·V48Í˳ÚmâÞXÊmÇ¿`žÐUÞ’|Ë9]\²—TiäªÔ=ì÷Öï&F<ª•FÿçÒòÁ`Ч‚š'à€!£YÙq®«¿)ø¨_EÄX:\E0p%ÖAÄÞ¿²ö !)cáÕ¥• e¡P/r¿ôV~ð·^¯Ž,ö7[ ¶&~YYY\È>u¥‹^¶éïV…¿¤þºÂ—LškvîCÃŒëÌþ‰DùÓ9)'ƒjägVߦü°´ÿYwþéq¿H÷ARŽÀô’K釮=Oç¶Õœ4rÂ$.4mŸŒÅùeÀ]ï 91Œ óts]ï4ª)V•y£vƒ—!9_Þ"~ dü|* “GˆM5jH¤»3¹«ÇølÏçí=xZʼnĨãø;’ i8ìüê=ÍGH=y[B~Éu÷:od¾¯-t$íÑ…ˆž>’gv-™ùþÛV‡sOzm§óvJ/1Ã1írŽ´ö ÝQˆÍqÎŽ!ëenIôdRPYÆÖ)ÝÒ/™Ü;ê<›ƒœI™ý‚g^Ц¨\ß]“ÇÒRKlu#5ˆd¯”FTÚ­`ÕBƒ"#Ö³®ƒ{÷û† 9Të#t,ÉÒçÑEé°/yi-i;Ç—ÎÅ dZiiÉ’iR×”"™ò&ìÓ ÜNðJAÑ3(oSïúKËžÀ01ùÓ/ÒÏÕ®|«bCFCE£@7{‹3ÀZ«ªlR…»Ì×Ú}Q½®j—»ûÒ5áÊŠÆA,QšÖx[4G¥þGÜù\¦ï°øÌ8Yêg3X^b%†ƒíMƵ¦^8îú¤Ù±ÎÚ°,Xæ–žª®¶žÔÚѼ“h,é†[g®pý0ߺj¼«<ø’lð¶â=Ò<ð¡ÖδµÐ~½Rmcº·Ç®XE°îC’çELâùÀ#‡`ÔÈöF"ð7i8‹Š lª‚èŽt-gò·£ÅO—AjàG_^m{õK«ôl¼ÍÍüNþuxëÍMÁqÁÉm½†µï·ê‡«?àÀH÷—ö4-j€=hÜÛøv·*søìÇô ?˜ï‘ô¦évTj ôßõ )s×yù(Á´T2ºÿÊQŇFžéÑjU{x¾ %Þ‹]Ù :Õ[×îe«Ïv ìH y%EUahÿîEwIÞEUß9´¶àZïÛDõyha‚Â*l(6†Æ¶á»ÈÝ­™s´œî¦MDbóØð mÓ® ð=‡=3³ÿºù˜°oC“·Ú <ã/¸°/—^ú¬,÷ÁѪ ä¹çöòmtÞ‘%7ãê³ vò*'®O§ç‡&U^¹œ`äGkç[2¶YÒð¤¢Å£K2ge|çš\§P?ãÊ=IŸãŠÄ„$jóÁ󆶜òqαüÊÐýèc¼Û=¯$[²Yײ’úžj=¥ÕÎl²ÿèäêy¤ŒjÆ·âÊåN~¯ðH¬8ò“žv‰óóDÐÐʾž«R•wÕØßòƒ¨.K~ð~§—…1õ@\¬dÝ:6«'ÂoÉkfK}Âæ—>ªî°)Øî²ªÏyаq½_DÅnËÿP…ÇOý²g˜YÒ·Xµ¦Öåaøœ´–šBs +Ó­n;œ'ÏÂðžŸøh=’u·o ï±µUðtxZÉ·¨ö,¥³#‡&I™¤0ÕSÍ׌Z‰Rà=†. ‚Ó‹)¿¶QwÈÞãÆüÔñ(ŠÒ[r¼«}ßFêsV‚‰oÈ´éÝ}žý¸0Üjg-@B!Ë“TÛn]Þ/Õ‡5)ïÛœäZד,ž$Ä¢Ò'Vé6ÌõáÖªvt}¢v¸ äÊpïgJztê–æ´C×ñŸÐÍXL ÞAéîé’w'Ñ*dwÑñ­~ñi‰ŸnÇò0Œ>™jBLî[ó=ðËl­Áz+A`ü«ÛFR¥ý~Óí±>,®%fóC3f&üÀn)¬½K"ÖºE¶ØÚyF§³M €³Öò*V®Qgœ¨’)&°ÑXóõú*³pÇ€ Õ#«È¨a8ð@Gg_ÿ¦(Å*1µlóFõž V°_Û“ÇÔГ‰ ì¯ù‘1«ÓÕŽ»dTþÂ[E+bE«è’‹ø:yîê`=ïæä®.ªTùfvÖØt{° ÍÞØ}ìðLùTëzJûéÝg2U2fòï>å <×ÝÂ}Õ—'Co­ðÌèB1‚9B‚ÜÄÂųWFÿs´Xæ“KUw˜Ÿ'w°)v…Æ zkjÇsȃZæïQ•ŠBMÑ;êØáÒ,/Ëo#v²6>,¼íÜlÚÈ ""èð… XäÓVù?ÇɈϑ›æ7‰AEY ß?üª0Lj3áýªU5°{÷ÈœGͧ×WéÞ ñ#ÔM0–z^#µ{1ÑzñDÃ(źMU>)œPY ÚÎ[5οÚДE‘G>>PÛŽOj:-%O’Ô¾ç\ƒÐ˜æ~\8 ¯sX¿ýÑÆ­rH/Å‚³}é L^¦äºe‘}½¬NìO.ÉÁ¿°É(ƒ įØ{? «§§æqö“p3;|Üü+ ½—ÔêÝ«q,Y|(÷ã‰Gœ¥³ ^’CqžÇé/&?›g“I¢Uè~ïHg…n›k-†W 2æ¢K%ëŸ#èë[Ôj®^±%MÝ#ýÒ…ðHDrŸÏãišn÷ó“™¿ë\äŒÉÐK5r”Õ} èÑ;9ÉY4«íTjPõ§û1c2>Ü’_hL[ç_^:cKMãWf¶}pjg½Ýš­ã7síD0ÈT=[¥Xé·´9ñI¢Äñ U‘ K[ïyïüËÉVé‘$ïMúy™ß›ÁS‰Â8gIYÑܸì˜=Í„6*àwï) û½ª]¬IÕ tˆï)ÏRut6WùÃì£áðÜpÚ8ƒW'£µ /ŠFUúTÉ\ù¹pÞ+÷sŽ?‹özÝm'×J˜UÑDûÄó„Ç®ôª9Wv·MhN–w/œžÅzœ˜Y ÏáÕ-dpðŠ °ó“Ñœ{OÐûNáïêU)vóò¼‘f63Vèí{dHDBtá~ÞøÇA°ð¹Ïá»0u1WóôcëΉ~fíòºé,ŒŒƒ¸D†¤»âÀ•Çœø4÷¸/»kÕ¨„©®ã’ñnÅ_vM ú(´ìmF簪ŔåäøÙK> 7âk^?~Š›Š\î”&Ò Ä!i"ë­†¦‡ªlŽ*„D’Û•¶–@çNÈšYþœå¼ÆRG¼EýÑ®–‡BöÈ»¬ ¦”Óóù¬Þü¼».ÇáⲨ+õCT®Zm©±0üW­(™¯õÓêÄdöIÖë?õr>Ža‡÷±V‘1|R4ÕÊ3Ýor/âÇÒü}BÓe$µyµÙ‰9Ù’?N ¿>#Ý~‚Há1*ô3Ùêj Š07}iON!ÏzNËÀô$WëÕX´?ùœ;†A­ØŸ÷¸ÈÂÙä‘úv©5‡njãsÏ¿S„2÷ãÓÍPp¼êMJ¬'OSôà×_>ÙúÞéák÷µ:q§t3 ½NOßo«8|œÔì\Ün%óT64*xÆ“âÿä«‚«g¸ºâ@¨S„â[Îì2·¬ïô²­8ëÀ¶$ƒ7ò]oN¥1÷­ôX«.6…=ß›þëó/$ý9Á Å£jcb‘Öí!é+ìÅGÚçf†³Æd$Æ7t¬/ÒüyŠ5èø:)vTp¯<^‰ˆ!cq! ‰´Í\²Ø8ñAŠ™ÝM4› X¹y'FgؾpµŸkט(¿=9©¾ÃO\rƒ½ìB·Ì['ÆB3N#ÿy &´uà{Y¶fr„³HT'¬éê•Byå^ù$‹.¢"ו3·º¤ƒO.Ö`l8Àa©IÊE@Ë\zÊ1ñ«~ƒŠW<<¨Ði¥ÔÏÐÏqÄ9<ɧ>}ÎÚXï­§Ä{œǹgû'¿ÙÑå©cÔ€£æL×|Ï}3uÚsÃn•B§Ò\"ÔÞ‡î_ €ŒQI0,Îø épö@vç†Ïµ«H„kËgÕi•ñ±Î¬p­û»¬¿¤hÊVoÓ‰Y¢Jú9abVïµ:üBÙrc£Ùª=]IívÉþ•o-ÏbÖ­ DÎ'˜ñް‡á«l½›ý,bɧµˆ"µØµa±Í{™ž‹Ý^¬ô6WÿÎ*8†ò„€åÌ{mÈÐ;ªJ&–i>ÿÛææeùë éñ-½`î„G ? ÷®{ðž+y˜^…PZp¤vyË*¾s²%g·SÍEÀÓØ| Ú3IGý„Õ$^Ž"”汞JýQ~©Äe!7Å2º}{¶ª²€D5>J²uàç.âÁ‡CÏ+%Ò¬<MHEÕ†‡_dq ºuðh;ž߀ޤTFŸ¬” “§J‚4ÄóûýU*7–É-Ÿ"‡¾í§ïÍyXµžz(ôä!B>u|çà.;©÷Ö§ÚH4«]ýñ!½Ï:ÜùH;àƒ£žŠAJOqîèN´°¦™J³­ƒwî´OWXy‘çRj’µ˜ü¨¸¾ªY¸iiðκµriJ#n³P„³Q­Šèiúš­YAúô5VîÕÂbÊ w7¡cÝf™Ä£ÌwµSY~Þ8UQSèÅ!×6ïÛ÷s8[´xœˆ:áð&*î,p>G5µK:­ýù"{öÝ '¹2­üx+åÚ’ÔŽ1%ü_Vó§÷¼¹Üç²åêõtðhE¾1²ô™ìœÅËmy²ÓZö÷YDböýÂ÷ÙAõo–g‘ogÓ‰ܾ3,Ÿæ¥¶`U._C÷@襼…ÑÖ£x™ùÞ VÆîQrwìû‚7?´…ÞφæÄÒ¤ÄôTo HWÀ"I¸]¶ú¦:Xh@wÉŒ#ѱ83»”Ò×E®*Ò4Å<;;ËA ªx3Qîòö=ÚaŠÃ—Í@ Ô~Q8 5¨ô4~l–Fk+šµm{lv»(‚¡³ƒV?mxnÎnç‡Nl:ì¹"­ý´þVËÚtÒÛéÙ½ /¾šTŠnÆãkΖM™þï²å³£×úq£)mF[6Ä’)C¡Fªw¬?YI—ÉXȪõl]èŒ(72º)ï-˜ÔO…ÉÕRï¹Tµ,æ„^|¸Å [nZ5§Dñlqq|¹½œ”M<©K–x²r¿[`L —ä4oR(¸ zÍz2óë»0ÃÿÖÓŽ±endstream endobj 251 0 obj << /Filter /FlateDecode /Length1 1373 /Length2 6093 /Length3 0 /Length 7034 >> stream xÚtTÔíÖ/]Ò%È€Ò9H#ÒÝ)Ò 00ÌÀÌÐ-Ý-J#¼tJK·€¤€ €(Ýߨï9ç{ϽkÝ»f­ÿ<»÷~öï÷°±èðÉÙÁmÀÊpŠÈ/( PÐÒ >â"bc3„  à?Z"6c0 Ã$ÿ—]¡Ð:E í¦‡ÔÝ¡à#PT(&)(”ø—#! Py@ìZüu8 Œ$bS€»z# Ž(t•œ¶\ „„ïïp€œ ±ÁZ ”#Ø]ÑÀm!`”÷?Rp>vD¡\%<==ùA.H~8Âá /À‚r胑`„Øðk\€6Èü{0~"6€¡#ùGm·Gy‚`Z…Ø‚aHt€;ÌŒ k Ô4:®`ØgÍ?¼€¿¯äþ;ÝßÑ¿A`¿ƒA¶¶pWÌsØC `€Ž²&?Ê Å Áì~9‚ H8:ä‚@A6h‡ßƒÊrzz¾¿§CÚ" ®($?ý5¡À¯4èKV‚Ù)À]\À0’èWŠØ}ëÞ¿×ê ƒ{Â|ÿœí!0;û_#ع» Á nî`5Å¿=Ð*¢ÿèÀ(€ˆ   ˜v€½l~%7ôvÿ6þV£û÷÷u…»ìÑ#€ý!ö`ô‘/ä î`ßÿmø§Dì ¶(€ Ø#úOv´lÿGFoñ˜ ¢þúýûdÆ–õþûïå èšè¨*éóüøß&yy¸À—ï‘(€OHDˆ¡þÿÌ¢ ‚üÝ…àbÕ`öp€ÄŸfÑ·ô¯†=þÞ>çßÄàü3—6X0€ó?7´E€ÿß0ÿòC÷¯,ÿ€ÿw?ÊîPèo+ç/óÿa¹@ ÞÛÑxuG¡±¯G3öß®OÁ誶ƒ¸»ü·U Bs@æý÷%BÊ/°.eëø*ôF¿…ÀÀºp$ä׃à þ— Í*[gô£Dãñ· Œ&Í?K*Áláv¿Ø%$" ! o"ôŠÑ’Àˆ¦¡Øë7‚ü08 @ç°‡#ˆ~íSX €~–~)Ëè:(Oøoù…lÝ4Í~ÝÅ¿äßœƒ½À¶Dó³p[©P§šÐÖ³j9O¾ÍQé)¶Í§\|¾óˆ6÷ Rü4®ªœç+ˆ¹´Á÷äŸ>+qË.0_û~kªÃhNÑk¹ô»²JÒŸØl!ú8NÛ7öú›\m/!#Ÿ¡ì–ßµ›Ÿq°3vf‡:[¾›»8©nÕ™gŠWmoÙâpøì¦ÞV•¨Æ«²I¾8£Xóàâi¶W6¹3t¬x(>&nÊ/²éã“)Ê—c·ÌêICÛ6²æ’ „nsúljëŸ!v~Z²³IrÒÓ `S«ÅÄ®4«&»³$ã ç|R_ñRû)ÖdƒäÕI†Üê@ÅjH­z&j3Ú¢R[iïuÓƒrÓë+ýQ”^u¼jêÑzžaäí~(·ÀûIt)ýi/ ¬ž9“æK®ê:*¥J(9Ì镤+ ;x™z«™Éð³$ÎàLi³ÌÐR8˜Î€ç§ÛíšF«m«CÓø¶Rn¤øøø|µqßçnV.CǤ¢1K 2/¬tœúŸ½Óx;‘\<ª+1RŸ]0Þsß•ùòD5§5b˜M;®EJœÃæp@*δ;­3Ŧßn•IJû°²ñ ù(rD>IEæ7ô,¯…(sA%ýïßV=Ú0!JÂ%aÒò8Ã.aSÑ>hŸë½Ë;YÔ&`=uÊš½‹­ŽKž¨#ôH|!‚ˆå³PSyn»Ñf/¶1T4üShnä^ÒB¡¿!€ôæKIi·ì!!» 5íJ-¥¸#Q(ͼ¯¨N„qE3¨Æ“#GZ§éH“ÎÖáLwýÝW$‰wÊCÙ>4läÏËÎ(BÁ~ב:éS6û!Uôí/¿~5&,Ö YO¶ljì ŸŽhyÌ¥UÙþù1–Ë N\‰Ôð—IŒÉd•þ:v@ SƒQê/÷]tCìG„«§›¹˜2üµ¢²u‹·„Æk @‡¸áuåãÑ,ÒïË®$éÆ þ?c}ë‹›QÐ0Š@Ôuž•=™Á¦4‰¦4mg z¸{² Iþ.†¹ÐD‡¿mš‡ÅXº6¶WDöšÏ(L±kÂEëÑhÝni(Áî9}d{aÓz •1ùþ,¢ôŨ™¼eæÕ(ùËÇ»­ëõ3ü–ÏØße,†3&—$O^“œu·´'5oU‰;µûЫM-î(¤³Á[¦®Êã³t`â ?õ¼Rl}1Ä7N.”Ä©Î2tè7?ÑE ’“R¼=³—ózÕYb¡f6„úì]pâºD`@‚‡—Ïæ‘g“ÄÓÄ31,ÿܹ¯‹Rнo>3k…MŒonF¦Jïy_º^t¢æ.ã£~X]¥ —|‰N"K’#¾Ð²àMëd Cæb.ך¯Êº"&zФ–˜“ ¹B#ó#ŸÁ€î¯]íÌö‡ö Î]¸,PýÝ ŸA1±V^a”­ÛV÷ÞÃ36û~‰—¢jzwªQu‰0÷<~ÕšèζoU“¥Lby§[ºp#i›:m:w \!ܾ-ƒon±¡£VÿIëz´6Ö(Jöh¨¿çqS„¢îŠnuß§pk#Eq",ƒ“êì_õU’Ž@i CF)(¬ýØ–Xšâ°ka›ÉæD5l¼ÚÍPÓBÏ<¨ˆZn8ûl¢o²Gk$åX+>- ^ÎüÒK³¹=&j2À}ð¾EH‹ÕÄÄÂLj‰qþÁ2Ù©†ûY 1ýð3̾<µ‡ fŸžñª†GS¾iïU[x"”5OÌõ-ÿª¹ôíÝŽ7u½>1^±¢E.)a´ø&'ÊÆÑ©' J:^êáDNÊ.E¡Ž\ô&ƒmدgÆ#bÄëCú™bv^ø~vÇï&‰ ³-äÞ”*Ë,Øl®ôc@+nüNG)d_÷LðQ0:}“³_—ø«ÝøÊæèU-!¥8–áå¢]0ËŽqksƸæmê1mÊ 6.š Ç‘$2ÅZÚ{Ú«òïÜãvZG°³ß7Ym&‚ÐŒðw#0<ðpqR˜Ý,·Ñê¡”tÈ[ÛëêŽ8!ì1ÖùF Ýú’²PFv¿òß„·Ë)ŸðïМ;öaÊ'^O/HãÚÊÛþŠsE6š°Ä‰ºñ%„j‘qìS]¿êMXXaö÷ñ6#½ÿR3(LÇÉîÉ9£4¾eµÜsÛ|”£ôÁÃ/3“§ÀÐr_ㄯÀY&öÇà÷¬©dþ5);_®™5WyÇ»<ÂÛ îF„w¸kÊ·±Ö$/\RÞH=fbC>ÇÂGôf}PÜ${„Ç•]øÄ)“fƒ¾þDDzøî¡«Gœb˜ez"uO>slÖ"É‘×ÃŒ¿öxì¡G^ÉIô¯¶Äºª¤×é¢O4Z >áÕA‹[’ô“Ì0…¢å¡OÌT_»…èqûš­·"2ŸW¯Àn´gÛø]ÇŸÄÕ­œTw ÚΧRæõ”ÜíÙ¼Þosº°`bÊßá´A¸=s£wÇ´-WerèŸïÁ {í*–ŸRP)ùN{^OŽÆ³u/|fæYÚàïzΜ~4ãï­N †NÅA)ÆçlðV#¡x–ŠÝbg&G=™„ÃWe\[Ñiìê¯î3SSMñ®ö/:Xаî*»s|å^4ÉâŽO€”A#~Øk§R¥ûº™2Vq`Ëö¯ÚáœÁ L¾×¬=ŠG˜·½Y„³Â¨EÃg dw%²nMü…ÁzÄÐ.+1ÙT SF£žÒv7r¶ÍÜãT¥r]æÂLRÚS¾uxÌ·{¯®pDŽ+6:5«ºæ¥YŒEøï´çú#05Ö.™h߸=ß0ÈÄææÐ¿Î# ’lD)cZùëóÑíÓÍ“_g)'IÿXg’â6}ٺܕM®Ÿ)ÅÏ)òÊ=ÜŒfLŸÝ#C¯¦»—~ì}wiZÄ'Iæü*屨†{lÖ¼.´åµ¼]ò-ƒÕu$#]ë ôpdi+±ðÂt}æ%-Þ®J=·œÆ­?³ _ý(ïUª³û€¼wÍž²êR ê®&è›ÍÍx@êfTfÖã;;Om˜«-¸ôâ(æœìaø C®ŽÁ䛨ÊL©QóÄO±'â’_y}#kj¤¯±ÕÉ”B„Ìž¾UlöUìûÔÂ$ÑuÂÀ¡´œw:¾yùx4tJ—œ€ñãªðÎõŽñ¦ÑlRB‘7Z—ž+«Ýª®&¨2†Y'cœdyä´§}+Ý”f›âmycj„'DUzkÉŸÃXÚ Ü½=XEÞ-*úÍbà¾7xº2ŠªçGÂ>[Ò<Ð9ÕЬOgûÈ™}ªu^=?ŸXØe”äÐìc§YÊ€£ß¨S•ÈÆÊ0‘„zý@\Óýã™Ù)"ÁJÒ™Ï/~nÐwY1zÂÖ:|wZõäpaØÅ¥M*)jª/b-ð•HΫI“à½Æ¹· ›A­Â’œCæŸ _?cÆG>î¨Ío\}Ñ­Ý$³J¤õr€xd‡£úƒU=_–!;Ž‹‚¹‡ëÓY™H}U¦Õ,½ Å-¿»œöÐÝ÷ Âo'P²WÛoܳ ¶¬Ÿ­LÓ´|»] :„ö¸­Ut&¼UþþZlŒ·Â¥ë³Rñ×FQ‰'iSW%bªá÷äÒgèÚÀG•¾ŸÇßæÇÉO iòºêž¦,CG_Þ±wÈ“R»i[éJ“)`Í\”ŸšRô¯!ÖÜÕzB¤´ÄÛ+l[4Ûå·CtÏ?‰4’wSúâK5uýˆƾÐÕ>Vkô¥åæ¾åÓS#9c±·^z`šûJêÃö"˜úBÅÄNÙËý¤uÓ0Y,e²é,5v;¿æ4ôƒfc>ج]™kXp¦8ÎÚúHýxŽ>:4„¤"¨9 Pá6!€KÞ@›¼üHf.¡/+ w–Šê52±:·'Á Ðß8GŒ'ù’ôâ0ØcŒ@|#bÉyíSé–º—öü½Òb¦?ýC(ûsêvò,l_}c™u (‹“ñg§&·1yÑè6QŠyt›Ê+Éåz4áüÒTt¦HéH¬ Va“GR#iúkTÊ»µó¥e;m‡2 ÊhóÛ v2ÆÈ\pIê_»‹c˽‹!@ïõڻ˛xåÔ‘ÃÁžm Pܽ­²ŠwyÃn@å.=û| ÎjoKLš„yÚ÷¯²ï[³¿0c-lröF2Ö[Æf1*1áŒ×^³5¾ã$¶W÷‰þlyÿNvGZm ÖA‰> Nh$!ÚJÛR°ÿŒ’t6Ü´ñÕѵ)cÈÔ„C˜]7¡‘Ä”Àg¿WGSÆcm†V”´Kì÷ZeWІI3/}¨FUæTÖ¼ú·‰°¢Xkꋪ”Oá¸%µy¹“âªî~Ù‡³½Öî©@5ÛdÇr²joS© Xæ¯z_yecvФ¾%^œFw ÆÍÊ΂4:š[AyÇþð‡¯Êù~Q‚Œ5´üewWH¬»ŸG¸)]3þYgwžùI©R!©&üÀy›ÿ:²gB;!Ž]Ö“|Ò +Vâ\8t\÷âGuøÀÄX mz}šmNvà¤-ïN?Œø(³³½mŸ•‰ûø¦Û‡šS›3o´û² ;Óz?‹“¯¥lÒéÅ…èt ·Â`VÉŠen"µ êá„e›þÔ­ý$c¦a~ìf·6UøÌsÿ„<«®î °/„G¶l#ÄÚ¿hÆãÜÓD¸;¥‘M2Îs…lFòp^b*U¦ yµRöªÙ69àå Ãü¾}úÉ$Ü“lŠ•ô¼£µíF_7(çuûº"ŠœðR•%‡k—íïáš9÷µy:t5×¼I b‹¹K»cºñ`U¦ÕÿîG̃í ܾÈ#-¥EKqêi„úDärí&"V”i¥J|YÏ‚¯c9(²C"UÔ)ºÒ7Ý£6”›éÂ×ç%{ˆ5µø!9iÖ!„ÑE«Í˜ 0oó"ƒ§²Ø’]À3{V¾£p÷_Í}ûö vß ÚJšªø—ô vÔ|Ó'n`ô#™u‰ÒA„ÈäAUÊcï¿ÌmŒͰw!ºí}¦º¢>ñ ù“ª_‚·!1+m¯¼Þú%žôÐO=XŒ×ûÀX%cpW/ú¬ð³¨QÔåÀú§jœpAežÀÀRßQ}ÚzsÔJ¨rKC¯­ˆŒÜì±y­¦3PE5¾ÄõÑìä,('vú\ÌW`6ôÎ8cZ >,ç“îãÙî.hAåQ «Áö‰¥Pœ†g„Çô¹œ”Úòä¼t}h÷=,°J‰ÿ\Ï"aÈü.hRóÅ;¥LRÈŠXkã:‡¯2£Ðµ÷#Ù[Ï\“˜‹Áe›C‰³ÝQiV[Ù¶--òdÃüÛwá˜ò·ŒQ+Bƒ¬ß•¼^ÖȩԼUâ–ßq)eüäy§`É–w°Ú‘÷åãö-^l7<÷W4E„óÓ¼/w:ô1âħ ãÃxÆñœÊØÚúÖf/ç¶»n›/Õ«sƒ;kžW“uo~8¥ßÄ?UÝMlý ÂÀ/í˜DÃ"fv2kÊÄ/ï¡!"ì0RÅ¡”zºqR´²t./A,êð>f@Æî¿7¬¬™-‚ú›lç¶ÈH©öW­0éêp+ ³YMàëyGQñ‚y€m˜!ü—ƒ¥FFÍ 2 J²Øîâõ¾ÖcÆßX>Üc3V<,ªˆ‰oΦ ŸÜjòÞc‰”¤-v²æ/enHûÊy.QóiýÊŽ¥8UP*!á…€fOÌá“nðu»x‹\'xÒ>|\å·åõvLgEO¡~° ͙Ÿ•”T'³Í  ·¤“¡ÉCÔMk?¾n&º_~5*õ^•o‡5$¼×ЎʽÒaºŒÍ]-áæM'}ë6–q„ë‹x‡Ê,ezä÷4šÞÈrÔíótºxgˆlÈÞ—tÍ›¤é=Ø!pk1²ö!Z%xu@Ï.;R§’ ‰Í¿9“Æ­¾s°p ÿÖÕñŒ§L£o1;8!Z¹»æÓ#Ðà£ïxnáÛí–xôž½îŽecåtÝÔk->ÉgÕ×ëÜ)6pzE ñ~ÙÚFš©˜” “åu`ø2Ù¬ÅoÁj™r§úVS‡™ýè×8tl®-ÇÔ©\–5\¯KF ÅPøÃ‘´…4ˆðAðõMÚ7=¾G6ç²}S›é±[ÛC]IT"2VÕ´V.^ÂÛ¡ü¿ù•á9™¼ xW_õ´-]†õ`˜´ Œå=¾ÚʯÒ1AD3½M®&Ä«^?ûö¨¶-¿~){ü˜å?µg>åcAM]ä½þQÕ?³a|ï&Ç_5¸þjzh­–g4D¾\­%¤&ÃJ=^Dt[)þÀ¸Š‹ºN´–´Ù>§•E˜T mÜM–ø$m÷}¾¹'Ý…”{ªÈMË0£†Ÿû}C4C$Më'{@Í–LÔÈ B¥N5S7ø‹ÔRÛØ*ñ³³™9?¬ÅÖùzi…Zr«¸ï. ä8$xªîî7ä{ƒõHöH=æ5=ÛŠsè]¯Îvê›Ã Ï)ö~ÍYÓN8?S 7 ù-§) Ê©b ?øñ‘I#C›¥¼Ïûâ>u…ú”"ÎóžÐ‰¦ì*‹m…9¹ô–å[OQä¾Eæ >Ow›mûXêÖ3z`¨ø±ÐŒû%Á}Œ†]Òn‚·âök•ó«;1¯ú÷òŒÎE»qò*Ë-ï» IuûF½%JçzÁ{¡rAÕë”çdEìÚ«gJ. Ò–ë`^]ÔÒe|lšw3`(ö=y'¬ÅêÇ!Õ£á°Íg'ç8¦‰¶ò •Ы¹ôÍ|[qM…¦`Å e•°ö#Á&þÈ"¿VÆUÀp[Ý&ö(DÏ$•_éaˆ§’1vy”$–£Ïÿê³çendstream endobj 252 0 obj << /Filter /FlateDecode /Length1 1612 /Length2 16760 /Length3 0 /Length 17594 >> stream xÚ¬·sx¥_³&›v¸cÛ¶mÛÆŽm[¤cÛ¶m;é˜;LÿÞwΜ¹Î7ß?3ç纞UU뮻ꮵö~ȈUè„LŒÍÄì]è˜è¹òVvÆ®@9{Y:e3 WÀ_#™ˆ³™‘‹•ƒ½¨‘‹7@ÃÌ jf`f0qqqÁ‘D=­,,]”jÊT44´ÿiù'`ìùž¿;Vöò¿/nf¶Žvfö.!þ¯7ª˜™\,ÍæV¶fE-)y ¥„¼@ÂÌÞÌÙÈ èjlkeµ21³šQÌœ¶ÿ^LìM­þ) HÿK0ÍL¬þn3ó01süÇE p4s¶³ÿ¾¬€ g#{—¿=pqXٛغšþCà¯ÝÜá_„þFØýõýStºMœ­]³*ŠŠÿ›§‹¥‘Ë?¹VÝ󿑦&®ÿ”ô/ß_˜¿^#+{ ÀÅÌÃåŸ\ÆfS+ £­‘çßÜÁ­þEÃheoñŸ hÎfFΦ¶f@à_˜¿Øÿtç?ëüoÕ9:Úzþk·Ã¿¢þ+ ™­9=óßœ&.s[XÙÃ1ü3(Röæ&ÆÛM]ÿÃçfæü¯Qþ33TI™:ØÛzLÍÌáä\þ¦Pþß©Lÿß'òƒÄÿ-ÿ·Èûÿ&îÕè;Äÿ¯çù¿B‹»ÚÚÊÙý€_0€¿7Œ@ðÏckäüÿ 7²³²õü?lø¯fÿ&ùÿƒ#åbô·Böa¤gü·Ñ (nåafªhåbb 07²ýÛ©ÙÕìMÍœm­ìÍþ*ú¯fè˜ÿ‹OÕÒÊÄÆþŸÖ³ýÛefoú_Éÿé_Ô„d¥Ä„iþëú¯(ſڻ¨z:þ%ö?K‘s0ý_‹0„…<ÞtO 3 €ýoBN&&ßÿC¶Á0ýçZÎÈÅÙÊ ó·dF¦þ?Ÿÿ\éý1{ÓfEÅÅÈÞôïxý/Ã?nWg翪þëÄÿ-ø?Öÿt333¸õžëôŸ.uX¹#S¢:}Là#¡Ž¥ªE5½þé{\•†µ¡ôM3ÜŸížË玥©Æú0m)zÓÌ~çãù’Põ n“wrÐ1è—"f\hÄx_/ÉîBh³3ªýšRRÖ/ù€ÂŸédq†¹~¦ q+@'}rDò3ùÑÑ…Òò­®ðü‚<ùôù‰bh|td¸÷²ÿ—&'–ŒÇË/õœ(ÅÅÓÐù¡ÑäòÍÃýR0J8ýEJ[Œï˜ áµÖ°P³7„ÐHDGA‹56YƼ’ÎK¹J.&óxq~áŠx3ÕÌ@ãí4Ààú¶ –Œj¯µÑ]o×’6 ¦Õ‚}ë(Žß£ìÐ#šõÀ¾Y¤o%Š}?˜€dHpð趃XÒ„ûÒµ#Ö6Ç¿o´ÆÝX<3¶è¾œYèî^Öy“Åè´ÏŒ³„é©lJ¢¾y×§7'j‰¡Z&áo‹Fö‘6LÁÌLJÍ)€CÞ`†qè<²ŠC«>ŒÎ2·-’‘žj“žöÕÕÙêßßba@ œ€.CÅî·@zžc 4ÉÏš=-L³m½»•GèqNXy#¡MŠ<¢R£€q±•uÛU¸mðïÊOQ´H…èû¨E0åMÑ&3¹’˜å¼Zêý¼%d(Œ·~}<ɼ†‡ÿkHüB dLíPôÓ_þàEï»™Jßsüiô¹ý&zQe³óùy¢%®_®55 ˆ’)+bº€k[å‰A…Ä‚ÓÞkYÊò”…_©/<.¥%Nóqc*{4”€–|6¸¿BÑßž‰Ò¤ÎCšu5¿’žã‘_ÝšJKX…Œ„¹’ žeÌ1¤³–^ò! ,^ø‡ir-ö‡ß—c·Íé'-¼€ÒW–QÔOóÒ“ÚÃçÊ6êb[XDYt>æâX^‹êpRA˜gÚš¶E*õ©²Ø§)š>.8–”Ûmž ÒUÿÐ{W( å -¤ÔóV³º§DQO/,:o¶æ~ù»Û¬ïfBßÉæø4­6~ìøñ«ÊfJu‚iìt¦°ÒtWdK*ïN[•tÉ8ëî[vȲ«C1 £oû'PÆ:µ{©R.±Œåõ8¤}ÑŠ?ôÔ:ª:$9 ìÊe†øæµoßâ„»à]ÁA´XM¡>Êâ{‹*²ŒS(7GÊ÷ÂIX…JéÄ¥!ÇX%µOMÓ’“–Ũà(Ã9aÒ.á^ÍTåí÷b· Ò¼Asò&YQ¬!)¿_Ñp z©|5=¨P‡´±H>pjéо݆&Ä“‡4{(›§‹¬mÈVM¦/&g¨ FŸ0ËøÚ2§m–>´Éû]ß{ùÚ;&ˆ=Æ»oœ7•„4º?ŠW¾9«$6 ÔXÒÜ! ¢¢Íóç’l%?[ÜràÎÏ J…ð²Z/|¯ÉýJ¶²LZd³ÒÚ4:ŠøÍå6ù»kigê)P þKhxóçãcÇ¢/Q4Û»¯’«ôçH<#f¿Œš’*ç¯{».´_تܯºEÁDâc&Î òæ:Ê éöÐa§Ó!Õ˜Gr{ÄÍ ¤´­ºÇÕï µ`òZ¶â,¼¥Wâaih CcŸðÄ›¿8•¸öm½ÉfDÀaj"PÔÁ+”*ÑDo1ß »7°Ok‰Gu̶Hò‡w«Á˜{HN:íQ.ê>êý“iévCЇ„l›!£j9œ$ÃDoŠÖ˜“|èý_&Ž2\Aq9EÚúWÌ݈iÂ%Û¨>£¿e×ý”µõ¡ösý5ŸZ¿&BÁªa“xìN©|üS _÷³lÆ~¤ó½=“e¹½"[¶ðê&ÍNÚ_Q¹Ýyy½ŒÃâ–áç‡ b圣ÁH½PŸ›O)aÇ5.^óÑš,W ¯5s…:Mx˜’;«'Ìwä·HëŠ'íÇÏ-œõ‚aKÅ"-m .)œ¾»Q,\òô I%A.|@ÏpC‚ àããíu] D—ÓÎöÜ$1÷B3Ýg_ óµ<ü¹q›æÓ¤ - UÑ._“q*á1~7k"ž9ª£ÞÍŽ›'㡈Ù"Sk“ ñó¦c,Íþ¸*\ó\:¤wÃ×Wv®Ei'^R0^¡çJàJ¿Ú<V9’ÔQ;©cª„Ó%$XV(Ó·t¶Â}?ñÇ®ŽoC‹þíkç..4n3?HÅke øŽQÇ,v.–@ää¤ÙÜÈ+ïÁp³”¡ô×âË‹tem#@çÕ Îaç¶”Žžß:¥‚È醮'Håà”"²~ïi—Fnšþ+†~¿ÑL\0¹ Œ©Ÿ“Bþ͘‡Nm8¯]°ËDj[Ó(sÆ.xfã ¿ë _X±(Àòò%A¥6Á£à2q TB^a|éfŠÞ7»ŠõWÅ·d°Ÿ*AžÛŠÀêZï#0ólñÅøRéOÏöû)M‚_³¹ä—Û:eÇ"D²f:SþB’EçÄïÃɤ¬Ò(£m¿VcÌÒ}f,[¥·c‡à"Òê{l¸Ëñ?ç~0 ¨Tü)­ÞÏ0.âtvVL˜ïã². ˆ#Ð~ ùÃ)Å\k<©ðÔÖÐé¶‹ÉJ²â ýl_út冩wÞ<þ‘QgÛlÊœIó/ “WŠÚIЖ'Z/S¤¿ýù_ùšŸ«×À—±“ÌN]4Å$ÅJó†æY"Ä.Â@támU#:&ñHP’ì<^,h’ÕPÒB¢`*%«[ ]ÇÈj]Ý8=ŠåÊpý §·šA˜éºÀÙMyé=KÔ9™‚3; !dm¸hŠ~‰‰øSãºàä­gaªÂT£âWV6#ÌóØ_A‹L·%^Ù,=pÑ£žx‹ά#\(ê!̧¬ü”ðI4iš=†2è‹|†Âòº.±ð¦‰·š€m‡Úˆ;»¹Y‚· §mªuòGß ²ø¿lŸm¬ÎSCPãRÛÉ%\ûÜEÝüæE×…ÌYbZ†´ãÊÒ)E¬ch¤½F Ã%ábçîÕ"I00ÛMÙOX^%œÔýÆ^,]8òpX ±õ“è\—Õ´ŽTßyác±Rár4üW]ö’°™É!4h5bà\铚`‚éeú˜¤êI¹íøØjO k˜ ß Yå„ZÞ/ƒîPÜÇ‘û4Îôb€”ðŒ;/¶)ªõb´ø ˜( [j샬¾ B14¦7 ŒÓ‚JÔ¶XÝïR_~‹#AÔõ­—Q8{駫޽ÉÝ€Îüæ Ê<Ÿ˜”Í?’®ëÙö­¬)%êé+" ®˜ÇáW9­Ö½Í†eÉ¡ü…øî}ÀÐñOæ —Oýóã£å0>QJ[ÓAC¸‹”)~µÅ¯Ý—¡!ô) g.•ߪ¹æäÖøXSÙJ€qªÅ¤ DT橱à¸îýöE…Ù—ôï™þ'ŸÛ‰×p0ÜíjóÅöÉcíjüå; 71ºµìÖíǺo¢ §I¸•±üû}«Y³(®ÓÔ–m ‰…|¢ÏÆR±ë0P\éãn'øIè=0Ï "™¥f1J/Ú%sÛB×nîZ:i• µS¢ÅýnÛ×ÎPò‘3§>Q£1 ÃzÙæÃŒÕQ††…–ô`MÕ¡;¡ky~˜åÎò¹œÝ l7£¼RÓcr„V^#F,^l¿¡4q8qà “—‚ Öùù¼]"ø†2b”!u"’Ä:SyDªq¶@Q• Í%å&¹Pر¾Õ[ß4Ò„ÚÀ·0f&Ë8küª5$šÂìŸj¶M}øFà¶zŒÖ*öëAê…7yú šÑ]ütvmþý˜å[Dg$ …Qd§—=~$zØí«$+×&,ç`u&ÖCeCal5l£&ógËÄôyëÌôϪ4aëªoSTÆ·d¥H‰6  ù¯Ê6JgR y¡+gI"¤•g…u;jSav£ŠdìÔBZËGJ(5‡õCuY™µý“?Y¹ŠyÚúô¿ª@ØMkÜpD.óQ´”æ!WÔTzç94 ¶»)Œ.à¼X·¬„ÍâuŽeâûŸ×(wá_éââ.|®É ’Öãóâ$]ŸÑô¬¤•úH=¸i˪ÙHöª\ͤØÀ¢9*iÓðÐK/=iÌÒ®­Ìð_Zf_kal´í¡6Š’®HúË\MY©Ã’c ˜ÎÙˆÒgúž™¶e¸>ù±à“‹‘‡ÖõHÚý“J¡u‰๦zðM½2Y†+ ¨þOÞëcš'h)÷;ïܼ'αß{D²æõùÖgÝMqkkƒ¬a×ß…ê¯`¢sT¿Ô:6Í}ëAC0OžÇß>Dx$šÉZ×]!âYˆ;á@«S§»cz…û F*ÓîmzÍëN y}²FlÀ®× §éô‘2ü¹ýÔ¬îv<â„Ø2Y-»_‹sÕ¿B%µ²µÎ“ëížh•ûÍ7Õ1]kpKž^4ï™›UP¼;{¾Á¦¦»*0›ù7Wê$'r8h¢éÌï@¥qêÔ}µ°êøgì7ßé»›“ˆ¢âA’uÀgjž„3ÁÓÚÏÜ+ÞôÄ –ɦޔä`>/ 2ƶ/$í ç$H{¾Îfàº(ñ > /H·n†;êû<,÷Åk¦³+×ÀÄ”õ´‹ N—=ìò£Ù‚'(îVÆẼNlû»ñ}/§™Þ×z ¦¾R·ÙÂÉ›Eõ›à'ÿofßiÒàXR­dþ&*·Hô<¸wrë®dœ¬±ÀOé7ƒ‡aýÒŸPš'»Y¸<Ò”ª:R°ø˜!j„¼èò}½eÊ?ÂKžOî²h³™žsT­_;ö¹T­ÏHM»H ¾½’¦£îŽþ _ê">p%xKlšçù>ð³ ÀdÜꊂgOá¢Éï×… ‚l~“šL•ÅO@ïfQLõàÙʺr¿ÿêC2P›7¦•ˆß`%}ÑÜP¹©Ñ?A&sýäF¼–<‰;WÈ€I g¦š ”ÍNoÌAN¢™‰¡ò“M¤Þ«ÿàPÃtt?¥º0ø*>»€¡9] ûNc›ñ¹÷bCÃÌÛ¸¤Õ­ËÀë}†°‘eôP ËŠ‚bæÚÃtÓg·î·®j2fÑß+ŸÑnqo¬ÐQWîe¯Çkï![-óÀV¿ð9´Qׯž°¥“‹‘Tô¦¹5QàÔpEÉó´Ý$@l¡“©Ì`QéþøóœøCÈ;éÛ˜í{ÇjÎë<o>Öp¯hV‰ÜÞø>khËTŒý¬Pe»ÎöBË/ì?øòkªò92ØÒ!›‡$6› 2þ} |ôÉŸWQoû±ÚmdÚ¬ ÿq Û‡H4Y\âµW´Òy‡.žxX`² Fý#Î`áT¡ßX¼FÕ‹ï°XÚDÙãÝ„•X^ÙBm#*'~>\ò×n‰å‰¬·3${ )ˆcÐ-ñFÔEì1€7Štá©y=Òʰ³¾Ñ›~§%'¨eôQ·BÜLgPû¼þxÙØœá±Ø.RÿÕ¦ª9y³Ý¸D¸È"5ßq¤k‡nòÝbÅD]oV†U——y$‡p1õ6J8’‰Þ%j6¾Ã1wªUÀ‹¥Ë:W«}:þ ñ‹‡ÕnþúÑ|-gùáp;‡ þþZ«ò{‡…M/@ÌÏ•mÙL¢e`¿_šñbuÔ ªrg‰VRݨ ^ ˜TIz¤_äùÖ2ù™,pp –ExXþ¼é~zè>³]Œ+Ö‰V{Cu¢Ÿâ$J¥aÏ5´‹¶5Ssœ ':;«€Ûæ¶s[iݦ¨àu !ŸèÖºº8Ë!ìyÙ£€~zLoæ5 äíFáâ?©-|0êXm/–¸k‚ƒØàšÿvrË£6ù ²Q|ïßT2 Ö)ôÜ/´Z7æ`•²‹<ƒa”ÔÚ“AòlîçdM¢ ãüø£qÄaáû —;Ù7­ðyòz Û„CdhäØ+õ!ƒ¸ S\ÿO¨šJÑ»ñÏgµ¾ò¢0ÈŒ5ª¤gÂtˆm†R]l„ï(ÍúÌ<QHsêîý0؈wäú,9Ä4¡²šQò”{Zš¬ëü­¥bøózè§%‚p b€Š¦©ÏhC¡™lL7·WòûU˜w»öÙ›+™lüNKâ³æ IÇ9~ØJ4TË^ÑÔWàis<Õ¯\_'íe‹Gõ^)ÃÐ ¶fŽRä®æÓŽ×ý ðØ[çvpnÝshÜ“l±ÙÃðýý VŠ0 ¶3h쮡{÷%_åk!6of¬eÂÃþÙyŒ¯Î•Ú¬+Öºy,eP¡Â·…6Ð,ÈÀ±¾7¢”ù“ja¸6nö]sZ“ÏLF3uUF›þä§5/~Ÿ`@O7I!$ЩñNT²ÕÖc›ƒWQ¦¨•–¢ äèÖîÄÁwÒŠi!"Utø{Ä8yä|"O‡kJl¯04›4Ød™s´›JѤTFà›qŸnbç|ß)j¡iyÏwÍnÆxé|Ý˸x‹'¹ìôëf¦jì–®Îe+Ir„†S>ä¨è3ŠZª“+ •7`>cS«§S’–p3 ~¸¾2ZÂçW¢¢FUwÇš5Ä)ÌÅ}¡çŸÌ1ÆìÊ ?‚äZμ™L{#ãJ&ýh¡Øh*=¹Fm®Ø„é(|í»ŒxÇ­€èžšŸµDØDü%îˆ{16´¡Ô5FlòÒWÄn8xî Ó´.o“®×2ëƒèÂf:2(ù9Êyû6rÙÚܬð\"¡–î`Ž^i°OB<˜µ°Ô»Ý¢J*›õnw,‘îê[˜ õè=±ôÓQ›/ø*¹íŒÕC‹ZŒ“%«½ù׬³JbÂ\D ©›Š]Ô;]>Wè–)ò½ÌÊ…Ì MþšT}Àrˆ !ÒÝmsYÐ4›ßþ ºmói(¡ríÐ?-r’çôºÕ• Þþq‚— TÁª?éöJ°SZã6Šf¾b½2{=¬bm® Å6W…áûõÆó"x.Ûr>Í 1ô}%x”·« ™€ýòÇ%ž•qF“Â.O5»oW)¯RXjvà!·MÁÚh¯ö¸ŸÖ‡œß#ÇzÚ~û g.J™R!æñ}º›ì"âi$ÖØ*Ä4crKgYºòt5Ãûš<èËíÒJ–cyêvtÁ u”q¤ÿÜö”xìMþ)«('ìU«-Ԩ˱ ‰zóßëQIÅñé^•5eYV Í£0KÆY)Nq_!„Ùb:aÖÚ9ð6ÁÄjÁô{¿©&êßç¸Ì̘Œ^¿‹q¡Ú¥tlw»l5ÂÐh6â~õàßúÌêùp¥ØQXupÁ"ƒw‘·ü,ô'ÛÉhý®ËñK0*8øSsF¦7ÎBn›tËSÞ¥ACBµPÁù,5FºÁ²ç]‹Æ”ï9£¥]§I×{öÕ"yŽîx4'¬ÔÏÃæÌO¡oH~ÞÁ"ùqÀCâp ‚¿¿qáDî´àB„†¾¡(þŽ–Bk&ñ¯šaŠW£6&‘cØÁe£‡¥\‹B†)!ü“l¡i.!{r&ŽYâ@ám(¦};HáuG%n“Ý3@£eè~]ñ•c˜×€ÅQ¸$¨6zÚŠoÛçô½Óa2úÅñóÉä+‰$渕+P(@)STþÌNèÄõÇ—™×g¡>ñMö{³ör§æëo¦pŠ,É ‘j ~¸Ê9fàÆ@áZ©}úÎþû|¡‘ß1T -¨ëTÒ¥+ plÃ^ nZ OU¯ûÏÕk¦_»XÁp_îI"‘‚¹øKë& Õw­wëÞÿ@8½ó$ìÌ"°Ÿí=1¡‡õßr6ÒZ¸Kh:Í™ëÝÉ€øi«¿£ÂKl/¹D¥Bü˜†¤DYc‹˜ sT­¡â:*ˆënqË~þÄ•¡ 9%'î_ñí½Ô›éÆ!+ë-gþV±‰·åb±mu<¡gM0Šf¹5ùµÇâñ»Ý™Æö9¢2GT…·ÌõÔvspyr$â5Dëh”D¥m}?+1qvÁÌ 4ezÃŒîs m‹»ªRpÕê°×Ã<4–uFßïÙµ8±¼w Ù#e‹Š7Îh~öÎþEV&öûÉ2ì’ÙH7È­%(…(à Ê~Œ=S/dÌA¿xÆVè˜0Å>Ø69"1fà ú67ÓŽ)Ý[Ä—þH  ,´æ¤GÀzì_ò7H§Š1ƒm¨g¯Kjž*‘‚EenÄÊh:vº;{H ÂÌ~àûV„"¤^&=î#:™AaÎpÓâÁÏæ”ŸÕtçQa¸Iß ÈYÖmEÉîržƒ¦Iþq@1±“Kª2¦³†¶/½y~‰îr–€À±]în“uƒ†=}«IZD ƒò^{WËPñ罡‚žAG¼% L} ŽÐJ¦‰™íË#湪êŠ~Eð…ó‹õF)8eä eû‚+o:ØÞÿY¹Ap‘ÑzÌV ©°V¾0Sø¥ûœEóŒc“àQŒ8E>©DÕk[8 ɾ!oqÖÞ&fÓ¬X hÄÙìÛ&ÒO!?¸>¦D0õp¹«öá\{«1Ý™²XKî‹DEƒÚX½Og wG~µòØŠ0UÈSåÔ–Ž  cxzbH»™]”ÀS.OCH¨ðuq~qž›þ¶œÎû°¨`^´d +´‘Ý­YM.n;Ï/‚õ;ÙÍÕö5#:6LldìaÙ‚ïŸx%ç×!`ñ‚ôi`L๪<éc:ë7Ù2‘â¯%²uÖˆ<…B#Zë]§#× ¤(Þ36çxPlEèÈœÉ×/RŸ3çÉù¤zkWÎAá i?LÊ9K³›‹#cÒ2“iȨ U,õùÈ{OÈ1kË¿Yo#n`æ¹]d«í" »`ç'ÄÆC_‡~§v˜&Ü4Ê–µ¤tèíÍ:žsû=h‹êâhoe—å{EG<.‡-bTl­ò6Ör2³sƒY)ö’XÔ‚‚¼óÀWÄ/FN,~Q•‹½">w[²ª¸«ç¨çÈ×ù˜·n!ÃÒ°Ó *Æ ËoDáK®LÅ>Ì3ñT¨7ûŽø«?†Y=™8¨Û]ì?Ô˪Ÿ´–*þŒšùÈMÂI{÷¿¯2rÜ“åœ oÅõ‚Ɇl/VnjøÈgˆøÒùG+LYûUEà±Í¯ˆ …Qî˜Ag­ÏjÒ}º×ÃkŠ“s… ¥é7×;ÍÌCpY›âg±Y Q1ãò›±†ÖýÝ}7 õíw×dÙpøBh؈_æ°áfßR ^Ë®5"KÚûüFCð~j.?ZÊ}Öò<NÆîí¬Ê#žfƒÿì(É›ÿ–Ò!H%eÐ!Ü]iϾò3-_£/»û1šÄíi[îνéiã˜?)^åÐkª˜ÎVqÉÂÌEúã1ÙdÐèЬǧИí»;ч>×^)öãe{©¤)&˹ќDØÑÜ<¿iqí»}èp>ïå›r:¡÷µŸæsÙ~—[aèÌ(dÁEäê=C·a_tX!Ø÷ZL/è½ ÉpVÁ!ÓX/¨|©L]¿Í=q°°R©²1&—òš^]¹TâO²¤™>èg +ð&£+°çt8ü?Sn/QV>)™t†ü¿àÔNñ£Ù‘´‹6m˜ »Žæë3³KÉ9ÓqI…ÂN®Àã4j°Ò?3§^l/¤†`pm‚ƒ>Ïq\dPÏËü{¥BµÛË>šD ´ã‘Ϥ«­usØYö½HÑZ·ðÌžM¥’%Òu8tRH=:ºö©´m–…̾q?¦ÊÊ¢ô+àkë|(O‘õpZ­íŠ«Q¶½%Cæš&H•^=-ƒœ‘8פb!ù{ ye3H£|ÕüC®žÓy‹|yc®¬³nJ&P …¬Á€”´ÖЋúio‚!¾Åƺõ^ÝzW¦G° Óa–µŸ×1ü³3F3Lvýg+-°£仹ª¶øW)š{û`?ÙÏåx#H!t"†a¢ûµ)v½Š“¦»Am-L÷à…`Áø'ã£Íî› ´Ýâû‰Ôpäft¯. ¿üWGø†J6e©gßîÍ.ì_LÊPXédÏÕ¥¥±T.³)pYæé´;ºjêeX ݳ}ªôÖ_Ô‡üó¯Y)7¤‘y'x·òö ¬ÛÏG§µ®í9’L>{‘6%|F1ò7Y§[Èhr6TeU`HýQOG©æ£Øw¬õR ‹Rí:V?‹…ù}╦âȪ3õ˜ïw èq±Ó= «1ìÝIÒ:Ñüüe¢¡ûŠ‹Ê¼‘ÁÃLã‰û›í[ñ¤%àPg/’r2ú!)°kwoÛè”õ—|ýoà£UeäÏšé- ’ÝlÆÒ‚áôXö}$P葞yÄÈó¶Èýºˆ“²Z5ÜoúˆLž\ Ë4ðFz7–@úMb«b਎*ˆFoáæR­>bâ ¡ŠÏî´À‰¨u}»ö¢öI†i¸Á!ŒÅ8À™eAh:ÊZ¿$tãäd?ÁFü£î'±©®ßkzôŽúgKžá3¹Òâº[×Eƒs1 O Ξ\v—Ë¢‚¥Y@÷g†ðáù zûûmóa÷†‰³FM‘ •XÜD««/}Ô¥ïy*’j2þ­ï MÙ©QúÚèš~9ïÛ ñmíâ¬Á T÷1s’öwŸÄÙ!p}ø‰ošÊቭöÖL™d®©7‡Ÿfï4;íðíy IX5Ê?ŠLWð¬"«-!ÞVQU)‡@—ã‡ìߺÙ{äªhž¦ Nü¯N]µ~类ï⪧å S‰côAû!“\öÔx¢a£ëæ1ÁæqάP òïéRª¸ø]d tBèÀÔÕñ|•}Þš“ðQ`W1(¤R•ByòB$z*šTb%ªk˜8’*ñ±ç¨B5h7ÓnUµU#>²¿ªIî§ð¼íô žpð[Ï£Qþ, Aj›‚ïæ9ø®ÏBs§|ƒT0\uüwEÎÿœfºËie{ ¡FóšÙJ/ÌÒ¸¶o§IÍ3<År3Ý\b¥ËVÎzµ3¿ú‰Ÿ3!öUZ¯¤ž]š½0›œ¸„B'KÌ®Ð3ßé'sq§ED¥9<°bV%ÖHS‹ïšf¿—L5#Ì®\¶-")'pë!ÇÝ Ã’H°”Vá2W-vÕIÊgy`@c–çˆÎwýxßWýc•bxFͼkbryø6¥’$¥“95B!œg®¹®ˆ–¾=¯88º¨6$æã uD„ M¥ª‘`[ê©¥ýƒùY4¤uÛ©&¿lÇÛ7¶ÒœA•©Qf¼h^=rñ©K½Ç{;¥ìHðNŸ1®m ßCõ÷ƒ—vµN9&_*ˆL©ûOB½µbÉñ#«üZï çòõ•Uü¼C€¦s] ¥h1_¶K8zƒKú‚éQ~ZF#ãE]ȯḚ̈–Öi­Ü˜Õ92úŸOl»pY"aÅm¢…®‰ƒ1}S¶‰,R™Ùïv¤éCQÉðÆ>›ÉØd£ó('RWF×x®]âvÓ‘jˆJaÀè·ÍÒ8ƒŒöb¨˜°²Ì3zä|#› u„³µ÷X»°k׊l~«ì#M4_¹ {iaø:Äù¯ÛBxf)Ì`Ýe –+¤â鼑š§q4„qg%ºQžçf=·0xõ×å  rvI¹3ò—W-‡ŸžWoýsÓýß[¿p}4ÈùAna¦ŠŒóZRÝÚR¢ïr¼Ws"Ù+([g€ô´7’MI~¾{àÐìÎ ‚‘P|¸”¬0ÀñsuÀ›~Üéú·¿e–dnWhy½êðÄ[‰ƒ|Oý_âÆb‚)–^’võTdG±¯tKÞs?dM©&*ób›dº®‰„>~/ ^ƒÆÃ%÷–åzE9“b ­Ãô*È¥Çb̯ù¥Í-pvÊÔÝöˆO;£ÞýszÿZ烄aCrÊöwUÊùj¿W`PiUu0œµš|5¡ÛCkÎL¾*dõ‡ÓðKúŒÎÇ!m2…Ç()$øÊ÷hËŸV\ Ró@p¯U=dwú¤¾ôÇv?÷ŸEÁ"l_xS€w›Šf5´¸ê$ÅU/o"|÷ :"¤Êéö l?~ÌYúrp3tº„(7ÈØ?=æÚDêçt^Õa–1T†½oüÁ‡Ù>ÌhîðÞSXM¾|m½g’1ýôzkï­†‹ã€¿‘••GÅhïG öÖ°N–ž½(›—);¡œ¢ÍÍŽ­ÇŒª4K×A_´úÔÒöP.)ÝÖmsï8„ȹ»½]®’kðžj§µp¦lÜ„PÂzÎC)—ݯ5[ ×;’Èò»^-uHGü89ÀÂãÖŠ¸Ôy–”±™é5þ'([©y[ž0úš0áwŠ/¡2zIçÔU¬¸TäS Èõ­Ö57¼³±:š¤¥öüº‘†ˆ¶¬IŠuÄyÚÓþËq‘ö¦Í:>ë†Ö¹a¹¶ÎVK¦ö‘¢hKJ' §¯ù¢¶%k‚¤ø˜â¢ITáàHÉr2·‚è!1ÝIÿ ‰oX‰ÛÃÊdVßüòl<¤$‹Ý:J•rdˈ\æKvçAS¦C¢èqÔë~áÒŒ!‡Å&­33¤8v¸c^O/2y/Ä3õ¾ø†Ä¥§a+c;9fÞ5CFÁÐás!;ûÖ~SÎ"È>ºp›ÿŠGiÉÄûxÿ߯Õw2ÁWëëös+þcЗ?X;Úã9;³ØO‘[Œ*ÎÌÕÆðZºº·Ó£ý¬]ÀÝ’• „±ý¾¯ËƒFöæé»3<ýá/q±édóýY>¹{©<"…ç¡! ùªœËÏ#3Φ»œî؆J½i×7¼¦ˆ¦‡v—ˆÀHëU¤µçü»>ti©æx8«F÷g¬Kà’ŬN@Wº+Ñœ‹ô=GsÚámv#…˜î£on§ñ êC¬D'–‹@èÞj—Ì>Ë'«EWW*©†aÉ>¨>ÿœú]¹Ï/Ý+bO+A4¾Tg,*0/ÉÐ[¥ƒ'z?Qÿ|¯ >@ãŠ/×ú{Dl^U>uˆÝ€ÁëœRÍ0ŠyGZ½ÄŽPë¼£{Zð^Ç÷3à;íÌhÝ›Lu‰Æ™ûÃé©ðÈ&2\ò(À;ñ8K/ \®ZcU÷X&’ÁŸ(Ùg øj`:A Þæiø§ß'ø­Ñ[2¤S¹y8ºŒçØZUûx‘§8èô2úÑà]`u÷ÕÜ¿…¿®ˆY0_.Ìë8µêj=JS| coµ¯ö}@ÉŽÙŸ¥ôJ㚟ÓJöÖ茣%åÎ v³dU^ÓÀ2{MW°oN˜^¡½Ä:­ï2lJ4 ‰€-»É÷îô&’†e{u!£ðÏ‘ûòÙKsÅfYÒ÷Þ%dÄAÑ¿ëµ+NO›‚šq§œëDÑ*¿ùI®Û´hsð;`û”‡—±NÏ7K(ƶö÷0ì¡´È °rË j¥Ù Ì{‰ Ÿ¥Éþ– \Þ)d¾sEQãi<’gÝ™l0ÓÍ:Ò¡³7d8–Íæ×ÊvºfGÃl×ÞXµýŽžAÍÞwM÷#UŒ!‡bBr‰O„bMpÞBç8’kÂô,ưϟNÚÑ~{ÓêojuÓÞöér¿¥¤Ãmã¿a< šÇLaqÉ©¥Ôê ?ZânÆ™˜XÒÏë/í³À¨U^©—œÓÉÝê*MÑ,d:^<™ ø¹rö#ຜf½ÄÃü~`ôo”C×'§ë‚…])-в›Ð{‘9|Ò^Œ_Š’*ÿVˆÙ½¼èïf«£Ó•gÛ>Ĩ#EÄ“$ wÕ³Vj¸ÆK ~ñ­”ÀW ©”)iJ–d`HFsij Xm³^œì(·êl‘²¡FälX– ‘@ÍBØÁÃ.ƒ [ñýùB²õ™éù-±ù$7â`.<¹ N6µÚrˆš‡<ïE3yª|d~¬\ËR£±ž3áSñƒ´YžLžËÃ}ŸNaK;†ë2íZ£ÔôÆ’Î.1&×/ëÝ| +&eJã(¦Æé¹é‘ûôõÛQ.© ,‹ ˜¢†ÞÛ)YfÛ$ 2È5îtÚŒ # XRÎi˜–gÇ‚1 Õ³ÁK¼ë!o-Sßå©Ó̧eÉþÒJpÞR^6 6áa\ÄwÔÚKf'Te”·—¢ì·<ãkN>ÓóÝâaAOÁü} ¢ì_PMßÈ…Þ¿{«˜ŽN¯ùæÏ1féÛE@1 RxüÕ1—MŠ€Ÿ "h$éF‚Ê~Ätˆ1½°V=¯½Ýj2ÓÑÕÉ õbë>¸--{GFÇdmôPÓ¯FÜÓOÓYŸÝãL%:À™Œ(—Y1Ý˨²-ˆž¶qsO[zPï’Ð÷|  „ûþºˆuèµ®}Ú† ƒý ƒ˜zΖ+dœ”¤^åJÈy«ö܆M¥mbtØ\¢_E4ÛÏfuf"¤y'~qÛ8ãã ˆúSBûà=P$å÷ Õò{á² ¼ÕCÚ~¿!ª@:´žŠ›˜*Óâ´*ðÐ AùÎJ\84 ÑCgWÍOY 8­w…¬fi‚‘+VË Äû?^ªç t¸ÄóN;Óü 2Mßvžå1 Y™ýs¼z3³A9 ¸zÐt¤Ç2Ò”_57³ØwÛ%Ó-ëÉÆc÷o¥eÇeT‰MÄÆGU˜ Ѩdµõ2]MÞK¦à¼œOð¨W î_ÊIÓX‡|,6´;æ¯6É/´ø…± ÙŸ°a)jõÁÙË’¹óˆ½Ã5h)²{ãû+w¯{Ï|acï°ö›ÚÛaÅ:ÍdŠm0bpøsúå#2Þ²N\‰cŠ5rïÖ¡dÃU_¼\ø%Iè ?‘Týð µÏ¦ÓN¾-æ¡P†7Ga‚al³Ió9%=c¯¸¬oĘ;3¿Uê¡”`D& -Ðk9¾ä fal—°R¸M¯£§»ë¹X|ÕZæÃs«^˜ùäܪrý«±ßh/MgÇ4ŠÊ²nZ.ûÔ·]ÿcˆùcK³™›t«*ϱÿ¦)” T¬0Õ1È× ö} Ë!¶–Œlg#HO­Ú-ó[åùK/O¥ÃËÀ[ ÏSœÔ¢t„Ó~ÛŠ Á¡—‹&oÈÕØ¶üªÆn1ëÀËPãè,¨„rån‰Mày$ô¬:e©r}ø…]aZfhý¢`|aMmÄ\¯ŸsÙ­Sëë#çœáE¡`£æ# òÌÉ“oŸ“Äl^áaîêÜÃPÏ’«ÀÉwN@ÒD–©¦vó„ï<¡mä;ØmJþ1yLYªlJ¹µÎ¡c„°šXÝe9Ÿä‰Y¨7ÿ2ùã9M~UŽÏt–kQÅd«µ²o¸*t¶ACnŠ>çýûdY÷ä|`¹oöUX[)Ó”Çå÷™ütŒqH×áGmÈ4Ât‚ÙºÔ×ûøI*P¯“®1Œ3g ÙK´W?ñ{ ¬l$žßÕwÃV7jœb9+殥ԧŒÒ<ãôµ*:úhÖPŸ1T*úE’^b‚m8FæxÉÏqAŽ&û4~«;]oTTX3D\-l;¹WÔš+uø>Ž\«h¶Ñá91Z3òPr]›õG"WîN'öÓGŒÐ1^qž¹©íŒ`¨EÕéµIãG 'y’¾ ;Çí¯máŸJäŒ=üΪ³"‘¨9Ý57¹s—…n.)ojl»7à`ÙDÇ[æ_°ÓK ÛŒèÔ-‚¥e—Ý÷ÿ#±Nü”ÎÝ•û&V±ô|ÖüjjñFö\Ž6ÀE‘ìŽy‹çúºùôö–ÙµD¸Ã”.Þp;ßžæí5©J×ð—‚kšð Èе{3Èõ¦Ú(ß±‹_Òûõ§É[p/õ@à\ÂŒ¸O¹åŽzu1gÛßóCÃ2÷¤w_~°iWš@‘zÀ3y¨°#Þ4á¸%êu3<1”Ž’=äÒ„íïÛ$ö&µ`LÓ$tÁ‚õªÿG„éY¡/k¸"9$°÷]×ݼöù£ï­Þ!s¬BqªQœÖlkücÿeHBo»µDM£÷à £)©ÿε}ØàœHߌÒÛÿà+ÞJŸ!é6nrMIW2Øp¯ñ2+®hýs÷íjøc€m"fwäCH‡>5ãñ”c>³ïøôpS-O,Z”Ìö@Ìš.!‡üé+Æâ¹aìð©ÌTù5÷˜t‡ì —9H|gM6:aÃTÕý’×4G;Mâ[P±ÙJÚÍ@u™Ñö¼Û@û-¸K%”JVó}ò<)ýNõ+¶Ü‹Õ88gè¶Ý‡Í°¼»ô°0d l1ø%{䛹å È­X!£† ý;dg¶;!µ ÚtUÖ3Å6 ¨x™A›™»³wÅøÆ€‘ëÇŠë•LÉ9=¨J^êb;‰Šüð\ð<¬4W·Þç5|©fôÅ©$«×>»…)Y‡Îëùå„]Èì.yy2:IÐ-jÔå›væ­a8ùwç2xäÎtñ:/î_[X¯°j¬kt†ZEÓÈ ¤õÇÂ×ì${§Õí\+èIþÑcb?\%NI‹k«̰ïÍ‚ž¤ú¬Çµ"/ÕMÏ—žU…¾šêô+Óšu$ø‰£)v¡u 53¡Ê—uLßjmüÌø€µxîÆqõ­u@ƒ”P”|NËi@Ü8G>˜Ç, Téí)oPß©¬§;ÿ£¢AH3yÏQ°}U$ξHZMvlŽ„0ÿNd>XïB u¹vÐ-•]({ O#ÎàÅ-ÐÚá/¿¯ižŒw){[Ú90D2<¾†É„ª%¬*×F½;Ä:Bœ^–Aý8”™Ð‰Þ0s–²ÛÑÀâfcóƒjƒÈÉ\ûðCX¡RêŽY^!?ÙÐÕ€“(8)sÕ]ç–ûWË6#RÅëãÚ±~Üt{Ðoõ Ã7#¥óÀßh¼fq@Àa¦„€qäÿÔ~ÞãQ|Ö‡Yóž~‘ßKa4SéeTÖÓendstream endobj 253 0 obj << /Filter /FlateDecode /Length1 1626 /Length2 12153 /Length3 0 /Length 12983 >> stream xÚ­wct¥Ý–ul›•Ûª˜Û¶NŒ“ŠmÛ©$…$Û¶mÛv*üò¾·»oÛýýéîgŒg/Ì5ךkï1%©’*£ˆ™ƒ‰¹„ƒ=ˆ‘•‰… ´3quQq°Spà‘c”77>윔”b뾮  ƒ½¸1Èœ in77°±Xyxx(bŽÎ@K+€F]E“–žžáŸ–¿B&ÿîùÈtZÚ¨>>¾šÛ:8Ú™Ûƒ> þljªææ•9ÀhkSTÒ–VÐH*¨$ÍíÍmJ®&¶@S€ÐÔÜÞÅœ`áà °ýÇ`ê`oü«5¦,€1ÀÅÑÜø‘fînjîø—‹àhîltqùø]–ÎÆö €@{S[W³¿|Ø-þ&äèìða÷áûSrp¹˜:A€ªJâÿà ²2ýUÛøá8X|Dš9˜ºþÕÒß¾˜/Èhï™»ƒþªeb0º8Ú{|ÔþstþMÃÕhoùO gsKcg3[s—˜쿦óÏ>ÿ©{cGG[¿³þŽú@‹¹­+ÛGMSÐGmK =ó_»"moá`eù‡ÝÌÕñß}_ÍÿÍ_;CûAÂØÌÁÞÖ`fnÀ¬àú(  ùŸ©Ìô'òÿÄÿ'ÿŸÈû¿÷_5úO—ø{ŸÿZÂÕÖVÁØîcþñÆ>c{ÀÇ;üõиÚý—c; ­Çÿ/é_£5ÍÿÁVÔÁÖì_}Ò ã‘ˆØ[~ÈÂÂÄò#ÐEènn¦™Z,Œm?æõ·]ÝÞÌÜÙhoþ¡ëß#0²²°ü‹OÍ hjcÿ—œÿp™Û›ý+ý©þ&Ï,¯ &ª¢Lÿß<®*},HÍÃñƒÛ¿µ"ï`ö‡¿`DEÜ^Œ¬\ŸŒì¬wÏSòo ÖžåAÎ@w€îGß,¬wÿo¿žôÿ拽©ƒÙ_k£ 2¶7ûØ´ÿ0üå6uuvþøïËÿÑõ¿ŸÿÞysswsS„¥yS¾`ëô¬ P%nnÿ¨¸nw'+dˆcaÚ¯þå~éá›<%F/!Lµã¼oMsÇŽ¯»2t{ƒ8¶Ô©æç߉|Èi»~ ¯QµpÓï2"gœhF{]ÌÊm@ép±hìm*«¼À·°;Ã]<Ðú“ýáEqïˆâkšV‡ÝŠV †Qùóø„*éðឺwh ¿¯ã ºk—>'ž’Ï×7å˜4äaä|[cúýô•ÛL}ÈÕQGfIŒ)Á¬®9SÞ¢lÎ/‹¹‡¾L‹ik®¢üþÆN>E#P?ZÔî¾@\ÙµâpºJÒ ª¡·wެ&>“´úI=¾ó!¦6´0ÉÍÂÉ\ -Ã^ZÙHaÙ‰qÆHõ[Ö#~ÈS€3eâW@•‰/§Â‹ Iæ^”yÛm×8¯h(Ï”v¦çâeÀ ª Ìr¾V1?ÜIÌ—Ú–W¼1j¿°ô^¹<žeOšËõA“tÈ< á[¾„DÚ!­Ø²M^ÜÁü{²Ÿ/ë¹¼Œå“‡ËÖð¸ãÀåy¬Œ½õT­[ËRƵwÂ÷… |¦‘?àD³ùSrôg$o¨bæ%l†w,Ï_ˆ‹•Gèx,W8ºŸá0’ œd`&yêºp{ÖprÀ·€T?ÒÒóÎÒÒ>Í2uaKVÓžå9ó)y+j®YmD}Š‘ ÂB§ÉéõZEg8âìÈÓ}¦V>áFo.?aÊÛÚR+W̶¸Žìµ3&"­©ñ/8 ôÂÓ*Â^@)vƒ3xƒµøtÛÉ÷)})†ÞÊ ¾xë™{ 3q¾¦ iC#½i'õ”;˜§û® ¦Ï?`Añß\Ž[,à»í;F—fíŸ7îÁôßtboê¼³ã+6,¸%ýG6K˜Åõ Ug]EYÑ…¾Yt 2;¦•ÛeÜÖÜ)×]­³1ª< 7S9rÉq,ôk'½ãñ0d¿S…óß„Ow°_ËÔ–*ÑeÕ}ª†œOz}ßéÆë0ÀÙøeæ“Àht3ί¯‘Æùžf’/Üs@,ì„]ô¿t‡n:¸ ûm²D¤´[U×Rá.9Ö-ÏKniYOÍÐeUÓv 8GÉqñßfë^ã—Wt<3a2Å[òŸºŒ|ÇóC·q‘U©yÔNÜEw}[\à"‹|ñEÎŽ*5k®Š®”†kQê…û¤û½ë<¦û>tÄc[@×Ã:ƒƒç[¶>•²Sžm-–ÿŒðªóžð{Òµ–uI Zx$ðÌ~\FöJµ ä'm¨”5·ŸaúãÖzl~¢‘¤ÀyÉíwîÖ†¯ùpSÓýi⼿™ ›Ó+B <ÓÛ×Û¨¹^EÆ”ðtdû)}æIqÂISJÅŽ¿®]Ëõ%(c{”e6¨àÏy)ÃÞ8Þ´þ- G…«r£µ±<+ï7}}Áƒ½"V/q\°ŒM8+*û3ßù3Äx£8Z,ŸöÓ}"XX¸¤ìÆÉéO§JÊìÂvmCÀŠøðúÞ—G¸ãPÈŠ›«dk«+¶{8î³û]~¶T±e„uùl0ˆ6+sgÔtuy“B¤>奫S'÷BŸ.›Q0ì ë•?úÅ(là8H¦à¸Øº«§Wnáé(Ã'ãxÞéO»q¹Ý=ú!ŸŽ"gByl…Ek®àÃͽqqè¿¥:J(ö¥ƒƒ€.HÆÃ‡qñ¥ÉònÖS%h4é«¡ ›ó)ß”±Ž+p0†‡ IÒm¡ÜºÞ…TïcgØ¢· Ê.SR¸Ðr6{ñXa~²„Ÿx49T§¹M'åR|çÛPtÿ¬à7“1*ÙBÁŸZŠì®í"ÏËíiýØw£Ó/Ò®Þavš5 êTäŸ2¢Üîw»Ûk¼‹p–uaœC„(Ž÷‚öík>‡”S´(fB«âÊéná‹Öj÷%¢!ö½ Ûø £\7cøIùÌäÐ…«Ûk™CaÿúXåkk˜h‹T­Ó˜?wÌ'¾3™ŽÒ%ÓÜo9¥b_ûX˜ÂÛK™G¾¾­‚ðVˆ“/Wü ID÷Wx{²ùõŊΡòìÇ vÞ­u@ˆ;Ê«¦:•ã7Ɍ͗ å¡iÜP…Ï¿9 HQqrDgcÒ>mCžŸP3D&=!ÞïfÐV=‰òwT,É„$J°bA‹SM¡Õ'åêP[_FFd»º)"Q£‹Œ°=ã-Fx š¹¹"Iw<Ù"×»É.y†‡uüù‡Ÿ‡`úÙ–©^$æZÏVÔAúÂ_HêBöWâÕàð î^Ó—¿|ígÏîÁõILLPªY±¨ÄÁ£~ˆ¿«¸ñË|øb "¨Ø¤žãëi‹éÇ‹ óTBz®~^(ÒÁDSI&€/ÑÁ×ÙHpFl*J_9ÃÅ_`/©’öûCÄîfO޹ñõlzuÙasc{À‚ ÆpÉ(9¸¶iظ‘'yn»pø-¯]xVôèO3®Ç™"5>9ÅÏ ;ëIØŒY9îLßzmCÕ:K64åÆž0ŸÜššw“MëÕ[­R]…íB«½õn›]”´!èíR‰ÄååÂ,"7ì%³:¯-ÉýÖ”¾Ÿ±#?Aq¾¦‰dg‚Ò4¦°ßãʳ}.@¿Ã0ºl½v°¾,êÍQߊ÷Û’ü±^?_ \ýåXælSh:ŒmDóúH]ýö¤ÿžŸwÂÕŸ!r䇱ßÈù!‚ÛÉ×- È㱞ç¾ rÜ öŒ‹Òa‰§BJc¾GÉK ÏaQ ”•‡ŸÐ³ø‰{´}y4*·-ÑÍc¹¸0Ýã“ÛG˜£ê‚"Ef|WggñÍ<†y8eKZ-`X¿Ó¡×Ý@=].zxœzw|ªÈßÙÀìÀIôß «εi"/6{z×K›ÎܬFP(R©ì`gz÷þ ÔG«|àIzþVL."£ÔF³½F¸çO·`å³m ²tÂ=éŸP̲ò¤£@”«»ùjÆÝ•·cŠ¥˜¾…„<­¼hù»C¶ßÑÝöÜçd'Ý„å GnË  ÉÑ×­ÈRg¢íÕ^·Ÿp@í‘{ݵ;ã"ó3ô´£ùlY1Y€êâ;lÊÉê¡H%K1Û×­îøø³?Ò¢³y¯2ˆ[!X­LèÅ@ 8âV/~¬ñ'·/Õ€Htüúò™’ ùB·A]±àqÄøxóâ°ÃöLƒ˜ùôZ‡Fn¨Ó‰é‚ñÔß“¡‘r’¿Í"5<#ÔQo/_UÔ|å¯i2äùEÌ„\2ý¾hNÉÆ;.ˆ™±Pe4¤m'Ô¾Ï?ÛJ©Åã赆Nê*úø³—ÍV(”‘…DºlÓªsV5Ù0#³Ž«ö¬¢ùWì!²âæÜ¯f½Y.^ç^ïÖ*;Weõ'Á¬žzLƒÀIb¢ld首B.ÄqF ®¸öADuÆQyì7Ô“X*•HDÅ&f=ªÖê t<1|k s F’Úìù¬t“` ¹r¢É ýa©I897q…p•Oô ÔÔLòÉšÅwpõCÀW­¾õý:³ÕélãëVêñ¹<´r‰è4ªòѹ†.ëe'?Rø÷M`øM>daäI‘×€3QàÃ'¦tÛI Ë÷l8mó$x„s­Œ,pŸïУ’ž â}ðå¡òÀ%‚Û*ÜB55¹àDb57ÔÒ4K(<̼I¶bEP§Š? ­«eç PÌý5GŒª¹“¼ªáU÷=á)¸#NBBõòt7dl"Ir½¯/2ñzû¥7ÜÉJ œÈWkÒ‘3b+ð Ö‡FŸNé |ÎÇT)·c2J›7ÊG\Jþ½nj‡¾•^Z„Ùù¼>Ý–5 D% +Z;7§zT7‡/)lEº«A¸Eõ$‡øÏ¬ ài¶¥@:hÆÌn¦?*?f,=/¿Ý¬˜¯Äø@~kÜ$ÈpÂ{¹ù3ã*‚aÃ* ƒÜÖ-ˆ’…ëÕ‘ܾáÑû…/@~”‰‹âbâ: —ìGV%tˆv^••Òº›«MBÝ©xŸÓ%ãð¡”æCßúŠÂªs-#Ë”beòítãvÊÍ{êÆÝÔœŸ,ã `ÿÜN%¿Ú1Fþ^‚L7Ž&[4Ÿã.UɪxR3gŸ:©+Yë(ʶçnh£ïzîL~—Têš§Ê÷§Ï´½Á„»ê¨w•jPg¡_4oM“øáÏm=).ŠÌ‹Èõ,bµy%øh]Ÿ3S5Øc(ŠQE}ÞY¾Óùb›ï„;m šhRP´ßM¶.‚à²n{¦aÛºp«‡ÊTìÈz–®L>ûï¼Ää•ïAêDmšV w0Ý*ǽZ'/ÑÑåÄG©b¾n&g¨®Ì,m®ñx{.£H ûû½þ*Õfõ«ä£ôúÓDîpÖ~M5sJ¿Ò\ßýcÐC§Î@ƒFŽy0Ä.£1¢šIIèì…ñ±\ y:Ç8ÙŸx#¶Á Õì5Vœ¤›d ãó~g)ðc5JÎÑBpVUr*;ïýÔóÓ,ƒÇ¾ Ö»ÉFÿfÐý²p_æfδj@—_ùSíËgè=[!$“UÄ£š0R =·˜Šõ¦JçݪQ»å%XwzŽ´òÓ{¦,[xHß’ÃwßõfãßV#§Ü:—ZEQLv‰)j-y­Œ}“¢ Ïæñãëݸ°"S¹ Øw+Ò2 [éu„Š¹Ï º,©y/¡ˆ®ü¥¿,\o³MÐý²‚ÍOY -4³'çt³yˆ/m›‹m÷§]Š€bZ¡V ¾¡<¾”¹ÙTžŽe¢3§L§ú®É Ö9ë²óÅçvæ~GŠF²ÔÿšÓî{o*´àÿ¢SþËËÁ²ýÈ”š—‚9 &6¿âPàè;Ý!´²ÎVÀÃÙÊ^Ö$˜Žñåzáç°Á+…RŠZ ­7ïyaÌý;&˜¤îØEŒ‡HHê‹dÃwu ®`f‚'±ÕYYöKTåOSýܿɪÑt@Êv¿ÓÈ ËhoõÏã3RmòæJºGÍP¢xs%ué_c7:–üDé.”‚ê¥û”â–ß )©¿k<ô:ßðÔÛȯîä jÑk#- è¶Giíýfӈѷ7»ìâö ‘Jù2Õ“jŸfjaÜìtBFû½ê|²yß| ‰ž_é.eÐ8–t"j&,‹Ý÷O … ·Ç¿ž|Ap(ûkÄÖÉ–¶DI³Y’+•Íe@É5Ù–Õ÷ôéa[Âþ˜{KÓVžŠû¯{lDhYÃrwäáíÉ7jÊ·ŒJÃr5›¦31¬nò®TŠŽÇ PIÇlvÓ  œðkáX~fÀK+„–oã$“ ¼Ñ_»æÜ9û‹Ã7ŠTrŒFâ—'áS©FÖK˜%ŤýÚ‘…¨~ê©y‰ëøS<‘q¨È „/Gzžä4Áð€ZÏT´QA² ÂñÇòò‰`@hÔX0€JʼZ¢ŸÛoyXýƒcc[Z߃A g1Ä׿¯·z™ô[“Ä¢3$¹Ò4¸±Úè+T•q@ðà…+¾¾A¾&1ÕÆÂ2úžà Qµ¦äg.D[È1ùÌSë~Û7¹RÕRXˆsŒ~3ÜŒ ù“Ù¸¾Êã6¼F½ô@õˆè²œîÜŒøPŽž(á¶9W’©Í‹{L…ffüoµblýŽïGÕd Ù˜z¤õåIQÁ7)x4)`ðe­ß†ÓØû®c›_¹Z£e:×®œû"šáÙq=™{\,}¨÷[÷\Ój{RÙ;Ý¥HHÉ-êø‚j‹}…6WšN\ïWZÑ\¼‚ŸcPeÜ3ÒÊ¢óÙ°ªÚ0´Aœ°tyP'Ú:4¡¢+Š[ŒS(¥Tc‘bm`tJqzú::ÚÞˆ–ýV"¶2—Ê:¥€AØ^°ÍøüýÔñæþ`ä¡»V %¡ü@ãgÂÐbQSÅR$]ÓARázÃ2\ ø2³ZÍ“óM8-7i=3ßHð™GšSD3xŠß¹‡ËùZ ®‚ì^`Ä6à1à–‘ cdòAxðe8ýÄBó[™Ê\';ѯ°¯åW“¹ì(Ûîr†XÂó#X³ÈqÆó{Å©ié¼² P´9_¼_¿Zp"5Ô©¼7æ¢ã¤«ÝRzk¶ˆÌ”ÛVf™ÖŒþÌX;xΰ–Å~A\í²j¢4»ÞŒ8z§8É^^¨ˆÂ]v±»›²?³¿,z ™à N•d´_Àµ­4IµÈÊWÙ$ȯȾii%˜®!÷üÍtmÿjlº‹fâ|¨Ž«Ù”³ýéL$Šƒ€YPúò"rº\[á¨e4ó8¶—¬È%dWˆ18 \²ÜhNÕ(Kï[ûNà˜<ÃÔPâ¢æÚVí¬mD Ký8c8&©v5’û´òm¤â¥X ¦ ]QžðI÷vL žÆ)µä¸Æþ„Êȼ#f ¡Ñ]õgr†÷mƒØDŸ¿·:Žò{"Ϭ7fŽÐõ^«„¿ÿ Ñ‹³È/”†ó‡Ûf¯1FJ½ËJÌGÅiæ$qÞ$Ї-HvÈ”¸êçegÓ”sa¿ ”\¨Wl<áF@)1?æ«Iz Ký'/U¼r¢=¯ 0iõçÚëçë?_ý>¤—xöœún¥þ‘©SoÊYæ#¼¦ »ÆÍ= ¬V‡“dvnñá|[@CË#çÉR •– éʆùÍ"Pµ~`Ѧʱ1“„­É›·, $¨p›¦¤¯”æTæèñx÷Éê—3ú™d¨@ö«©_¼Êã<ì Yљ߼d¨9™r±ÓÓÂVÞ‹ªPùÔʺy¾“ô?ùp±£úàú‰q!š>Ë猯JÐU½!xßóìâàS±¾1Úƒ—ÊñöÌY”m‹ó)êê²S‚VÍÂ!³ IáÝHá ( pY+çJu`‘ºN„˜0—JðY™·ß''uÉyì_&]vmÆXE¹`!GÕ•p¸/€¢Ú`µü®~ã÷]ßÔ.Tö‰Ob :í±\ƒg­åϬB¯ÕÐÒ~”á"\Oºž¦Ùæúñg©ì#0§Ö@<ó‡nã„‘ˆ$ªÅ[0ë›.T/6‡  ØžCº(ñQ„~BSÉÙƒœJ8̘7o+ºø’¬*KË þ°og"èÒ2‡ýrsÍ ÛÔž÷kzY˜ºbеÈGļÙj¶¹‡ˆÐ½ŸÌ‘ԆþY¬Dmhâ’oÍT5/°N1Qib±)”´Vßqòš¥NþÒ±:=x bºßƘ~ŸœË¤:Ûò~äÓ 'ïV!v1ù¢«MÕ©C€Y¿ù5ùú¸ >8 \ ´])^Væ‚yÄÛ4"xnEeï—î‘Pˆø°Q„ðG’ÈØáÂAm:j6)ÅfPõ3ÝPŒç“Í%óo®q‡e³…²·€L †lRw¬.€ð…"®$ɪeÄ… Ž†IL±‡Þ¶7[…¶žŒ©w€¥&i/ëõ#J-‹1%sÇgæynÊl;,°Äò”twúZëÉê”$~zø*ªS±A*p4ÕHl4ÇZ+6ñ¯L3 b/µ7ö_ø‡ ‡}e,BŽJ\ücÞ-;±|A…jÊU*¯@ª—L#ÍÉ‚ñãO©ÇƒC8 T1¹Nd" EcIRþB2#‹„¼6óAMûåezJaü&ä¨Ú(a8£R³ŠOÃâûØ„ nH»×}H ¥wÞÕDºyvU+t’/a};x.‡ŠuÑöv;]qEè*¥†^VQ[­ WNl‰ ³h‚Ï9šb¤s]Á# _&xxßõ:¦Í æý@ê,›Á¹©Ñ·&@Ë·5WjÄ‘æà š¾ªÛaaõx·QóãhñÒy|Ö 'ƒÔ0$;‹÷^ƒ°Ç·úýwé—Pƒ˜}fC?Ú:K¸…’pyëÀøKßpB Áx åœ0{Æ^õæ­i-)2º´û䜠«R ¹,ÔâóGUÖ¦ÛæEá3,ºÔüŸIRhHïçOg×á/UA»ŸÒ!Êü.•‰ðx‡:jaðV¥¦C ÄòaÈ,¨ЈŽåf³Ïêá35ßéžç£NC<¥ô&¥çÁþ´'õT¤6Vé»dÏÙÄ‚.`õ`Ð÷º †­ÆVÖ«6 Oùê i/±)SMmíÓ^ò~¤èŠI•mxo`ö|Ú¤˜¨QÔ‹Çž ŸÚÒ!ykú:‰:Ÿ2dR,.†Õ14w‰(Š˜?„ás«ÓÜø–cU9ÌêšõNÉŠa›Éô=ÓVv„ƒÒæMäy«ûúKc;íËþCÒ(x€ÜŽ'¯ïÎçÁ!…“Z¬×\«î!Zz¥Üž‡LpŠ6šô»QϪÌvýŒ•ÜÊn†…níÁè‡Mc(»x× æ0,éd‰,g…Ž6CñônÒ‹ãý:¬‹@”y<UýºZT4ñ)ÏÎ×EÍ22ÆjØ€åbŽð¸ÅΜåû‰ç ñßãõ6p¦@^vŽçßüºK­ š­Ç~™V¡CW‚C‡! C°jæ^E1¼!Ñ.¦„9•ÍúÀÁæs%Á°¨]m+Æz ™³ÑùÐÛ»é«ñÄðœ.â…(s̆)Ã0 jÐJr€Oކ–öš©::AÇŒ\Œ¶¥ÓÜÖ_‡–tW #È2¯Ø9Y/9¶Á» aΔëËMtQ%á ðµUŠõÈð6oæöE eÄÏm²¦k‹,õdÑià8-üò‚>.Ø–ÀÉþu1–‚¼g_ÏQ~É-¥º¡ô,Å-0…¤ú9óÖ»8gz¶2cžÅüzOÅÀéÌPÍŸ‘¾ýKÖè C×»¡vt×ÏOs2òDnÞüáC@œ´K*\ØåÙ¶=J9 £…ñºK‹‘§b“ȨHV†èv$èAäe§n¤Æ1æZCeáÊŸ¥²6R‚M|æ“çŒNvÆm¨7ÏÈÁç6fŽÌB©áYž—^´àTb4Äaa]ú²6DÛ}yp‡w’?iÔ4bSf?Õ_JzpäÁç9®ñ]±j\j,yJ ZÑÁ4·d6zųrm§ž‚m'öSÞ†*dÛí`šf[(²šG!xËî;@ËŸ=~8Æ¡i8…×”+=bùñçí)<1çù;Kš´ŸÏ©£‚BoƒT@ßoÄå,aÙ×»ìmr;Óãn"SÖÒšOû%%~ÝÅžSþ‚A7{¸”dâ%Þ–û$ZzP¡]‡Ü#äi¾óó•,=F<Å?ÄXq’“ST↯|®D¢ÆÃ¿î*øñ°ï“én—mêì,Ks:^Ùnvö÷±òQÔg>¦KÛvû/x#P?9@ë¥2+~÷ Ê3欧k¶wmDö²ÛéVÎŒ:ƒä¤ùçÍô$rL]iÆê=y+Ç"÷üNà*ëðÉ3Ä3“k®±|UUg»¿TCæÞ^õ{Kæ´oLòt~xæÁÎ)Ò2ªRí}Ë×ÞlU3Õòuö[…KN?*@á\d~k0ßâÆäFCEæE`›èL«4ü††½ãx¶*zŸ’•è1ÏÕ»û.¬¯Â·ýùw½¦ ~]&µQ_©“Wµ9ø ¢7ëI®¬­Òæj‡Œ·“æÂWJ†°V]\†G|KºÙ y¾-7È„AxóЊRF£'3š3ˆ¨ófê†ÈKãõ"Y…s5í è¢Ì±9'}\ýE‡»—øé’•œÕ|FéÝÏñuD›ž²]ä=¨O&[§ŠÂß)NyƒÎ~ 4CÚö´4Ó©ØÝE†‡J ã±G;Ó|5Z® -ÏVäaþÍ9€) Ojq·)؆/®hž8î~e_;Ò}›C_3¤é«ÜC(rCÄÇT$ÆJQTÃ]áƒ8[:ùsÍ'2Ö0=*Þÿó¢‹2¿mn4Ø8Ɨݸ›Ø*y 蟙›–Ó“„½dp¨~œúŽå:Åñ¼$5éš"Ý_›’!°óU«¡Ctùù©zÌ?s;àØ ó'{ʵ™Ìþ(qcÑ›T˜›wÙ¶¦ è@pH…O'dó3\étxѲ!”RîDgó±ÁÑi—ø‰-”î>‹9s^‰U‘½ …‘XOöÒ'³Y˜F¹lúœ£G²|œLôò¹Ù†;gW™µ ípzá6ùØHÝo,RÎešmÜÚÍð?àR¨›h0´d>èDÙãÅÝüñÛÖe~Ù ê{qÝÚŸ:[.Ü·Ô¾Cßh&Wž“£}§ˆ¡fP| Ë•ê (Ú"-üAK‹X—¥V>òFÓÄg/_‡ҾXBEŽ"3[2 :R`7`ù£ É‹Cn¼YPQñŸ_š(S*øö‹ì¤øâë G… ²Xd¹òSR2h_Ð’:ƒ«?¡ŸåJú¬/SáçÎ~%ôŒ“/Ÿ¸Ñð¤·Õ©MÓ“],îÅ–]O+ÑðÈŽ]ÿ,G«_s4H4µ9FÍ.Ýô“¦ÐjzÁþhLAñÂ][ç]+´sÀZžÏp¸i¥r3jšãëk(´%͉ã~UÞàP,õbwAíÊR¬v=uAÉÉ¢!Ý„|<íJ¾•ÜEm[#g±¸Aì©ßdF´òÈL;"S?3! ¦hèúiŧMJŸpÄ]Ì–³¡ER*tÜ_‹×~„¶…sÒW¥õt \y˜KÂZ¬|?ÎﱡZç e*¾l8I•šŽSŠÖveº}ÌÚ—TÁpl½C;“Ò—û~Î:ï5â.@ _L™²!wç¾DYÏü‹¨ôÎ’+Ä14«RŸÙçç&f}ñøôméÇ¿‚&·Æ(¬†ÿuï)&n÷‹›Ñ9­ÏÑ«º•·Ã ^f\bP‹:#ÐõsdrGÐò}ê!£÷åRàF„)¨ÑüËMÄî2æ§¡1-Œ7eD×áÔ§Þ*±ehß„í~nê«"G` _’™X–©~“©byD’Ãì0µd|¿'ƒ8HnÌPŠì6XP9‘î°Dðòø¿ÌHgBê0€fòñ)Œ$©èç¯ì¾ÈMWgÏäXŒÃ¾ÇÂ1‹.íGÚ­ß,e}ö`»Ýí,3gSÍ2¥Å…º´N‹È­Ù6‚3B’5.‹Û­Ê€øLÜÌ™P]àî`|‰5·))æ´O ™Þ*ízG.{¬vkØR–q@I7[ÜÑ¿¢«%°†Õ´º?àÇ›Iè@ɸö>¸°Œý–r;¨gCC¦&ùºT´OéIšnË#*ÂÍ7ºÙ3ð°êÔªc°O!¼LeÞßáßÀ¨ðU«iF š¥³š7ç‡Z‘ }úWkÔªÎ>oƒ}ÜHã(Íq¬d‰ï<–IúÖÝðÍ&µØ÷EW§ðÚ‰T!:ö90·ã™×MÜ¿™¶/ Ì=ÄW~ðû±Ôј °bø«õ«VÚ÷-‘¿ÁSʰ7r…—¤ F-°½Õ»Œ5’qÿþ™?Z*ãi6N:KÏNçÃî!„I„|ŽÍ6†á~læ_¢d…⟌3ëã3¯-]NÇ”’Ǻ‰]êba}Ø­d³µ#gt©é#}/ñ›Œú,‚ÚVD¶ºtPÇ8!s…»äL„N÷‚E™X/,ÌÇE·Î¤EÜi¢u‚˜ •œ( °ð‚ÅÞ­¼.“…žÇ•‚a³bî˜]t$ ˆBãå‘M]>¿ö†±ÓP¨‡Â$ê7(,;¾ ³luo$mלFGiÕéf‡ÜÛ³€z-˜õ¥È5dê–”e%ÝÁ,w#…,\¢üôÀÓ%AÀ:MRÙC¸üV·ÔO8w)hG¤¾¡ö-Í·ï²ßˆã;Ó”šŽu\[òe+òÊ;òåÒÔI˜Ðm‰š¯Õ#q¹µT=É™æBfŹY¸íü›ZJFCUüyoõ3¦ºÅ:È}mž¾?Ôa–qZNëÄ”žêuánüÚù™ž@ ÕM"ª–„þÍfé t÷ä$W•Uj5äÛ?zãÄœuU”Rþ'ù|½—xöôîTêÒ¼°v—7?OA/{®„ê(Ì&ˆ;çTuÈAO®#_]yýFý3Ál§M9 e¶ˆ¹’ |gá€8Âðc ‡Ötœº5ó ‚µ(’Rp€ãàÃ¥t¬¬–ã͝ÀpÁÓ{ÝÛDʳ]/tJ—×íSPŒ p÷òA}·É÷¾Êžyn•O"õzÐIõ¾d5JFKîè[Dݘ`fä†ÁŸC½À{ï¦à>‘›<Ï–¾ y­4Q·‡JÎ…RBD‘öãÞm—T ÎWo5bj"#e–,vRä ܾvœÒ$C%<ìWõBÜÚqb³Pu<†ûÚ;h'¿Õæ|¯u-4em]¹õ…è7™*Ø|»A2%Š·Q?÷QzÞJØ,VÎf÷ðÑ™/7Å’Êی 0͉vÛXå®FqÖg²Ê¿nÝÇDÔ‹)¥ ü8‡Ð®­”ÑO'vl³”î0…É‚dL“¥úlßCfj6DSßi¦Í¬JñF7øÅ,÷t"x ³¼¸óügãØxxF¾Î ­é&uû$Øôxs=P³´DD Üž?Võ: /!”6x~é7Ü'ûrwWŸZdhÿI`—?º^}mÕfO÷¾îÁ£ª‡ðC“ö2?ª*€\eGˆJ`f>¡ß)dqFƒ‘«ºüb—Å“úÁ)‰ìS:ÄèâvtdË“T°ðW¦úÅÊÂ…¹4÷RM|×àæ=©Ã‚&ÌÂ^ù ´‡,©9°>õ:[œƒB{¥?¿‘qªªÃø«ZÈ'U>b…<Àð“IšUŸz¹4„EJ ê>Ã'hm¥°úwXŠj|·*µ– ':Ÿ¯ëFãšwÛ¯ö£`FÐâëK_ÇÛÛñ¢v6\íuC‰¯N(îžnè8hƒ‘êL×þša?õñ•ÛK/ï:2ãü2å!}Y*åª$Ó!æ}8?UÚj/¯®ûþ›Ãßspìjˆét1æÓòwi†r¹6v! IL¦¨ÛWËKA›V‰Ù­_7ëk¼"Âb³¡’Iœ”a¸Û¡]Øôl$'e ˜Tí¹þå '[KoÌ9ÃþkàVÎE?›Àé=TßvÕjš<¡¿é… R¯«½áØår§)¹Øk/ ™`¬Æ_ûr²È0ñb<à¦)Po©JFkÔþ|¢ã!-VÓ^·E.ÂA¦½Žû•¾Õ‰’iLúnù¹–]Ķ‹2´‡×Î ùöåÆÐ§}]ÖÏ’{D‡ŽÔ»ýyŽ["6Á\¿™"JA«Ð ³šÚ-¶ã Ã%tt§“ û›£¥IúL¼BREÚC©AF¨;XEIbøöuU3š»å¯çïj‡Ì  /¹ÁiRÆêL¢²IKÅ"!F[<ñ» ÜŸ…ÀZ_•¤Ð÷cïôrÊt¤·E»Ø/ÆTš2_#‡$XÖ+Ó‹—ò†oöl3ÜãëTް¨evM+v©£‰”›`NŸArúÔ7²M «&QÐÚG å}Aµ“w>UÆÊ©hº[?(½ÖF8 ¸ðù ÂÛbrîV=@rññ[V[Gz÷žÙ*õÛT²4Ùï?É’Œý_ñK`Ô¦æñù¦˜H[º=«RT¢…t²ðÐÛ…áðbÌÈç "2ÕÆDÜ!È Áqް&âõGNã. ý1OVwÝ7Ï•ÕC–…$ó†Ã™3ö=¹•ç㸠µ¦mJ6‡±õdÞ,)ðõXȰ*X¥?](2˜`9Ú.sò¨›h‰{àYÃuU~µYí_y»”ÈéàéýJ‚¾Rd.®y±šè†žH±èñÑìa&^­hÁ*¯ûÌ¡·QRd@¸X„ÍîÌÆ–XÔ¥Â(ýÒ¨KÿzèÉ#ŽróB+î»kÅp},­ÒªRNlÊ·ÈP¦Õ@ð,IðêifˆäQNíoÇuH÷`.í‰ö6Ž<ì.h‡úç}ìnw¼s‘ÔL@טcçÁ©…”ß÷ J‡Þ׎¢$0˜*¸8É4´;u²žÒËSý/õPTÉáʯ­|yôH¥ ÎfìYA’[Û^­´£ãi^Fxx­ÎéVÅ'Ö+þZN(ghGÆýJJh8‰p. ×Þ“õ®ô$Å»ü–wžÀgÉbï#¥KÖ,bºÕ•Ë,KÈvó/ªaº‚•VJ5ú—¢MžX/Ím!¦¸nýˆ- IrëÆß> stream xÚ¬¹ctem·&ÛvvlÛ¶mgǪ8Û6*VÅNŪØIŶmõ¼oŸ>=Î×ý§ûüØc¬{⚸æšc­µ)H”ÕDÌM’Ž® ,ŒÌ¼Ek{S7UG{EGyU ¥௜Ž‚BÌhâjíè nâ ähÍâ@3++€…‡‡Ž æèäålmiå  ÖPÕ¢¡££ÿOÉ?&S¯ÿÐüõt±¶tPþ½pÚ9:Ù\ÿBü_;ªW+ ÀÂÚSRÖ‘Q”PK)j¤€@g;€²›©µ@ÞÚ èà¤X8:ìþ}˜9:˜[ÿSš ã_,€ ÀÅ hfý× èitúGEp:Û[»¸ü½X»,M\ÿöÀÕ`í`fçfþOåŽÿJÈÉÙñ¯…ý_Ý_0eGW3gk'WÀߨÊâ’ÿÎÓÕÊÄõŸØ.ÖÕG‹¿–æŽfnÿ”ô/Ý_˜¿ZWk€+ÐÓõŸX¦@€¹µ‹“‰×ߨÁœœ­ÿ•†›‹µƒåf@pZš8›Û]\þÂüÅþ§;ÿY'à©ÞÄÉÉÎë_ÞŽÿ²úŸ9X»ºí,áXXÿÆ4sýÛÒÚŽéŸY‘q°p°0ÿ[nîæô:w ó¿DýÏÌÐüMÂÄÜÑÁÎ `´€cRttý@ýÇ2ãÉÿ ÿ·üßBïÿ¹ÿ•£ÿå&þ½Ÿÿ+´¤›¢‰ýßø÷Žü]2&€¿{ øgÑØ™8ÿÿ|Lì­í¼þO^ÿÕZ øïtÿ`2®&Û"â`ù—fFæ ­]$­=æÊÖ®fV »¿=û—\ÃÁèlgíüËí¿Ú ``afþ/:u+k3[‡Hàø· è`þ_+øK׿òg’WWUÑ¢ûß,Ø*ÿWu/§¿¹ýjÍÿçáQQGO€7 '7€•›åïý÷7!VvßÿMȱüçYÁÄÕÙÚ ÷·nf–Uÿ?~ÿy2ø/0fŽæÿŒŽš«‰ƒùßiûŸ‚ÔfnÎÎIþ×ø[õœÿ5÷@ 'Ð neÑÑŒ/Ä&#;Óµ;ohB\¯¿—|(Ô©¬Q½¸0 Æ±Ç?#b›§Òø½6”±iŠ÷³ÍkáÔéc_–ö`¤ËŽª' xY@àKFÓWˆºAÙÁEwÄdX†˜y¦ã}õG~ B—“Yó`gBEÕ°ôŠpªƒÍæê‰&€Ì½0ƒüÑ ÉÏ,½!³¥ ­®èôŒ2ùøé‘ê÷èðÐ`Ï dß>>]n<,Ÿ ¶_ê)IŠ«—±ó}£Ù'ä«;—KÕBN«V j²†Çwü·E7bò‡¸mt–Ì 6"Ë/Ð=fáEÓx9Ëð0ø8Öâ$Azâ1±iuYÃúÎE™³eÎÕóAÞ Ûìež8køÃ¦èE© ²bŽÍOTMjaéß²uÃÍ¥5™¹Q2Ut4£¦¹Øëñ„($‘¢…ëF+Rv„Kb ;\}‰`ºAªÕ3êœ)3 Xƒ3IJzDÝãgÖ± £=‹y„~UýÉ'´Ë–¶Ñ„%Z1iS57´ -”Ñ×…Zë!w¹GÁöŠŽ*½aßDÌ#“Gqçs—jØÚ£×Õ!Á„8/d<}Ôß$WºãÕ8¤#Ý}R.+§˜ïÇžª{öôÇ´v°©‰^/úX»?§]4-»'Šs7…0ðxÅŽµKé.¤Q6†æe‹47X‡&; ú`ÄdÉlw"[£ ÛàëÐÆÑ³hx.ˆ’°‹7]Þñ—Ÿ\‡{ÓôK©ôXÏosЦ¤pÚƒõqwÏ^HÈÏ«Æ$Ûë"ZøqëmöNÅÖ™-ÑwjÌtZŸv‡ÊYKK°*6µ1«!ÔJƒEWŸìRi–Åÿé™çî©n»ù(Ÿ£2Њá“ó¡ë©–2'«Ôô—n(‘ÿ!^ÍabVnêYòèîì„ÁòP¨Ì&¢ há¹×FG¾¹(Öz®&E‡Œb³5WÅ1 ÉÝU†3ÏW\õƒøU{ñ˜¤Ä_ý"¾ÉîÀæbäàiž#âu¿f)ØgC+x®Rl‚Âüµó§¯@ÂA°tTÑ ÷D>Tÿÿ×øaøíîϼå0Ý?Šm4bHóY½†²úÜŒX |<Ž'æ,äëÚþ›°óË–'W›2ýÁâlurŧ“GóO½?4uÍѪ˜ßã»#H~‚ã(keƒM}šèÇùš”ù¹ l4Ò†€~o9šm¦ŽƒŽÃ.9ÃoÅ„ 0M·Wo>T\Ä O‡Âí¾nIð4…zô j7î—ïôKï…µ>­f»nSÑÚi5/˜æö(ё۶à)µä àÜê›QPÉTy1ÿ¨º0$*oët Èq±Ka OjDØt)hœ±+z §ä2 eG—cð¨"á ­DÔÒ‚’«Gƒø¥… ]n—Å Ú:Bº1ðõçVõÜIÕëòÀ•ÚÅû0°)&|0ô¥jÂÓyëäœ#žˆ"ùkÆÆËÚƒ‰rùÈÌtc¼|»lf×PÀ(¸)žñϲVXßnŒšt·¢iø[—wã»öuæl/Á.±€ç&Ìd¾Ënáö‹o¥}°ƒÇ~RH¯½^/YíŽÐìYΛ3¦m ¨ƒ€LÿÂJÉÈR¡r¦»î‘õÃO;¡yƤPù “}4B«7uòÊ —‘'–L®ŸðïZõ%cx¨ƒ&’¡|—’Ù0h(=_øÉ€Åçg—£ü!èg8ù”±-UøòE÷`u†>ŸÝKf¨mÍÀžüÎ Ì[šáYØeøhçRN]Ù‰2âßÍ’ËŽoöšß¯,ëÑÐh§9E!¼Õ;Ýgôј15ìI{Ö2Ñ"—Æ? o`¯Ý_¯Õ8T6ècè6Æ£Œ’É2àW­ÉÂnÍÊô‰)ÚrF¶…Ð…`Ïœ K(¥ L³ÊjØo|‡…]øÏpø“g,·ÖŠ:%1QšÄ|ÌXiøÏ§Ñ¹·Àågä䌜a×*7ŸÒµBà*ؘY]\£nkW`ô9Æyôl_ʣ敖Ý=\ÕÿPJÊmÂ]aC¤¾GÆWDcÿ!'9ÁDîävKÆÉ?qüôÑl옦b>åO 9Lrõ ³¤.lëIjKæÊh…mĨ×<·ÏÊNùsö§…N¼aA&ÙøØñuÍûˆöÏ<ÞÃeM:¿{ÍfƒÞ¨¼àUmxéë"`o Wm„4d4ÅÚÛ…·Ëjñ˜­ïpñ!À¢tb<ÁY¸ŸðêFs¶¼…]ZÏõµFšÅu8<+IMÎÎQ!—› ù:1”÷1Ý÷€ åíFØIóýõŒø¥&ÿg“í¯ l؉CãkµÒÐ"š0_—ÄÔýUìPë½u0~xÏ °°.[§…ÅÒF±!œƒc([4Ô¬GМŸØïíL¼öQÃB¾Ñ¼Î(‚±ËDð4ÈR–ZWå¶Ý›P㪑CÑi0uG20$—å ƒäq¸ë'èÂi׬m’ª¿X{å*ºaÈb{îp#ê#ñ›†œú ,Œ/7ŽknfÞýú?Ã'Y"{ÜO•šÕ²-h² */è¹m‚$­íIÄmvªÄ¾ÿ/‰hÜŸ#*í¦\¸¡¯•ÐúÕ<$ …ikË€ggJ˜ РWØ( ô1Þb[äŽ<÷x61¾‚ë3ª6ž¹F‘.Bؼqù…&¯2ÌLYߺìˆü“À¾aúµÌø“Ç bÿâ0þMð38´â'`…`·bÖ–|¦ÅiçC Gõ}çˆhËפDùõ׋ë^§rŠŒÀ¨d! œw“À©B`üz¯«\ýíµ†yC’à0ïûó¯ý¶~O-Åu4÷ y›¾_9Šã‘]4`ÊÝvâS/=Q–Áè…Í×Ù¶TÞÆ€•3?×Ò¡Ó$8©¹ÃÐa‹’Ú†`¢t8t½åÒgì¡G¬#“QÉRégK—ƒ¤\üú?}”¬p¿½bd! @ÒE ˆ‹ÇzYh쇧“õ’BjÁõõ4Å!˜“n·€/§³Uëlpá¦)[7·ØßsŒÈ¥z ÈEªÏ®G„ˆõ*ÕJ†·ž([œÿÂ}n’ë ëÆÕ k»Ý?ÍŽœBá"ÏFùc%†çtµ- Ñ7/ ¶á]â4&/ÍÀ3œ‘rrûhÑF¿á‹ú#šÉ­wó+ù$‚Üé5v#´YPÞÉ—³ãÙ¶t›“„:]C [|âY ¾h $röEZÁRw“¾Üø½K«Úu6yïkìäÑ!zB Ñé ôto‚^«9š£&O*I󔵕!ÉmÑòÚeI ÕÖ1’fqöãU1kWUáðIj^ôÌ·|HâªnA7¬Ã´+fw¦Œ µÛF•!;ôiìDý”Ls2³ìxîÎP YDlF؈Ôïy˜á,œHͰ·¨v*«+FñùkÇÍÃÖñÉPìñj÷R{ƒäÉ>{-YºB^ÐהݠQ%;´+¹Az²¼óûHT0ßž}àcsè#¸Ðïu4‡Ã*d¸¯?7“ ‰Ò•zqZ\AW4±ívõn±j>U µéR7" !,<¡w2Ç ¿0 *#è?YÕR4Yj!†­o× -ÁN%ntµ’€$bÄ=D8Œã@Ø!œÂz£X'@Ù6uÖùbàüñÌAŠ—Â+|íEíš[ãs,|†ÔÈ˘`ö‡t»ß‘™õÉ–ø%¹ȃ õ»i*ô:¹I’ÇŽÛDõÉÍP»›J”³é÷ȹ¶²0`@¹ž6> iã4{C\تž3öÊnãCÚúÒ•z)Ó#m2í³^ŽhOÁ–/£è[c(,)ع1±¾Éu ¯²È0›¤¸z•a¢J³~nõíC¶"–íÚæmj¯${[-ª[íÒþ†Œ<>_»°º×CÂÍ·Ï¥dòÑC“ŒAöFMÆx' Àn_ju© ×ÑEˆw˜rŠy¨_0EU5‡ h”o¸OÐ#­´ ácî¡ Œ"¬{ÜØÜädV]©\†Vªæyv¹Ì :'ËáJÞbûˆ›É2+†#åfëT‰t)R˜ÀžÊê–Ý™EÄÑKê.ÉäxžúNâ7ÞïÚþ}~±£·“ÎcùW!‹gº^ÙQmE·ï~Ê ƒ/Ø à0+91RE"¢Ê·­/ÿ˜$Žâ?‹5ö Ï'Ž¿3Ïd+ G:ãÞ‰v‚úéz‰è—_ê](/7) ùR«ÏñÏݼák»ã|;§SS«¤.»kFu­¡$ìfÞ–(´ŽÜ ½FWå!8ax¨m»·¶8q^’£ZB¯ –ó0^êHtšÇì¾ñBxò\­ä\ÞïýdéÚ,Ÿu÷ð™Òš[ÊžÖÔ¾öxÕÛ¦ëúþ°/$¹f{.g Áܼ̉¢z]ö³N†Â^Pë–$ŽTBÝ7¿Bê­n ¨À°!Jh6ìÏ­%[üÌeD¤„L2¦1X©Eè ÖŠ(‹’¯Êïw.0E Á69ÖâMPµÎ÷ÝÓ[Øy+ÓJkéæénRþ'½ Rµr™0jI~¬3§R-r ¤”J)sóŠ?Ï»ÞìÚ´l¾OÆYõ§¬Ù·Ø%-[Ýw’ý>UãìZQË…po‡Ëä°2Œ9¹×?К¦h ûcʼn4¿œ{9èÕñê}`À±Ý~AãïœïÉòÛgZO‡»ôÏmÄ:´­6,ÝRcÉD æpÚð«ã”nÂì?ÙmëÜ«<´ëþÉþ|D,¹\`+¸¤ÆÕD7§¢’×búì—+òDñUùi9¹µZlJ8§§3šK  Ò7HI7fw»Ï«·ˆbûz.‚pqÝ´ðÀd}AŇÝ_c o3©æ„b…¯óhyËÒFoXQbPY–>h(­Ì:a",)Ë}(ï\'´ž IÇG"€åœ¤r²°‹ž•œ‘8|§·B|üñÌŒ4Úô˜:†ÃBÔ¾ÖÔeù[±«<›ƒ†i´(‘1ÙO&\Šñê4—Ïv*gû¢SƒM!ßà›#´€·ÏÎ@%á9¡†ÜÆq;g”‘ ÷«¿+Ôx҅š8G|ý Ýf7Ï>ÂIöŽÄÞ!;}˜GµNÐ_CÒM—ébˆ± k·Ì}@Ä}ÄhàÀÛƒm~2a#ªbXžYjý„Ô)jD}ÞýªäøJ•‚*|fñɤUcô½òA˜`µDf®,n4 ]…h"`O@x8ø̃ "ÿ®$½¹O³Ÿ´¤ÿÖ·Y;êDGh½\UpŽHêZmL& ( Ö*AFò›üÌÔJk÷ ߇sEY]áÔ/Z'ùãñ)íŒÕƒñq UÕT Ñf" [UV¬ßÓäYw3Æ07x¦H`˜æZ ¾r~õϹ˜Ö·÷‹8IõÂé„ËPØÈæ½K¢|wexõ‡žÐCMÔT>†Ø¹<Ò2_æT±×´$`Žc°æ±Üo#È¥òöÌi¾½Cl}åºjõ@þXtù=_a7–q´zÕo°ösã–¶OÞfÕñ:Þû^úø +Š•ã‘Ò&¿z1Ňívgm÷Øá³ì”ôE÷9³,ì¥,\„¿¯¦³ÕSÝ4[…šiˆƒ]W‘”y@kÚ&¹¶ð,!_eÕ é…Ö‹‹åIõê1Æ•©© ¦ÏÙíôò„®Œ§)ì %ú@'øÕ?j˜Ÿ ñ+’ÙB¬ñ|­N ,Š$jïïZp$COïlœcþÒŽƒQ¦Tõf|ž…¦M!`Ç„­º§Ô3]€Ic!ºÀ6×/:í,UbNSŸ3.°ôXÞvï D‘òƒ‚“ú3pžõ3ìzXg8¶«„Ï$æýg+¦7%žSÐÁ­¿bRG]MÌ<)nqBÇyXÙS ¨W­z(H×W?â+Øz¾¿Vó –R%i‰ïI|Ãíh(Ôw(ØE‚уRão…çæZ¼'ËL µ°bŒ~ Çw²c'é«>œ\™gæî`Êt Ôø%×Õ:'w÷HTâœÒMQ¡üЋt"h%[¿+Ž@û*˘cI¡…ê—Ir2·©=G‡ûáU¾kpápþâÏ ,ÁøÖ y~ÚN<ê=mŸhw“½h9îÛ®aÈ<ÒŢ㚈Êgi°Ùb»E1{íõüÀ¬Ûé~™{ÃÇÞ‡glóía@ÅÆî{+ÂD/åÖýç%’dm4aýðamŽ7Œ(”m‘-nKWDVÙ0ozІÔ0ã¨RÒÈcåzR*ëu ¨jŒ%ãã ¿Öjl­j‹bÒ vÏo qø®Tît)Q‘‡dì{ÙÓÈ(ÊÐïåÜèK†uïm²ôoýrCóÍ®Æ*ùÇ;Ë6aè32mkW’}\0²Áús^ ÐM{ÃV6ÊdŠiŸß9Sg±èšê`g°ˆ¶ÙGZ‡^UÕ®‚BeødzV~!‡ãû*}¶óÀäÎi~4.ª~»êÐp'öůIN´kô³B­*§÷Ȥ=„`}¯[3þél5d·ñj–²»·£'m³H·¡~å&‘El¹aÜi ÃY“'l ëÌjNí;°Ú^¾Õ”.-›gÅ­«Úˆ‰Þļ½o‘9y¦¹ ‹ÝœÑýâJ!>F žÿ'áÃ"NðÏ y1CV7VßdOæÑÇ‘>ÞBÚñ5hKƒb?¬çP}¢e29y9¶óª…}\Na=ëÛ±mÜ)»š:öUPIŒÅ oíîܬåœò„qí#½ó‰¶FIF97a©pòÿQÁ¯G˜‹жws­ËU$\%CÍ6Kõ>wC*— ñË]k°?‰×üÙ­5S³Á¶Žn¡… ‹2c=<”Åzï–ßÝ<­«»é“¹JòŽ Ž lÚC‹{ (¦û™ônâ#—¡w’Ò÷"‘%¬\*O”ú´ „°ÅXáÁqͽk—iÈeo;i`È븼 æáO(½Yk‡f "‰çä£  ÷ž”û”éià´]ò l¾V°¡•ò8o<õokÇʈ½¬5‰©_üëð( ©kpKäfÄôå!êŒÂÑGš£xu!Ê>Öd‡Å•ÐsÁNvK„ÎóÌØx«^ŒÄâ.5AÙ¨Ò ?£-f•uˆ@Þ ÍÈ,KÏ>„Åt»egП=˜½ú}Ëé{˜Ò^ I¬€þl»»øMÆ«¬ký«xÏS«5†ì#÷p‘ªúÖ¨íš`tÈ'E)¥6lYaf¨ê*¢ŒéDð Ö~˜D,Ûþ|›ì¯‹³æ¯ Œh-w]ˆ:óo”,¢aȤœÀ|5“y¦è†˜Ï&ÓCh·ÖpŸ FÅóݾQFL„á‚bé·„¤ðõE »jQôðSwç)MHÝ»¹zJ稚R÷c½è/y‘Y™Š€{g¯–-ñÌÙ“%¨ZƒD¶}bnz˜ýP~“ŒÊæè21ñÇÄvÂÇöѾÝK6ª:¦­8pž%‡„½É¬<`ÑtXzN=G¹âg iðöÂZŸ­øbYЬ©§»ßf¨ž*Ü–>L†ßå×—`®Z&¨¢7DwžÓr¬8SÛÚÛðÎ|Û¶HLƒ<î¾Ù]o÷SlÊ'ÀêèúÓ>¼fú•FÁwêW©æs†c.”’‰°°©$Ÿ É‡ž|»Ú Ä°j«VKÿé´#ÏÄT:ˆFÔÊ^;é ð~bÄÊåéÆònñ3åsN³5Ò˜²ô8ìGžná. ´uìË“ „EÖ7d[0ÚqBiârj|Ã%=ÞíTüú¡Ny 'v˜fP[÷ã7!µüpî®,¬eg«!å}kÐGˆnU©­: Û°ç7qhÔ æUWi{9œ”$Iù^YÀ)´jûÝ‚¢£õÖ ³…;þCbY%Nì&>L¬ÅBZFUZÄ`Èn'¬žÌv’Zk¨Z³ì!×ÿþÓm éûQfëYÅ£tnÝ×z4áŠZj㈨äýꔈë§Fø¸™ù räÐX„MøƒôLëæÄŽ%¨í×Öéƒ!Zk‘ÛowÌ+UMÊg=? œf¦Âšú¡v³ÂëWMeaCð«6K•¨Ý®1>ÊÄ¥_cöhÞìÚ"%îy–õâ¡onHýX}¼:× Px+>{«èßׇïwxr¥£Àb,ÛÃÄôÔÈKØ›ó7Ôôd› «±d˜ö¯Ð%¶Ã9àñ¡®¨JÇÏE¨®€SFk,ø&5Èú¼¬(¦àü>´Syƒ ·1çvE.½¯œêª›ýø8œê´êïÊ+µ‡W ±~!Ä‹®Õâ@ž‡Î¥nÌJ6¸©‰˜'–ÈÑÌÄW”uVжVÉóŽK fgÞZÁÎi|™ å‡{;¤ZØÆ mïÅó;Á­…U—°³óœÉ-aègê±ú˜=Ã7®W&íö°ø)iýÚ;jq‘÷T|r>ø6«.Ž\x7ä;„lN0ÅSº¢“dˆ±J¼¢õ8ÊÜãS ¯ëàWõh:•äz\Õ€¿H`jêßz¼Yà· >“§“Üc+>娇§MŠÝ8ïÌµŽ­É}~g§lÐÜ31÷i:8!·'‘AÍéûî\POQ’ûk‘ EÛÆs©›ÁgЃ>Là %™ÝneÂ<}}gOÇ v·­½w5…¹!#-çÎ9R6û-jù<Ö»Zndf¥C ŒE¡‰›¼2­2¯EYœ½k½c^çädu@êì¦5º¿¾Þh<÷$54Æõ/–›/˜‘§>|ôŸ3DÅhf`­©‚ÔF‹”;à‡<è%'’{šu¾[ –t+9‰ÂFaœ÷·m’ºTƒBìåÕ ¬N®k gIHqtQ´·‚¨â#…¯~£+–zL~Jæ÷©ƒj¯Œq©‘ç Ž`‡ ³¨‰ÖDêû(P™ *‘² Ñ°Åtœ?ò‹8f„~FGÄë’Åœ{¿ùœˆAÛn›Sê)ÒÀýìv sÛOµ1µ€ŠyÖÏ&`óøR†¼)ô;7¢PƨNõzäžs²#@8Ì 9óE4К jÚDI+V¤Ò¹Ä‰·æŸ—A¼Ç¦sG j·7â¨ÄgðFËG’O†Å髎¨Ù®®¥êTŒ‚ˆÝ³É°C1x.í}b[òèjøµãÔ±Ü=bÊH×Ðã ´^ÉD×ç]waÔ¤Ôñ^Ôçc–sÏ%]*ãzN§Ro¼ˆ˜KNµ·GÃM‚ ëf÷t’a+ëÕAƒŽú€©:¾  °Ãݪêýžà¬A>·0Ó4}â¦9Œg1g“Žø2ž|´G N5ÂS¡ÇG Fdø\l¶qäüà„²×·%Ki¬«¼îðD¨Å_GáÜ>? ÃÆÈÒ€*6fµß í¥¸ Žs¿H°Ø~?îäk¸>µ¿S©"Áé¸VöZ\ä¼Nh£öpÞ2Û_@öBañ@2ý¿dC¼"å‚8IÓL‚e‘z%6xåJÖü½ÊdŠpÕ+„óÒl%V?U œWkxôZ…#Ž( ›pv1COí &1¡1o„ bˆ³æöë.É7 b0Õp¡9WØç¿V ,®äŒ«ãæX2K€0¸ÛÉ1$ýó5úpž­ñšu>ùQZ=`n¨…ÍYø&­3áAf“ÌŸÙq Šõà™'êîEÁ¿¶fï@¤~šÖˆŠ…ØÕî³Ç61ƒr½îmOCÜ€uõ”;÷{èÇYï…é¡p <2&C©öÙ^|}×òp4¸íYÜåt3‰xGrê¼—fü‘î–Ê埾9\ÆìÁàcº;|°±£Vûù©VGpœä–qFXQöKО_kG&•zi˜n2çnÒñɤØ~†k¼NF‘±Nx }™a«ìËu žÈÇ­E¿Fæà²ÐèÍrs: ¢¹Wª<ý¦èòã¸äÆ -N+ÐBy9äâóc,êRF=e`ZÂpd(SŽi’¥dm¡LÖ]…Ry‹’¨³9*‚éË¡¿2»àH<÷]JÕóÀwçéèŽ8Æ eú¦CÙAqñ‚©ý žñ‹=Ý׈„o=Lv?îuI ¥=ö‹eR/‡×z_!Ômؘv¸g.}pô¿Æ›«@©hß“XÓwj©a åáy¬Ñ…·/´ÈÈ]Œ¶ ·ä/Îba8D¥™0ñœO¸GÕñ!X>7–Ï UY ~Y°Ô[ºÐ °ÖªÃ8axäûÝ» ÕŪπô ƒå:Ä7;€¿‰~AÒÖÓúN<~#fʽû’¹DÓ_tÛX LJˆwHº±YÇ9í"PÛ{LJ„âøµS«¸€W±XOH¿r¸—ˆ~é°®©DfÃ:U™’Ûc×™.p( r3³¢6•=~¿‡›Jc…÷þнÑÕ¦rdøžn&{QÂ{z4u§M®Ç…}ó®Ñ¹uýn•ݘ+­¤Ç°w³>,jáêq‹wH–[ßô±¦«2ÅDÛR[Ñ/f4ï™y FÈvâå´‰}Ñö#N ¹«gæ“£eÄÑ0l%Êóƒ˜3ºGß*5ü"¸sž´¯lH­ÀôRìePtuŸy…hÇ>Qù … ]«ØQƒ³å{Ý#éj3ñ$&ì$۫П0cìhoß°ã+LÉfsÞþ@*Ììt¨Ð ͲÑ={PN<êôÃ)Ì/eM^*p>D ¤î}Üîªô•©§» ÌŠy;~ð<žÆ€±M—ë]pF‘k§Øƒ×Ä÷Ÿå‰úìídÜ3ÇÊõÊÁŸ%wMÑ‹E½§ŽãPL¡8AÊm'.8¨žß[ª¾¬-Õã@*Øÿp#Éu‚ýà®ÿtÄsó¬˜8ØuÛÁo'„!é[J '¡,Óxn ÌdцˆäfnT§…mÉÄ¢Gt¸lóI…¥‘wܰWZs{ƒÛ;EAFø-–Ó¢˜ÙƒìÏ4,$¿ƒ1+TÓ¨hÌW|Ùt† dC½€qmÖeâ™h³QíZÅf>HЎƸ8§1råT˜ âï&8™¾ñ™6èM¸N®¸/ÓýÈ‹†’›êÖ€Ê&:ôÇ^šÛÝ7ÂàÉIQ,£Ò‰4<ê6A'+†x͹ë+Gc˜Ðþä7?ý¨@û©©Â-n1±vE‘sIégu:<øÓ3uˆÏ;ùc.ƒÌ–š%esûq“óg7ÏÒuš¶dÙÃ,^gSÓ5ÛzyoUÌh~B>¬¥Ë}n '‚Ü!Né`ËoÅÕ)ð¤ V62{Æ!´÷.Uf`Ç@Á¥ã*;ØíUüfàr× ùÚ#â¢t™y{8„îø ·o”aðDT­C§ÎYø¢LV[3XíMõ6ô› )ûo‚ [kÃç«^Bjß[°È³Áµ/·«¢{=×}%„9¹¯J€c[<Ú8ò·œ¯d\¢ÌCùÑMo›e$9Q¤*ژʴH¯wÿøÃ7ñÀž„ Ø›iöö³¨Ã_‡‹–Çš¼:üo´ø™Ú„µúŸU×"B-ûú¾ùB½î ôCjôÑt‡—{t$)ËÆ³‚ð1ö›p¹n5n°8TWœ¤Ì%’;0Ÿv«ä(4•¼l¡áèX€9A–m¦Ö²3]m»–Ù2„£õÓ•§á_aõâ•_Ó´ûÉärÒ2Ÿ6ëü2×:gåÆ3 OøåilSrY;^91“{yù6y‘”"\X¤\SDà ‰6Dú á2ôWSI° Ôô7?uº²ó — ÞÂYø%R<Ò t Á‘ês]ÎÔØÞìG};!:2á[`GpƒNÒ³›<1‹¬—å¹Ìœa:êM{iüâÊ鲟ŸR\¸ø †Æ¼\ÉL –r—>جüúÀÜâÚWo»€I=Ñ4fA*™u`Ä3ߥñâ¹óíV ªfÉtÙ]úº¿x¸\AøÕ…`½,nôF@×ðºPáå–ÆdŽøÞY 31ž5–I¾ÆMyYÂ5Ò–k£àÀýr´9¼êÔ“iLøkÌR‡Kô‹þ™ªÅ.t=LÃ-ÏûQmm¸É™an¨d]pÀ-[Y xIÐb­»¼U%˜7ðè;Ìñ9ÛÄáïIõÚ&r12Wÿnš¯qÚqƉÑC‚ƒ*Sš2—ªhÄo»¨A› ÜLÚ² ãã¼ ÇÈÔGL/ã/vë±WÊ!•^·äí¿¯Pu[P­{_¤-Cí¸¦o–Ez ˆ÷<¶`¼ø¼s3£Ü'Q~âtZùˆ }N5`2U& „ÞìŠÛàäŸï¥Ðµ¡qyäú÷û‡Ÿc^ŒH‰Y­šƒ<ÒžÊõMPD0— r¦¢èDó ˆSÓ0ýµFšB[GK/‹º®@ÿ#ï:?wrUlBRâõéCgÅÔß9^8Ûîƒâñ°y»®E?}åR‡;ÔU^šÅáÐIÀ|ÌÏŠ¹„î=*™ÃàwGßè¿fq-[ðÑÂâÄf]UÇ*S‹løyLpAHpÏÈýÏzÅÑO.®øc$eA`îÆÄzl$3@D5 È,tƒ,xþïŸñº"¡ù¦Ì{ßÊNúwÉ$¥ò|:h6L>ú}Õêa7O&‡ð=yÀ(Ø«œðw« 0ÄA„>ªiáß=2:/ã>s/YsŠó#• UbžÅMåu‚cøa1)MA“gêšñDÒ”¿o,icsX\Ù¹3¡XËŒý )m,Õùý Èi4üF4_įÉ Ù Èžpe¯åL×κ_GL2VKzÓ€q>ò®îê’FÖöܯZ»š?\”5°…‘Š×à-õ}I›8‹Áâòa:Ïyu§{²»~…{éx™¯O•bkwö\±a¶ßÂ7t³âçŠZº§ÑV\§-3“8dƒâµÛ°iø@ž!µŠdÂ7…‰;Ûö Ž4 ëdÓ5$ÙtÆ cRI¿bµ½øÝ¦Æ¼‰ ŽöÔrÌ÷–s0—²ŒIìj¨|Î ™wz÷ÊçN•™gåMo"t ÏçRœ„6d6#´(ÓÇ Ùtre¿W­%ÝîAy º”²%z–ÇÏñGH| §©Ýëx‚÷|YpóXíИ#HfFìÔª«·u]Q™PÏ“ßDØñd‰n£ÝÉ^T%™vsmfE3vì ”}¬3¦Âl>?z±™XÑmû 'k˜’ªE¹ÒWn4múçõap“Ø^õ bc+¿´y¨ºÑó®\Ÿp2ÅQRÁY¬²MìóQ9çóéä«ä¥ûyƒ®§æ Ëu" íÿ’QÓnf]efýú³ÍlI©IDEvò´Ð¨»»ãÓb*?¤ägÐ_rþ}ütL´lCz ûŒ¸ã—=#¤NQÆÊsÜ6WÔ&ý\À³ÊiDÀ‚Ž Çä4¢QI¹gÓìšN¦àÉ@?ŠFËÓåÿ)¿ŸpI‡óÝCÜÜË= U«¿»‹BÀäçC¥m]Ràiâ®]©ªUˆ¶“ìƒf+ÂoË ¨!÷MŸúêa¼Ã\¯`°MúÂϬŇȴ€-Hïxîp̲~ˆÆpðcöLùRç z…d¤0KÑ:Ü[vUî!OCäB ×§1=Õ·7ì"êçù§Z9Ež´Õ1ˆ?Äæ¬D:8X"·'¤9WöŠVÓê0û¥H3œ *d*×/¨…ú„ë¢Ã". DÓ ¥ØÖ”Ÿl›FI“ñ™9%!ÚçèpK÷‚á×F²Q•_Skæ„÷uä×âzÌÁqR%¾ ;¨WHëÚ€ëígù^ЉÄ…?ÞbvøâÚ'±QèmhÛM b?h"9h*jrµŠÃü¤}ЗÌ[—8.£­-b\rj‹ Óäx!x ‰|¦ QÚ—¿EˆTÿö†Îýûî̳²[Âj÷šÆÞÅïFŽ^"WЧ•ø)qmÝšòÞ âòžKhÀ‘²ó¾è²ÌxÖÈkKKT­/?‘úÙÔËRùi•û9B”u10=VܽŸe2QÇîQ¡«=Ú+ñ‹,ì˜örr‘¢“ŽNÀáϹE6É~þœ¾y'´%ëŒHäÕ .&ÁØ]ál¡Æ‘©²¾ùhRå­2õå36’#v ½ªƒi{aMÌñï"‰ñ‚Ú ]È!®Q {¸ˆ©yöŸr;˜à§¼ñ˜½\aµ*ØÅöênô…^¶ÂoÛbÉ…ö.wçUèðKÖ¿Ó2Šœ©>Ó@&%B2Â/ùÛþãóŀ9®öuoÞ·@æêÇ͕ү(¨|ñß ÒðízÞ±Oß™ÌsƒëÜ(pŒ[ÅÁt;ÓT/!XúCÊÐI1ùƒ·A¯/?ª@)³F‘Ã1)F¼8i`VOKèü#w¸5¹Óþ8zdçJ<;§tô{4Æûw©Nga ¥]jtá H¤z]88ÐüqÃ\k xØÍ K€µTÚó½m³rçOžü¢§©:éÂoÚc?´%½kïƒ(©­åpVªEDðCI¨zQö‡8^…)³Ž¡#OvY¼pÝ›§ßrËÈ1æ¾MÚ‡u"JÉÔïû¢ TÜþ‡%DÎ%³\’{ë¨ÐÅ0Nas ®»œ?žLŸýh£É®u~e×bCw/ĉE•—îË#8Üüî»Aoôð… áõE²·tj±:°çMzŒéul‰š€ùl÷õ8Þ9²vg)) œ4çˆÜ½+†#a_Jðåjmes"“Hƒ[äO:a m[¯uT=Ëÿ`ÉËðË ã(3˜Ä›¾ªÔ6G;3%.¯aǬ9ñuŒ?ö²Á=ƒ{¶Öú£»$xƒ™H„æhìËò¢Ü05…Ta·íNokõö•h·zï!EìLù%lÐUr+L^ABÄûx–±Š:éÒu6êÃåÒóÀÔWEã!»:h7xwêáöÕøö„Þ'ö´i3CSHG/M ŽCÎVz ¨@Ó¬s2Ã;¤÷ôØ/&3úÇ –" ÂtÛªùF"ò0 øñ PÏnRbH‰s³ÜtòuΉ’~§ÔM8Ü•êãgS‚c?úí.Ñ—ù•óõ2CÇbRYéc¼¦Öm‘e|ã‡Òƒ©bm¬å7Nù!q›½¶ó”©!”Ÿñº«7VÁ⥑ K´¡çð70‹tÈÉòâYÃéA+bá þ Â÷‘ÅkõÚ<}v|ø=Q#^ûRÒ¼1? Ñtº!:s8H©Um‹é9«HÈk!ÏZhv1•Ãë˜"ÙYË×.ó+flã`û¬­«ÆÕ‚EÍÐȶ ¢¡Ù=ßæ,þòåLï¿”ªæè(©¨:ÄEA_+ðq°â?ˆLãVÙUê›N­wm~¸Öĸ²HIæ-Zxã…ã¹P“K$ØY÷?Š‘ÄٜЮÌûƒÀЀDY?~ƒê³xkáû¨êð+9éÄåre²W¯†½,FöILJ(5X³R‰O‹Ot“Ž®A°Ò…»áotv·Ë-‘(²o{ŸVþ˜ dç[VqÌŽMŒ†^ÀtY\BWkfd¨Ìì }O¿päÍ!)‡X .à˜Ö΂“à¾y´@¯/ÈÓq•òˆ†,·e+ÁÌ ¾Ûñ7S¥l$ U ¹˜1Ý=a¼Ã»I¢¾J@1K섉Û…êÅ!Ü$]þXÊ ØÞ!:Ô1G„XÉtÀ&ÀƒNµbQìýNì·Çç¿Ë9^ΧӦÑ\€˜ºÅð ï{·£Õˆ°îÞ,ÞiY͈îÛÆý ɪ£Ä>.)yÝ^–4¶kŒ5Åù3¶ŒuðLûM“Ÿ”öRåñ­[H%ªöÜho‡Öe5Ÿúe£F'ÌÊ À¹c &Ö>06Bžê:R Zî"¸ßÈd¨”g?,yR¨VÊ‹Y7JÞíKò`7<®Ó÷uRH ‚;"Ž,Û‹¸*úYZîmg J‡~úua=¸É|÷OnËBI~®ÆzUW4MóI?Ãõ_ûwRŠ[–wн£Äº»âÌ8‡|Û p[œ+c}{ U¡æ6J.T!ÐF<9$.á/nfϲÔÉÁ]\¥ÛÃé((ßõÌ(qÀ0¢êÎ〿v“SaYf%\”½7}|Ü›ïK ü!'ÚLj®3†ýì{õö§‘Ì:š2ÂÏœ°ŠÜWËÌš4nã&Dw麔Á”Ϻ'l ; ¨µQZŠÕ?ôc4!_תYíO¢°ÇnÈ*zDÄs+ª›>0‹L5]–*‚žÉ}È<®]'8eY?HÁ =¦¦æ¨×FߜȄg¨†¿sJkdׇ d¥Ø˜F\X×}ŸkÑë ÞŸK(FC* @²¸÷Y?“Ï=§[”{øL——'9×éÚN’Š„±”ÙE–½•ŽO5KrúÚýXÿÌÛ¤˜m†pêì‚…â6¡zý”Ã)[*:”¹7áf5h‚¯îtÒÑ»a“­r׳@.°¨N™¬øHPµaZ6ÐkPUäÍÃäu‚pÇ®†ˆJ):Äd¹ÃÖKýB†n¤^ΰFT_"®¡¾U±Xá¼Ø—ÙJ7dÑ_ïÞA:æ”ð¶ñi©Å›Á›PŸdLA ¼]ä{ç÷ˆÂ Dœ ƒšá¡»Ù‡-p:g¹™ãÆÜÍÿÑ.ï¯Æ†ÄMïB¬s­¹@ßÿÍð:Ü=3íËZªiTít.æ8(pÜHÅBMMà…½¬M,ÇBP)VD4þÝ_·¿.ÚUSÊjˆj¥mX7q] 1ðp,sni攜_„N}Dônï÷›žúÖÖ]å\وŋÎý]®}w}`#õWDcât“¡zy32ûç·ôÏS¡Óé F \Û‘aýí˜íBï —xÃ/æÖË?(GŒaÓ Ù( B'o¯Ü…k£«O÷©¬) ÎUEÓv)þ ‘ÎV°íXâÃ=Æí8^¯w8ó<áÍêÚÌ\ÂdÚ4–¦lS£JàM¢Üao_F<>AÕé»Ý¸“Ö(d9û«È™ñþÏ—E§øyÏóL÷Sˆ’ã|Œ9ì× j4(°7üúg}=Ž>c}JÌLð·G9f˜ePlù 7mè3lhà¼"°ê¼†ãß­†h ™tÝ…ªvcý FÍÌÁn¤0z½ Vrµùâ6«iàMpâ†bÞZGö]jc«m»°ðêu?î¡ùùÁ.Ò+nÀÞ_΋¤HŽšz[£#a¸¼L{¨‚ a7ûÏ.R]#âŒKܱ§èô‘û&ÞþTÙJÎ]A^´¯æ¨•5Ù(¹Ï~Üv¿¨RÙóX„1™A eòù›ˆÅP±Æppp¥ÝäÀ¼—}ƒï™ˆ;O82zgƒ7S¸TfwþDãa’&ñÓU;ÅÙñ:¹Ã"ã6Ì‹í{ÈŠ¶Š—Ý0o)NŸ}ßû {Ðè“©58ìgx£âa}Ï·…VÏw0 7XgZPŠÄ#ýU®¿ªœ„ÖË» Yáú¨1]Fl€ –{ ËSûlÞñ{º‚\Ì¿ƒƒW)¥ð’#×D»\2…æ>k–c¬™ÃG»ôù´ÑÉÔc¿6EÂ×uÉ“<5M5YÅ„©ÿ Íc‘n J9ZUú‹&ÚÏpN­pÓÎèÔÄNä¬HýÁF) ÂFvÉç`÷Q½V¥LŠ?ü|qj•Â’XEÀo–¾]ÇëØ³Lª0<6f½“j_ÒµjPòq{­Öyð2Ë/xfOf ò$¨wÔê©!}±GÄbò‚©³$·•‰§Àë8ïòEÓÙ÷ÚGXé@¹SÂÃ|$Ô]l•€e€†,þW~jñ(éªýo~fŽ*öSíŠ(ÕÃÞΊEÒ JÔ˜cÒÁ?_­½g§ð)úV»ûÙ®Öw„bG3zÕ1w6Áj{~¦§P›ñÝë Âô1gsÛÅ2O¸·a°Ñ€;Û¸2ÈË<4-ÇœážáPÁ-DÒÉäËÈ29o1¨Þ &ÛT¾(”ÃzZQy±«¤ò‡™–þX6Ë&ê(ÚVhSüCö› _¢Aµcž•Íü‚úƒrº’$Îr.Ïü,ês“k¨3ò>oÆ Yk~¡N{šÁ¬õ­®†Žg¸©AN0€ßûÿ»DñPb–³BWQãð]ý©¥9Зûñ³ýQ”‰ÅHpµAæ¯ÀmÅ>Ðî4:‡Ä§i%­ %t9[gK¯…=™Î2²6w[” Öo!ûÒÿTlý.¡¦AJiònpD˜gVA laìÈ¡Ñ÷ßü.ƒjà˜ZÅ6ƒúñÛ¬†y¨2ã³ê->6Ù31„Zª _4óöòÿ§û16 ±¨E–O3TŽ!mí2zoàLäç`T/ûLèÙ0¹7ɰZ] ðÆGH»fÅ­¿;}/…¼”á«§¸~òˆ¯ÌC{ÍsÃÍx:h˜çk¢ 8M$ù{B »càÙìRNÒð*ë;Zñ瀔GwQ4/jÖ¢„ EWË”Žüœ›Üà´iðÍåj—+L`Å©W*¾«Ñ¾Ö cüã +abt;§¤å: Èé7οofà—Héñ ɼÛJÅ[+ëk”ºDF¦’KŠ›wM‘pÿωéñp{ƒ¼É[K}AIê¶ ËBOÕ­‘e×{ÕIc>läºDC)>Í蟱—qêGO(„T‹¤ÀñpCÙÈ)?F]Æqc!ÙÑõ²U[uñn)¿ùëv{æ\î´@/'”KḾ+¢Î,¢î¯ç ~®£ÌŒå°v5.’²A{·Êz:eêSΓŽôWsZºœÔŽ-3b-9’q’òtLn-cGÈQ¬FÃFÌ  NŒëBd¾Ûc:U'‚$¨‡þßÑžŽHîãý¢ë‘€«ù•T©ºZx\àR€k]¹™-{ž}+Sçôá@ID¼)“aûTmù 57Þtƒº«ô„˜5 ÷Í60†ƒ5·[ûaT!Éìh  ê²Â]ö:ÝIÝ÷-Ä€+¾þO]åÊÃ÷ŠEЏ$‰‡Îâ׈ÓY¤¥oZ8b;!¹ï&•ß¿«n#A´ÈÝBÆÃ¤ió@?ý5é{nª7ÒIír½I÷ï´TôÛehMlÔ®ìJæü3Ts¬§¨´`w©ªõ(¨B.åš}+XWmÞ5ŠàP¾JH÷­ILþÎåR>SÆo¾±+Òyß$£ïp'$ïF™ÉП~î ÐÀŒaYfzhŠV걨§ã'PqÌ¿$Y!=ŽÚœwÒx"™™ˆÒÛWÖ¹„¢*íÄ ±W.M©džýd©%Ò„Ó-‚,g*V‰I|“4¨· ðîÜéO«u »UÆeˆE!ôÂHsCÞâázDf~IŠc{ÿé_5“I}ÃZ8ËÛÓr¤K??Wê0ê 6ñ{[>›€ðH$¾H–Ì!ü „ '¯Q9ª×~pRy`ø•†¤÷{i?ìLSê-úQÊ 6f(§2 zŸƒ ThÁ© VTÿ¯×¬­ˆýSaVD9_,‹Ì¦ÌÌhj{YðÈ5¹Ž”Cé˜JÿUË[&Š;xF· E­X8¬µˆ)ΑVÂ:ž­G¾×5+±/Æ/ïƒmìµ2©2Ëõò6¿»;ì•W25ƒ´ØSB!ô<¶§ôëçé ŽhvÎF¤žzÖ\Õ>³šŽ9`ãäÝi·zD £tÔ~ò4/é["Øý;6'e3äò÷ oÝXr ÷ï‡Í2ÁSB‰¯nË$ÌçàB´ë0°ÊVÛK Æ¢ÓÆ+<¶Kõ»ð$³P ã¢õ‰¼XMy>j¨ýÛàÁÚØô0:€ÜÀ¥*w:Œ ‡ãÀ N#C¾ÐñKCJ,1À'´Üú‰ŠP`柺ydᆮù7úÝ_¢OÑÝÛ®ôšÝ¥Ë¢nSê0Ú"ÿÊWYú'É@_ЀUŒYsV«ECÁiÉ8E…‚WÃu 6’N ª¤Å¶'^I£2oà‚ÂGçÖ³­Z ÆSÒ÷vuÏ:¸È,ɤq¥PžcX†ýi„Ÿñ»\±ýã]I²50­ 6}ÖÁÉôBdº9GVU ßwÝ{ð"ÓwÑ«2é¢982öÿªž4_ž…ýÄu5CýŸ¿ ˜úB;cºÒM÷[¹õ¦ÁýYĈÕÈBÙ°ˆçùLo¥‡–rÌü„Éí¥ ˜áØ“£Ù–iþrÊŠä¿øT B´Æßôl_Jž6òŽâÔ°†À˜,õNË„oºéd9×ÏFõEÂL?¾" YÖÏV¶°Vé5×yE“4/& Ð@ä¡w]}pMká€àÞÐÕPdH*"AYˆðŒÇ¹#"‚R¯…ªgÝfR½IrmÈgŒ !ÿÞÇšÌÔvcL¼ÞQíÇ]íËàk8¥Š3G$Ó´|Âð=ä/ÚèQ¨?~Ô¥|ÙT]Çþç9>B¥aÃõçi·õ¦9•¬ø7 À¢—§6nqvÌü[Ô&î³Ý&owã¶Û’õÆ"gA/°éþ8ÈS%{5të$VÜ>3Uj_ÿ X=+A²*ÏêÒTÀ”*ân¨±§÷ýE¥õ!¤Ü›s{Ë×Ûë‰43“šCëÉhøuK¶R‰™ I-g*mÓÏ2R@¹AaJ0üíêD¶½^°zf>™;,¶wæºz´µÈ¯[9ê0<Û˼åE¹ÇHÆëìzM#:Zââ¦nF‡¤éliáEHiÀÈî!%Z#.ûÕUhµÌ«è%Š–ê[@¬³»Þñ˜ œ¬]©A‹Ð”N.¹Šæ) †Mô-WÇ—Ï­-•m{óÑ"ç;”8¦Ïí--³èrðÀ™ÕÅ^³Q'Y‚«Ç[Üçw1¿W¼Ð•øBÃÖj‹(@x$uµÖÚzþ¶ ìiÙ߈,ozd°AÁv‘¤˜£ÐÞbÊsÐ/¾ ý’åYVÍ𪾮 δ®1èdÞ:Õ }4x}“U ´Ç¶c‹?+ªqEŒâõ~Hå?¦¡Ž9D´"¯­ÀÈ¥&uÔ©T+AIÔY|Ú–‚Ö×dzk e{N 0~F3•Má—ZöC]{óa;ïJ†s6Åðjú+hl!€¬{ÍMë•eưõÝéù30\Æ€8ZÉÐ,“²-Js{'\pšœó·EV]Ñu¨6Àµ™ç™Sª”úñ{@ÀdRÒháEKWxý$ÛĘ?œ­ö{‡Úˆ€é/3#DZ=óä›kZe}]dÔ ,MN ²ãj‰XlåÉ67× €þ ž#:E S3‹aÖW,ŒÈv˜Xk¯K‚¢,îZn¢€^˜á;°*0Óvf2 ´Î‚Ρh½¯ó¡Óaxa$ÎC†ép#ÑnJaဎ…¼OÆ•™ä—ͽa°ºBÈÂÙ@œ7 Ù§KD‹5)&«}wj µgÄˉÌ6P”ËŽw”Ökö +ƒš°9Ô› @ÌÅ5hÙFiÝ™œº\vɃúm¬fúïx¢X_$š®)j÷®[±"Ûzë*_å²KSó$Q©íx0ÜM¤€÷¢QA¶ºJùzËEØÿ‹a*Ú¹Èø{^»†Š /™|j³@Ê|Ž¿C%ìY?Ž«–¯rså+ÓEŽ–I1Ê&ÍeFƒÎ%òÙì„6^ ‡lˆ&ùH¢—ÌÚf<yƒ˜³~×iºp΋ÆXsL¸y!³Ô—vp£Þ”¶*)úÝÆ¨öÿÞ ¨kðªM”pq[×óLUgR§n„{cr¨]ÀPªÚ]š·ìU%7ÎI}Cãþa—¢×C¶."ð³Ñ(¸‹¼z§%®”噡Ѩ^À1CŒªcÒ vþdf<4ÒUÅ™¤A_v£hˆ‘¹›Ó˜ç–=dAœ˜íà)f"îf|lºê?_9åiiSO9pÌd_öFÄo½Èª¥SdÎU6ʹ85ÆW}hß³Ò—o¹Í+Í×ô­4beÒ!ç03‚(¹ %Þzõ»jjnßî»O¯‚vtÏ«­t‡=?Á›æXN!oŒèçÒ»`ÿÿ£x‚b°@49Jl½WÝ\Á[ŽêA׎x“F9{"Š2¹ãN¢Ñ$&ñoصx<×d8'‘1&-¨³à>ÔüU@[†l–›¬Öb¡@À‚I.Õúåd²ˆÌR±E]«´ä‡D]¨Ë ÍGsŠ¥Ù–‘®°aHúüusƱæ¬ï¤:`M\öùZA5•6¦õ»R”0ÕË·PÉ÷C:V´…d®@X×D¦o†Â:âk;;y®4^±NÁäg©ªKˆRi5iÎø´o¯à3.~½çËZÀ?ñœëô¸ÿÓè*¥GSHz⛯Âùf–åZ 4?¾«â]F°ò¿$¾‰ˆE€Ï¡sÃÓ§ ç8K»¯Rþa÷zØ…çè2Îr)ë稥ðJ«I×A…þEC#q¹,O1¬=&žMÛVE=òôIÏxÁ ÚÚÕ¥M%Ç®Îé1 TTéÀ/Ì75K$…쌢ÉnÆbebw"öO!ù®¹:D‰¿‰8:ŸÉm‹‡ìRyòît}ZLÔCøLytáS¿€‘:k>Ì#W oá`?ªdæ­x£L}q±Îœ~Ã]xȵêtZ2o¦8 6V|;ÀQ»¿DeH•’W¨ÁŸ\)(£S<½­¬EŠ’Ô€¾&>}Ce£]±òo¬]&{Føl;¯ø7¯8IþãÆPÅø‰C¢áÀ-Mºw°ã7jÖŸ'íRÂ$˜þìžÊ¡*º‚‰$mfR{44P¢Q¯Û†võ¢º1endstream endobj 255 0 obj << /Filter /FlateDecode /Length1 1647 /Length2 9233 /Length3 0 /Length 10082 >> stream xÚ­xeTœÝ’5’ AB‚»www·n ¡é†Æ58.Áàžàwî®Á’àCÞwîÜY÷ûæÏÌýѽžSûÔ®ª³ëÔzºi(Ô4YÄ0 êÌÂÁÊ.PÛ[¸8iÀìU`üJ, kygsà ã~AC# ™;ƒaP)sg@H,œœ~~þ4I˜ƒlmã  ×ÖÐe`bbþ§åÏ€…Ç?'O'°5@ûôà ‚ÀìAPç'Šÿµ£&p¶¬À@RUM_^E@/«¢ AAð§"Ô\, `K€Øu1¬`päïÀ‚ÿ”æÄúÄ%î089€,ÁOn wKÈà‚Ûƒœžž`'€5ÜêütÎ0j qþIàÉnû+!8ìi‡ýöD¦srv²„ƒœOQÕ¤dþÎÓÙÆÜùOl'ð €Y=íÂ,]þ”ôöDó„:›ƒ¡Ng»óŸX ìä1÷xŠýDæÿ•†‹jýÏ ˜pµ999=ÑT ¹¯–i›y™¶ØLаRu#½N§•VŸð°ël¯«k˜Þ¡¼mæ‚£þbð£rÍõãþé€ík™\ƒß‚S‡ðº*ïà6~ï×Oºî¾Þžö³ç[$L™1è4‚愾‰ ÎfðËZˇç7®¼.nX^¸©÷.TþPʘdµçä5§}sÑE਑D²Sí¼M»çi磻0 ”4ø.×Û_¦Š*Ú2äüÎV—àÕKvÒÄ&í´VW=¿«Ú¹$,o6z®´#y÷sól]s½w6‚2 ô‹oÓ14J¸¨7콃—“ñÝy¸7g¼=м²F±³¶*M÷qï6%w`•ÀmO®Ð[¹Okë$ˆæµçǬ›}ÊŸGp M+6‘ƒêÅ\öÂ϶ó‘çžw56¼r¾£xm¸9¸“>&ÝòeˆÞ}gl¿9*r¥,.Úw%WZ‰J2xƃËyNâ3…ÅnÕ/·÷ŸéFGý¨(\GÇ™}ô’®¿T*M)¼c%¢”½X:Ê ¦(0Ëæîq²W„QÉ­}C­Äër’m€ójìr«ïB³¥ÑëLS¦ú}õ¾É³"ÚŠµJœ&þUl“Ï$Èû«'µ¢.ÍÜžÁ*´úÇ8y¤;c‰ w×’/‹U5ÓS9…®¾Ïiùq²¦wdxÝþ“±%¢]ðê&·w¢qB(ßm;u»o¨Í|cgºF$Õú¢!öuBá 9°‘[ÚþCI²±÷7®uëÇ5ù~J)îß1Ûq\Ï»>z%‹ÉÜwƒ\ÔÔ -S­!“ñÍ«0j:Zß ÓúÄ”¡$œ;­q£,3ÅŽöO‚w\‘ñf¸âÝ }‰GgÞ¥IÉqý6è}†F¬ð] \Ã(ãgšò††šÊ«÷ *y—Åe¦ÃŸñ¨E¯ÊÎ~MòQÆ‚ß~Æ1½‘Ÿù$ñlXÎÙ:YzcÔp¹hH?]yhûk1²Uëõ4ÒDc¶{â­>“Ã)õQ­Š¿öŠ–gIÊ&À|À/ìž0¤roàH½ag[Y‘sŒ13† X^Ljxå)c„ œ;³K‘ò¨ÕÃF×ÓæM¹Óã0ª;šªÜÔÛŒ_o†¦ó³F®c½*f)0S[ãêžÖ #Çq®chnù Œ6òuVçCb=òÈÒI¿m§bqÃLÂ\ÔĦ2éG%ó=ÄÁ_'·íyììïg¯\[J™yúeŒ%éªâüØ©™ÞÙØØÊi¤/Ò,ûøU*º¼ÅLˆÅP Y”f/Õ²‡8LrðÜ_æõôå#mKÉ5r»iFÌjfâÛ35ßÓ”Ä3ã—ðeN™‘7'4ð„ò Ò½(¯LìHók€ms~¤ì/Óm ·ï¨eM¸9Ìåð 7Ø‘PtXED´Ê£»5Õ#N_Õë½ÿ18¶-·3Ñ£·ùfa­ÎúbäÇÈ:%BÛŒ&w eÐRÄW±ãù‹–Œù`ØKD/Ž‹‡èü·oùWÄ»Ww_üMe¸%h»„­½ö<îÖj^|jæWÍàÃÿ䨩7£ÀÇ@ÚXf”øݹO¡—-n¡‚Ä(¹vf˜§k«†k¯RU<æÊÀ<~`Ì¡Îi'Í[XI™ÁzÈë·^Fç8Þ¯¾þ›Êôd•SOÁ—Øyîô±s7ØÄ1¹ÞG}¹+,û2,—ð7î(î—M^ ÌçaS|ÝoÃââ‚ÉBÝ9½TaÇæM Èß×ñY*Æ5'^]‰ƒ"¾ùWÇq»b³ÊkóØÐ£­Ãw–ÙýO#L®z\µÚ>HcülE™ø©vš¿ˆ9Ç¡ì¿ýÞºNŽ?…Pbo @âµ4CDÐá<<ÃÛ»»’Kæa]¸Ú0ïógçŽ[‹=bÊE R€dk´·‹ˆRD•Ð!~Úknn(÷9ù8öz«“§[…äJ'DîghàãH‰‚C1yXÕW€¢è³b1a•kCñýÉÕᵎ‡üžß )ªR{ƒª®¡Ñ‡—f©˜¤˜Yƒ«÷ÀªÇÒB¡_*d”mîõ‘ŠmüÆEÌ…q1-Ï‚†ô¯$¶TÊŠÛwÃ[¯Ë×3|Öu_×-$Éš,&:ß îtšêŸÜ¤”,ú$¿†QŽ18˜ÌO¼ Œp–¢+s:GòIE²µ&´PVf¨ xI×,à$?êUæ=<^úpˆ5W‹²›-ü³t]ëMCý)åëÆ^é;Aîï¿ C‚ìrªkÚ7m¯7_M‘ÖMP÷W¿š„v|za…çf7(ëÊü†Öû!/ï­›S£’è!ÉBÞaVr[EÓ‘hG c9Kt´ctÿ•Å‚Õ@ç@ãîÁÑyf÷ÕIbÒë]ÍDݨÎàÄ®vÍL“Ìëa·À8éÒrA­›¨IÕ’Ségã‚Ü~ùÓ&ŵ¼#EØûŽÉ0޼֔+JhÁ§”êð.~ú¬€µIÜÆ}zƒP ÞЙ4ˆ£vÜ ž/œÛk\58×3‘cÝÜŸ£XçK¨xá®@¢Ø@Í®N.gc‹…»JJ wS¬þᣕÒ®‡lU„#aû›ˆÈ0†‡gx-7þúy²/¶jÙèV&þÒ¦§›J 24¯•¼ÖPîQÇÍNÀ-"‹vÔÿzv–Â’æ‹Ã/bç¹Cj*`Ñ·Áà…5¦Úª|0Þ:rf(I¾³¯5 DC=’uBï‚©n_vW¿C¶ÊHò¹hŒEè{}¶ Þâ7Ýóç¹PZ|kéšx‚$Ž0å‰ä—IÛžo¢y×¾È3Š0_zתg36&³%Â}Š~e³ƒ?š€•ù‚€ÞçV•TxG\ÜÿÒÉvŠà5ãEP; eš%`‰åƒh.‡!03NEHpÉ0àýlHía\‰¯;æ¶ø`KÈòÐgÍmâö›¸¡}¶Z> ù¹ž‘ŸæBIðš ´TŒ¶Ÿ©©®‰jOÔYw\–îÒ»dž\´‘®)ô詘44S8ÅUß<ÎUý¤3«¦ ØøïG&ó}—Uë#Óê$6H¬^Ùô‰‚|ÓFÆtVÒ\:RÛî ]É!óW Ñ®UõÇ÷ÜyAˆl†NÜI§¯zœü™;3€zï÷7+ªÈ7Ñàùº2ÖØ—ÆrŸ ÊnQ7¿ã÷º½}Ÿ™š>Jc‰¡ÝøÝ±ý˹®Û`%)%©oö¹µ€IÐÀ´h41‚‘(ÒÉšÒeGS¿Ñ0èÞ¼*¸{¥~þàž¶ô\=¹>J£À…µÞb(vý£|´ôRÛùA>éç›Á†íÌ€rJªÙ€¨ÊãMÈOÙ ±Uß7´Pœäß$>LUÙ>ñ_B ^Ø ä0Ë4%Ëlæm'&CfJ\Wß)wÓ,È‘7ßÛKL6 äa)™ÆÖbíÂDت$1©ÆÞ®)úݧ×]¬›Æeuðã/§× „¬DÕFÎÀ¬>MgWÿòa1'Çtùãj„H¡¾*Tý©aÔÛV´ bó1Ž!år$ÓDóQXYpX—¢>ιõl¬¦ëôÎU¶yÀ·/AMˆºü7ƒzd¾û‡Ý¶¿XbÐNîf ô6×Zõ=÷Á2دÿ\ zwŠæ¨›ÙMµrWSÌyr1°vUšõIÍ—RlÄb?Ÿ…pù²ÏGþcA2;úôTg*ßä2Ö0Ñ‘¥†ÿ…²t—dq|ÃO†.]12‹ÖyÒNNa€M yRjûÞ³ÎGÒ,ƒwâl<(Õ3oÐ'åe¯A ÕcÎÑó^!/K„¬&5_‡¢’së÷;•ßVš:³ä(` ‰Ü33¾kýtºià&ë4â‰D{ƒ}])_h ̵¡üüêôW5yySãPú€–”"wÍGŽÂÊûèßw4Þ=lÇ.ÈzvÌ&ÒÛã#œ¿)á,tØè°å€¸A>}ç—ÄÄq_WõX-®-=¿m%û&æ×µ¿ðs·v·^IŒ´ÙmÞæ~v^îªôcî=¹¬yÕ¼fR¨Zät6¹eCM¯°)ý¯6H=åÀj|«au ÿD8¦@ï4 ›\3+Ī"ŽãA+îlŸú’8:±C§ µKr\á‘a=GY<¾Úlr«µ+º(“!i4Oœ±EìtEâ'^ßDº,ÕÇ2îùB(Ï…†«üº?nÔÓg<ÿ´j,2«ÀÌFŒk®Û;'ÈÕô¥#Å ž°@ÇU§óþðw£&ësèZœõLkPª¢'R#èësAÁ»z¡¨Ÿ“Ò²:–‘‘t”æ¼µ¹­FVodÊô>¦¡¬(Å4–,Dæ)2}A\í¦I~I=‘¯¥^­q/ ¦õ?·¹ª"µ©ÊÛœ-ô·õIÁl; ÑPnÏþRÅÿ2 ®vl.:ç¬õËéÝÁ»µ9Q¦•Lû+ó¼“u…Þen‘—Kˆ(µÜŽŒï*Ãý)ŠÒIŸÀÅ‘‚WµÊ$I2db†á¤½‹® :Ù½3Yo Ôˆ×m2]­J´-Ø?4¬o—CôÚtÕZ|>lMâƒ*Ly"ÅCû®QÀÆ?”©WÙ^š;·MÆ•àÌEotj|€ëUkiqÉ£tžÞBß~×Û$«œzý6Ø-Aà›óÉ”&­Nd÷RbÑmhôð½Á«1û`ŽâD«6Ç$¤‚.ŸÔç÷\Ë¢ŠeàˆÙS†5w}+Ù îÒˆ8t£ %§”,Ÿ°fòx&äÿ’uJ¢w%´]¨€ŽÆíBêèSù˜‰¯o¾{¦Žj{}³/¡ˆ-\cR1ßÐ2ô­-°Ç bh9ÎÒw '×þ ¤tá ù!PCÉrc«é9U'ˆ]Ÿ?æÕÍꢙ–ñ_ÍÅV4ºÒŽÂŒî½;ì¶p³›ÞoîA¸ÆO…{>x1âþ(*rmF›;<¸’¡žL{óÓ§”é ù(¥–¾^l>ªµÛÚÁù/}DZÒÊüÓacLpØÏZôdpǰôÞõ}+ šs&ž ªáÆ¥¸¢•€®d+¾Q˜Ùâ˜ã°Fe2œŸý²5j^„å/Cª_íÞô´F¹ãÞn’I¶!  ¦†÷OCÔC’vÕ Wò>oeÕ‹Àï“@Ùdeã}ÅSéü 1/¤èrèMv'75õ‡@'k|Ý8.—Aö#Ýç"Çoü—nPçC×} s (:m¿Ïï–).9M`9l‘H¿Çø GËÍM¼e'ó6o­Ê{\’˜BL6½DXžªÑ¿P{ úFJ4¥±í+Õ…ˆL;w”Ї)ù +råÍÇ—´F☷á½!GŸJáǯµÅc}ûùüG.ºª£oà˜Sr0Ç:‰…; ï}· E³iòg‚¿}N¥ö—òê:Ooƒ _7¾“ÓtüÚ›°‹óEHBáàŠ|SF²ÌÃ~Ï!¤$Æî>˜C¨`ð®ÿȲN%µË«(¨Ã÷zv0®#Ì¢¡…»æmÂèyßyƒò‰ÅÝŒxG»Ò"’j.§ÞVFVøù‚š(FèxÆ.ƒ¤¾ã(Ê yÐâRFq*èžoCäX"Ç|á´¿C™ì:rÇ9Ý1Æ<ÔÊÔcVl˜ÝUô¡údGkË´hÐ (piêf’A5®°l54Þféê¯oü,5˜fâ—í-ø3®®ÝRc"ÙVž·qÑN¥”Én‹íÌWšçuæTß#`©¯YD._eøîWóúÛå/Dë„{¸‹ Xs bÃxÝO4‡¾=/Ê9aŒÆo¬}…Z Ÿ)|´Ÿ¸ž*°÷Ûÿ=”ƒqúlþz9} ˆ¿nlk,ý­…äð¼CŒ‡®+ÿ2w(KÁ% ¸Ípj{ rdÑ}¶"Hkï2¦´14?Üɘm‚ ä8ðã2ÿ›LŽç®tö9ÎRïÙlTåøÇnáâ̦c”Fð·´Âs)‡îÂÕBS…RÏhü›‘RÕ“ƒ(…ío|Ÿ›ik 5„ƒKáÕ-D‹ë%÷¼h4eÜFsvIÊ4T³‹¤,jS7âø-”+éR[î&CÝÍ©9L”Óì!/+”c âÈ—|oã|` ãµ9C1Ï@´0\Q!NÑCXhQ™ñ¯àµ=¸Š†mŒ·—“7SÛ ej§ž‚¯Ï «ô¡ý2*‘¥€Ø„jP\a ͈tdò¼ú¡æÕý“°*u9m®×xß('»­¿Ï¤3o̵Gp ~N Êý~K´ÁLÕòèÁ oH{$ÐÏ0ˆx{wjƒr’KãÔfªÁö•´{^e‹º]•Œaô©À \âx˜i½AÄž^X:«ËkðPoºæD? f›,ëîÙô(û"wÔŠ‘Ǭ¶TXðüpÃ…?Týž°'žøq…cO,‡4òM§½öá`vŸ(„‹.”Á϶ƂÃ’+úLvØ¿©œjõEÀ°Y¹Cé 6­ë`7;<µ‹HÉCk9ŸÚ•ôìêò³°Ï6¢íXð# ¥ÀÎÖÃoƒ+Ð?ùRKìfÄe9ÚyYƒ’óJËÒm ¤ ›d:]°Æ€ºFbðÆPnUèE.7{þšÝú“zËq%ÜL”óˆrðá5û!Hg“'kÈ·£z©ÍéË}§XvS‰ÿÓmîæ„e»7õÖP3LΦ1$.ßHÊ9d)Q[dùj6î(Z'¯.nXl,K0ºû™aå3¦óÅY惩¤BÔÔt™!I¥WXˆæU~Išë€[”È¥‚Ú(ן(GVô²~)‰o=¶œs|Ï*Íœva.KR9j>ý‰z¹bŠ7S¢%X‚Ù ËìÀcOîÆ 'í• 7hÓ§KEÐÊ;Ã6D]J£³Ugl&<ƺýÂáñuOP¢ÎŽº›R᫜­êã;F‚¼†®B¹ß¼ä”E~õ³ñ´¼2up6SùÛ'GBî÷Ìw 6aÞôŒÁ¢Êß#É)cáþ¢µ¯IÎ-‡g8l»È ü÷Ì̲Ө¢~Ÿ”ÄÝ0-ò¾ !-d®B¤*;ýf,Ñ ç¥þM+Ï»ÉGÊ +ðd zªÃ¾zéðôCp›"Ûû¢ ÷Y¯ÀsÑ{¶0¿®c³±:Cœº–¢Rì$åÈx¨ ºjÀÌè;a/&°}þ¾›ëø=Öø¼ÝÄÄ pá~¼=…LÊr9ó.JzÞz;!ÁûÉ]Ñ®ú÷ú¿H6/’†8ÛRY¥>j¯¡%I²nd}^0ì)ÁõÐeÙ¡å~=Cgó>f;§ÍÉOGU¯“sJå@ÅÚtÒB÷@fM!ɳÈ!gm<ƒ "³!ø3„2"s9&Eᔥëö]üÌ×iÇÿ(«ØFÕ`N àæº,ø—P´í*¤YbÀº]Û ÷çz~¬Œ’,П‹ú(³µ”uKKÇí2Ûà j¨uò,f[³ýÒìx—>s òvÊT5¼öõã»eþrâØ$˜§i–ÚŸ”ïKÃj€7{úp½Ç8KÃøØØñ­·øÈ‚6‰èŒæHüÒß ×eœ,3~R¸‘yù­°…;EkÏÀ_pã¿©‡YÉ YÔÄy駈¥õdµ(!TÎ.¸K¦wKÕj-!”ï{Ÿ¶¢” WïÁòû ]ö¡û!—mT倗ú"ƒƒÊõšP z² 2ËñÈ (äª%Û’ÐáôÖº ·œÑþõð<á(t?9õÅmtY“áìÂtù£:ý-Öí’šçܯD<Õ½  Ažw£LÁ¸™Z]‹ŠCë* VùÜ™HrX\öc(×f^½bþŸ=šnáÂ@°Œù›‚QÁ¸ý%c¹úqÞïu¬rl aa=½pó_Š<ãÌá·†ú=+îÈ.Ý(~Bì.6ÇFÈa|Yºe)òÔ4è•SA?¢ÎŒlŽ0LU~t®¿µ+‘ E¸`bTÈO2Èf ·jÉiàw‰ÀŸð`¼yÉ‘`£ÕËŽdåí.'GÇí>ö⊑[ã@ub¦1ãt‘üøp‘‰LÁD‡¸ÓAÿÝCGùNÚËpîïåßaDkžih[=©²æ Ô”.Õ; sÔÏñQúaØÅ-ÿÜóáÖ˜4öá¾ú2‹)³!‰·‰F™û¹p¥Õ-tö¼yEÅ,^aM¸Èhø€ ¡áz6Ô6ãç®EzCå jrÖÊЧ.5ïF‘À:f•3âíÏŒ4wÕdDãÝ]ß6±Ô±n««]»6ŽLSÒÍVF"%M#¥•ITŸ ‰qftÉXª…Ð6"¯6+‚ã¯w¾7õ¸æÖ@ͬUhÒýI} ™~—é1Å/&®Üµ÷ iK©º®?–Ä >BxgýF…6‚ÞD×a¢Uº¨ Û<èÞÒ-9g°vÇ;õz+ñ*û¯°µ;ßâù1ÝÇèi¹päfþ^cŠgá"AÑC;âòÙˆïnù¿ iu¦WüdÞ +"C¨v)Áæ­ÐÃvÏ.Ý:ûKöhE£ß9CÛ ´u­;’in%»à‰Kù}t9¼¸wÌ3}º“«¡Âãð—ßÊžgM©7 'Z# ’ô‹ý¸Þpy†`J¬bÿ&3Rw±?qίí_ß“ ïS‘¦’ãœP25†~<:ÙõŒ·yIOkˆQß±íQ~ŒÙvtÖSòóCš j¥hXÆÍïÕÖ^U4´µïº+Œ8Éì\E73Éû霞ž²Rw^÷Neórû»:ÿµWê×¶luêeimƒ5]z)âŒ3dÓí÷¬u–iÆmªMl×<ÆØ±6n5ÐêÍ3Ö˜lsx²áûRÒÎÂñ"–¡ ¤m4x{þ©õÝ‹^SÜ´J…5¦[íçRvÇü¶&bòönd~qWò.ùRÄ€áÈÄ´#Ù&4¨«Qg[žŽàâLTƒ–~{ÆøO{˯~„Ú> stream xœí[Ysܸ~ϯàã*)ˆƒWUj«,kíú”¼¾¶ü@(‰ñ\;‡üú|ƒ‚˜í¤’—ÔE°ÑúF£I‰¬LÒDdU¢ÊDäh¦ wžHjç`z–IžV¸«¤÷,)Ë÷<á©X$œ+Q¢QæhT R$¢HÑ(€Sð„KÙ À¢ WÈ…B#'ä,áYJȘ9Ë3ç)!cæ\2fÎ+ —˜¹$H‰™+E\œK)ua ™$K„Âô‚ˆËú5DOI Hj‹ž*Z/bAÈ £°ž,FT2‘¥äh¨D …n•+jähت bs©œ¬ª$*K$ˆËIÄ2åI®85D’2…KHW¢»HÁŽL³¤ ê$H)æi‘EFÈeRßj)sš™§IYa-ÉyRå˜Lr‘Tž$—h@ÆëA<’Zt*aiWrˆ:Í UÉ!ë´€R%‡°Ó*C¯€´9ˆÄèÐ$Ô„E1ç„Læ"M©k@ ˜šàBKxâ0‚a HœÆb  Z$Ö¤.)ÉX2¨ZJ²–ŒKIæ’’ìEdÃJÛk¨Bãa U ‹52®çà TÂJy¦ˆ#…5²ÜHPƳ¼JÌ$òœëÖ€†kä’ä¯ mXM‘]j(2Ì\•ùûßv?!>Òäzí"¾ö£û÷ûk?;ë-žÅµBH£Ïã‹¿{ýë‡7¿ãùŒ‹e<‹¯ýâþÓ³G§Ö ž-c,>5$¬Íþ<Ž2§ìÍ«7/~‰¸ÑÙ¶ž'?ô%ÇG ô |°Ü¡¼ýÖ^m’?hSÒÝfzƒjdmàÆM>zQĪÐ,õ²¾i6nOYÓ~÷þd¨&öjYUDûd±›Í0Õ]Ø*›T`n$vQLò|,6/² ¯ÆR"²tB9Ç8lÅ«I‰Le$¶L'éh™`ÿŸ¨l4—™š`Ó+A‘MÒb,6Ò¨‰D~6;-&b Ë½“¢•q9©~ð¯t㣉íõuF¦Þwv S¿ž‘±æëtVÏöçn¹m®.gäUìj9›Ñv ¡ÖóU³ÞÔ‹+‹²non!Ï fÖ\»¦Cpl5Ûm6]ÎçuÂn¿­n›€·Ä›Y½¹MØ?›õ2aËd¹ý‚ÖövÝ }½Ü­‰¸ÏhoÚ¯øÓ|¦ÑYsÑÒ€ér¶\P×¼µÍY³ÁŠÍŸ;ÚÝoÖM *qÄí[ÊÆÙ)M’=‚*àa {KG €ÞaBÈm‘Ð@ {•0hìJIØïÈ%`:¬ {Ÿ° »\×ÓOÍV3ŽÝÝ=î÷ÙnqqM—ëÆÊËÈ¢¸é,‹ ÂIôð„} ƒÀ ¤±ÂЄAà c‘S}NØ—„A ß ;:Pa:l «z3mÛm;»jLæ4m×ÓÝüzÖ|¥SÑ^±†÷d(Ö™w³¸"¥à„åÖõU3¯×Ÿè M²^}³˜8D²usÓn Üæ gl²«›~…“këénÛ ¯ÁDK×EË=BvÝãGçP]ØÕ.@‡þÿ_ÿþõñ¿$KZ‡Žè"3Å ynª`d>Ú\­ëXS)ôªÖ´´+eÏ.üŸë™eiã*íäîÒTÔ´~ÔÏiŽî¼’©ñKë·®­ý—|Êú%áR›úÈà5.=;<ò=ÉŸG3âOê¸Ö„”¼ïè¬ÝÞ}x7ƶKÛvýÝrv¯Ïº¿B @`£{&ÒÐÑ쇞NAÊ=ô\Ýaf©Mõ"æ EÌE§¢Ô7Ö\x¹×¾J÷š'aÞü;:þ1kq‘•æpÑY ¾·/Ò»èîvRDímÛYˆ¯­ÅÛM:«²ã|cQyÕiÄß :Åz*ìh·í"·£Ñ—Ih,ŠäMí2¶+Æqc)õùnÿëvœÌ35½”ig¹D!›»ÏVÇž·^A¯;мS·ƒ±0ÂõüLe²3 ç–ýl)OáEl¹á_¾ù9N]D×Á>ë»N\áåoÞþåÔî«ÿà•«(ÜœÔîo¦tÞÌ$؃zõÄœ|ò5séÐø“9[àDÓì{œÐÏê›Mb ¬§§Ë¯8êÝÃIáIœsnÄûÑô?ng”œ»Ã* ÏëyV³©^ÚNï/n€|cê‹m3“€CïlíËÙ;K°’ÜGqdއ#Yª,KT9 YR<ä¨_U8Ä‘úOs„³-mG²”:-áL9Ð’{™´ç©Wö÷YJCDÌÿ!œCŽ"f— •ä¿À‰2„HófHu±A×tuAs©‹¦$AëbÅH¶;Ó„¦)B®{Ŷ8×?`—´îa®/w³Y³ïiU®ƒGN/Ÿ{ìÈ2d'¨\p5ª¢~·"EO‘Uö,Õì’MÙƒÙ »e-ûûÄflÁ–lÅÖlölÇ>³/ì[o*žDùV¼S~‰4±,x_‹EÈö¡BzT¡<åw³_ ØÏúì>û÷Ù){À²Gì1û…=agì){Æž³ì%;gì5û½aoÙ;j_+bõb»¬×~I«W΂L÷¥$Su3;Dmꃸq"]zƒô÷ÎtãêpЇ©vj¡j›C;Æá´Ë­öõD¯œh·…®få µZ» uÙMûÕ¡ð½ûœ¶‚¯ìûçЫ©V5.`Y«ä<ˆe¯>ô^4jêns€™~¿9œÁŒ¼¶þÑW ùŠUÔ@Así9w«… ½F™w‚-æœ1z¡˜Õ Ø{‰Ó<¢“õÝ{âPÖU?˜êGOÖäx!íßàtÆÙÞöäM’6õUí=9.x#c½"‚õe*Òêéæ%v%úÚ…~Šå}ã•¡X|åg#Ây>ç”@zBE>p4žýªÅëbÚ« ª½g(²¹¢òþ…Å·#±Íó‡®ÌmôebšÑš mæ%‰¯ÂYD‹¦þí)ÓE8ïÊàcB^¯l߯Úïß+ôâ¾:?.6ºR¿‹’y‡ƒ¤à‡öLmiúsÑŸm{P¢‚gmC#-Wu'ô/õz¡Û Ðë¬ýÜËU³Ø`«œ6'úñ}Ϫ]èÀ÷ õn£Yô„ìs³>ÑÅÆ=ÔP@_– ùº½Ù­á²dN?Í68›- €$3ôi÷QíFµ‡7L[­ €pPa?m ×üJ¤Ñ.šþ Á¸Òp²ØÍ/á&’üs8€§±u•vMûEJØ’ßwùË<Úƒèªdí¢Qò žd1ä±ð P6$‡]’ºd´‹¢©ŒóH!UfÑ.Š«ö£³‘J#™,LæGy,iò2¶.q/¢Üó"Ê<ñ.¢¼ë"Ê:q.òqìw"ô·º²_ù=Ķˆ²]QO5ìd¢y¼ƒöÿÈdš:gï`M !)+æä†F.Žm>r6àñˆ¡| è"]Åv,t‘®dTW‚tÛnÐEºŠm7viª2²˜ã‘ðØ^†)+¶—áGÊŠíeø¹2ª,IÊŠíD†H.«‘Læ&Uz”IÒ–ŠjK’¶TT[’´¥¢Ú’¤-Õñ˜Fy$¹RãxT|Àã‘LÆàsU–"e©¨²)KE•E I£¶OÂäQa’,ù¨\MNúYŒ²ÉØaI<ª ÒèB™Œ“J•Í8y1`OÙŒ“—ñQú:‚AeÈtp¿wx9`QÙŒ“—qIQåÀ•Í8y9° e3N^lÂÉËñF™ 2€´R‹Î‡9²‡¢aR£LÂɇY2 '¦5Ê$œ|˜×Xòø˜ÄF™ ²‡· ‹Î‡‰2 'fÊ$œb˜¼(›qŠá.ªLÊ)†i¥OŒÉj”É"ÈÁœÆ¢‹aJ£LÖ)†2i§&4Êäb˜Ï(“xŠa:cɇ³™U}£‹w¶ä.®WºÓ¸Pp ¿óÛÖ´-méCHÊ¢7Š„søü¦q„#­ˆP¦KyþTÅë‘¡ x¹ Ó÷‰€°3ÿëäÇI"ûÞ4Óm»\üuY´ýG Cv…»n¤« €ÄQž@]- –ÝÁߢÙJÌfw¹Ȱ¾ØÃ•¶þìAµ”‹ª ¦eU¶Šè)àtÐ)êp’ “-lëË™­õx`*+œ~—­ÁĈÑ5î =èÒŧ2Ú¥a•ëQ'Âê‹ûo'{“6~I’¤ @ÒF É»EWê{5Á` =¤ÒFi〴RŠl¸FXà ÏÝáR–|{ÐöT!Ý?ZÑÈNßq 6éi° =H÷ÿˆ6 —6å–6¿–]`›,v±<\Ðrd JÚŒXÚôWvåýXXíÙk0±Í„¥Mn¥ÍC¥M:¥Špà[@lî‡ÍˆRuÿî÷/æÄendstream endobj 257 0 obj << /Type /ObjStm /Length 2303 /Filter /FlateDecode /N 94 /First 832 >> stream xœåZmoÜÆþÞ_1ß"£ðrß_Œ €UIhôuZݱ>‘’[ÿ¾Ï¬$«’Î1R´ù`ßîr´;;»óÌ3C'I’qŠ ÿh ?†”Møµ¤¢Å¯#c á<ÙhðÈññˆßDICÎKR2àW¤´Ç ^c&©Ñà)-d½å¹1¡w¤œåGÈ”7H*D~”H%^ “jð((ÒºŒhÒ&bž`H;­‚%XàHG<7üÒs›ÒŠÿ °Ú&ðö$žGV5Qq‡ÿÓd¥Ä0¶je¶d•ÆZXÏ*Þ`„%´â‘€†ç‘HÖHIhÀª&I²e§I‘õó$Ìð§&aæÄM–œ ,ãÈi U“'X…rŽ—H ˜Ø¤D.` hG.âÈ,Ôu)ñˆ&¯,òš•’–¼-;pä}Ù“'<àø¢d™ˆF™'¡•-l¤åí* lgì››Í*CÁynXœ:4´P»Á<Ê,WlCQñ*Rä÷*Q´|o´¤è 8ï-: aì6:6’6½á‹FäG8@ÁÌ!ðf޼„ÆÌÑófNl h naÐX¬a4%iyÄ Á‡f,%ÅÛÁ2Iñ¸³šGžG"áLx×™ï¼Å‰­naÙdÙ,¸¯Éò [ÌìŒý×_RuJ'«M½s/Ô ª~¤ê›îmG_}uûôgÒ6ÀËÞPõ÷ŸþAÊX° C(¸C»ßnéŸ,~òzÛôùÕ´mÎûº¿¦>ﺡ;4¯ê¶^çž.»žÆM¦n—[º}¿Êôú¢¦¼ê†ëaÌW/ž.{ÖŒXá±f¯éNûfÌ¢ÍïÇ®} ?Uêú ¬ù31J(žãëÒQø‡Î·T}GÕ›¼1j´l$Œ`¯1J$Ï®h„Ã0¯¿?¯w™ª¿4í;ªÞ–öë¶íÆÃ*ñov¸@-\\Á® üî;%40G« .sô:oƾ—˜JzpÍà²B32¨$€HÊIqÅf¨´ÎíØu TÒª©¼‰pƒS´Â@€ˆPèÏÐé"Ÿ7õ’X±häÙA•F/Òh“·Û%6‚M0Î¥(ßô¨…Æ1za«£4‚ {óÝGÕØtíÍÐÉfw¯ªjÕçzl~[_]uí º~]m›<"ÕùõËvõ²½¨¬Õ‹ÏlD=Ý c«ˆFË·)ÁCÒÄmœuíXvr$Åå¹ ©F¸í$tômH§Ån;¸`^Þu":ö¶ÃO¹Ã»ú¡ïV?fÖ¹úáô šäã X~[MÁV„Ixw­G"ñQW\x0¬‡âïñûºÜcPaA  Ú! *†hÄJ8Rˆ«ÇyÖËíÀI:©Ò}r% =Ó!/Ç]—3WrÊ f‡3¼½ß‹@Ú‘@#´"EæŒNX&ló5ÚÔWÍQVK–h°Ú0«¼ ¤Qr„ÈëÕ,d\msÝ7ízÓí‡%ÑVÛ$8w­9ºóÂç­ ‚©úqª}{Ùu#äGÄ긫edBHã<Å ðKD['’â„# ëÕ3ÂöÜ98߯Þå± v½Ícî¶õùP ùê—ÜÖÊÓÀm‘$ ‰ ·á€³*¨æÞ¤K¼Ì@xÎÙt„ qqì’“HŒKÐýç5éº7ûsHX]u ¸Ì ¢\5ðÏËZ/g§à]Êqö)…<šªÞ[Ô,°¨u —¡4‚íà”­M弡ZÛ£,úl˜làÄœZ"N ¡‹jηé(Çy Ó";)Pg& .9‰EÖÁX —æëd—Ø)àŒJeóp#0‡N†cÙ|Ü"E6Æ…œ¨„GmÒ1$¾@ ážóþ—¨êCºˆvª#HçÊâX‚fðFVš‘ÂCÂ^#¨º‰Â3®‚<6ÇpS7Uø!Ø5»%ìÁÀ‘”åp'8ƒp|êfV®¾4åC€ÓŽ©\[sÍÑ~˜j)!õ¬T}¡‰kL¡â, E˜ˆ+Ráf)Ôíê«E¾x\ØùT\ª+m‘\h5K¡¶ù°Dðvz÷Q!ðve—èsÇÜæ«Äà‹CúXƒò@ ;§õ ÆÏWxs¿‚ÌÜ"c™ qKà”8[¦'Q"ÜΪ~®ÛzIúª"¤å*¿ü6D%NK!_pi~†Fu¿'ŒŠ‚_ê¨BK}8âp†^èÏIZ¯êw‹JÆ3*@*¨·fHEbÅ9+Òk~ƒ17 XDÛ’.)‰uøåW>¥(R’øœÆGi—J^nëv ø¨Ç<ˆ¦{Ù´ùÃ’ä p3Ñ~#S’«ã*¿7°›†on"¾}‚Å)l ÆÏÈþ*—~ùõXØJÁ_tx‡“5i¢0®¢ô“…ÁUÒTa -¿5›& `SîPø=$¬6cõ!a ¿W“…%@b¢°K\Þœ*-âÌTaø¦1S…}üiØDa)øË©i Ûü…Ñ4áRX*l&¦Þg§#rÅÉÂH,íç„oÝ ´@úÌÄ÷ÅFcÕ ƒ] Ñœ(Ì^ež¼ÙÞ›®§@ü×=»ö)œ¾ÒRE©¥ðÖþQª/¤üâNŽÿæúÏv]?ÒM©üû|ýx:”¹þÚ]|n ÙÅ~ø=L‹Ë>çMÞ‰u_ï6Íjh:±»¸?è¾¹Ò§·+iÿÅ Ì ½mÆm¾iAl—/›õvȼ¿Z%±endstream endobj 1 0 obj << /Annots [ 357 0 R 358 0 R 359 0 R 367 0 R 368 0 R 369 0 R 370 0 R 371 0 R 372 0 R 374 0 R 376 0 R 377 0 R 378 0 R 379 0 R 380 0 R 373 0 R 375 0 R 381 0 R ] /Contents 2 0 R /MediaBox [ 0 0 612 792 ] /Parent 266 0 R /Resources 382 0 R /Type /Page >> endobj 2 0 obj << /Filter /FlateDecode /Length 2891 >> stream xÚËrÛ8òî¯Ðm©* æû‘[&™¤f+•ÚñeËãDB×ɤ3ž¯ß~zg.b£Ñh4ý„üÍqão>ßüts÷)7…*Ò0ÝÜ6A«,M6i‘¨´6÷ÕæÁ ·÷ÿ¼ñe­å'yBKbUÄñf*Î ^q¿Í}¯Ûîb?÷tU ÆZdÞxê¬a|?tûÆœí-Ït­à»Ç“á™sgGFµÝ¨a £Ía&Þ¡F˳uëöpœzӢ蛓1ˆT˜±ˆ¶›†Ã$ñ¾owh*ÆžOœSÕ¼™L;òÜ—ºþp³vêý6ô½i¬»Ö*&ù¹Óìµ5£»v}‰ê‹¢zTFei£Ô+»ÊÜ2º©ŸPtÃ£Ï \×1üd·Lß Œr¼öu«‡ÚØ©÷ÑìkÝ ðQhàvÞý|žv YYÔ¶)e©wÒxªçmß,ñlÝ’ü0Ùtí‘¡Êèfäùï +F²Òáy‘º|ÒÇÚq(AÛ F¾Ûmà½ÀølW$<&’ðÇë áÎËS=šrœÀXãîùúgúß}?,§f|a,‰_;•'†FmŸª-KÝ#ÇJ°­Ðcïî\ó•'EA¢²(©IÜÊ€ý²¦wnêú8•iËæ³ôÈ0WIV86p蕽‚PÁiÍÇ/_X²“iš5–q¨â4pä/öÝÍ—>¤d-IäéVÎK>}QUä*Ÿ&ÝFW¬ È16`ž`.vÖ%é ”‡ ˜¶bSH|Q®ïéµã&*üÜÉ¿¶1˜Û}»vÞ(Ty:ßXÞýq49*íSMü·ÜÔ8bÓBåŸ J˜Ó¿†(Îg3 ûEaì:4­ïÙa@8ߓ٪Ão„‘ Ò)VŸzYn“ç¯6k/LÞŒ”Ì×0 ¢ðÔ‘†OžvËsâàˆ»J¿0ùÂ6/K†¸ÚîPŒ†Qe!kËäWQ0qÒVØv#cœ—%\¬%P[Päb5é¾7z@¸€j"ñQD °7h}¡ ‘ ?F<µœ)S ,n_ÛCå²`T\JeÚöÜMí‚ïUq쯗Ũ™+û„¡„A× 3áò¢GÅ÷§ZH¥ ~â p¥–é5#Å•’0‡ÕÜD58PíÛ”>˜~+dÍûѹÀhΞ„ypàp …‰™—B$†Èê–ù,ËqÂî¸NìÖDNt€À¾MsP<ÿK»à €)OíjD(Ù£1Öõ á-da>o( rZ‚6Ô,qóJrUÄôs¡Áãý 'I/Br»J…—õ+†Œ-¤²#–î¶mI£4˜Æ`Då9©ÿRv¦kÃzUÚê­&G.vS»rε´ÆT×{ƒ‚­ÙnKaä; 1Fɳ1éãÈ5¤s”òc1„ê–É¥Vò]U…Ý…¬r¼ô4B=ø› S:f%$8ÎÚÍ÷T&ÔJ9ƒŠ"Pß·©æ¸èJš!ÈS°&•“nº#¸£‹.Žªÿ :¼¦yÙ¦‰wËZ– ãý ØG5±åÁôjª]8J³óÆ9(*’±.)e+ö|}q&"]Ú“Le±_Pç‘A+“›H‰<Dk%x¦?ÎçB&¸“ƒƒ7Õ€!EÅÙµ]ÆùÂî$‘äPÙËLáÑ¥GgÈ‘(@ƒÿßÅ”˜£F”gPÙˆÄDŽ_±.hMFHå"=ÿkýpä,»ÖO¼¦ŸTÅE¶ÐÏGx‡ÑIÙRñŽ(ü¡÷¾©Aa : Ý™U™LÅA¾P ÅÌ'_ä>ið«é;[Ýð2ç¡‚½v+„.iGd-?•YG'¹ê¹fǼË|󼞠ZÜlË_é›ÞH»„ ¨Ðë3FÊà »qâÒ Bò2EUˆ{íA|ìw'¨ ¸Mæ×Ë´Tà¸(…¥Sš’ ú£?q•ÈJ[ã;B”d.ëáÌÞ0j?tÓñ$bR\IÐ¥F1ŠK³$»:§"ÆRXÕfjŒ'_ô·~ªÂxîÿu3¬Z"4Íɵ!&«o*J‹…!ÞŠHòúE¾J‚åãÅœ±8xp.¤¢…êĽœå`6ý$µ R òÀÔvMÝ^eKË {Š¡&båØaœ*?ܱЭHÎí»Ã¬0JTÎÚ³Ïí›lÒ ’ÐŒ¥’t/i’JbvÀ"Ÿ~õÈ]ØàTÛ“tRû“ß.KzèÍÜ+Hxú‹@P*@µ‹º]WZ@8¦Ò=\Ü’á÷Ð5âö¯¸ô[0ò‡_q4øŸ‘u,"CÔ˜ôeA-_¾î·*ý«~7ŠÖ}WSU‰0;"ƒág=‡×†Ü}í(À|ƒóapÉ&sñê¶Y©<+CM+ä[]u=%ðn© -@zª-Ã`ë+–€‰ÆÉšc¾iZŠù}e½cNÇáå00ˆùsuf„JÞ Nï/|iªÀ—AUž™àÎÎ=ÄAàâJŸÈ÷ÎPéê¶¶†24\ żœ5 ûžq{¨]Œ{‡¹Ôés°‡/öܔ³©-þLA…QNõê)§?ó<çÍ~“ ôƒL1;yHè5sÂ*½—TvÕ?,_Âκ2îQÿÇ·|oçŠwá;>ì~úÏ6o÷õÃîëGÆÆÊwn¥i­y7›Ô塯ü‚ì È.&U‚ݳAãß{hÉÂÇÞí_vÛ]xm‰_¨¸«;ØìþB ìÏendstream endobj 3 0 obj << /Annots [ 389 0 R 390 0 R 391 0 R 392 0 R 393 0 R 394 0 R 395 0 R ] /Contents 4 0 R /MediaBox [ 0 0 612 792 ] /Parent 266 0 R /Resources 396 0 R /Type /Page >> endobj 4 0 obj << /Filter /FlateDecode /Length 2843 >> stream xÚÙ’Û¸ñÝ_¡·PU‡‘~ózãÄ[ñQë©ÚlͺR‰‘°¦H† =£¿O‡Òp¼yÐÝh6}¡­«hõW?ݾºy—%«",2™­nïWÉ. 3±Ê  ±º­VwA¼þzûË«Èí éJˆ°HS‰;¶q…y’®¶²“¼à=r½Q¿êZ ºZoe¿­wiÐöß}ØDiž"›ˆ÷oÚ{Ô°GÆA×·ûZŸxÑÞóX›}¯ú3/*c‡Þì×2 ÆÁ´ B“à¨,£÷Z7<Tù­&Y`a<ða-¢ åÅIy0AÕÙnxÙ¨“®Ï(7 *âPîXÎçãˆäŒcìM£z£-CUSÍÑQ`Û±/5“–m¥CÓÙqrßö'Ý3žÎƒÀÁcUõ}-Sà:¨ƒžÏEt÷g;§Ž£rä sÉhá Ilx¹×¥.²À ´ Ï÷}-Ò€Î2ßoÝñŒNcÙž:·Úrë‰:Ѐ¹ªëå° jeöiFÌj=Ð ¾ªLÝö¦90’¾££ééL]M$`>¥¶Öѵn_£ÿ¶NÓÀò.°PÀwÓ·ÍI7Ɖø¶`ÒëíÒÅ%ébW¸Ïïr6´o×­ªxƬ€à¨úŠ-«×ŒêõGÓkü®ãF6´h‹pÞF÷6dÌ;¼º@@wc¿l‘°K÷]¯'¯«UsÁD,/IZœ´M}æ™»^4&¸8p7;à…¹Þ¾àv)›6ŽlÚ 9 (’°H2 …ÈYÌO Z~"¼3“—à’Tƒ“vOǯ6¼|p`«Ý䬜È'Fh×Zkö¦6p|Í0ÓØÌM±˜Ä›e;Iö¤¿¢„ÓVæ½h@ÐdЧ탩ô†qÊÑŸ‡cÛ8§åì‘ϳGš†…Èà›|…¦[J12 Or'â¯æÍ1&tG ¡äÜ4‘€½&Nå¤PXêv˳CÞóØ Y‘„»ìBË“"°c§{R ,dØû{q;ÄŸh"VΦ4ÖªgÀ<‚'ÅÌ q󃻭k^ÐÉ\|Z>íœ8NÖºYŠ€Ó’àFyJ0<2NÀ€;´LËL¶8²Öüá·H)æFE€+ëñûÕ°äl¬ò~CdÁ¾o¿!OípwÙWž€Ã6LRéN7•nJ¾yÀñÍÃÄœ £À¥ÑeéI5,0Fz˜ M-e5ô*çp‰ÊRÈ„¹q0а„aO(ð¸ [e* GÊÐ8Qí ¨Z¬qF×!Ae¹—^¤—] ™rYî°¹ñ'K°3/°Ü:¡*áä{8aeí.êÜ £Œ#9)~øâü¨ºŽzh©¸Ù×ø‹^œFtU»"8Aµ‚žWvÜ;¡ÉÇ#'#É·}?…¨)ˆ"ÙÌ™áΊ$\ÉÁì*D ŸÐ›½7å’Sm€Ú‡¢ó]ßžx†¡ž&®Í!gµ*®@§ØÓ£Íù6Šä…7³’$œ`0-š»/³xÝ/=–g*J2~ÅàŸo27ø±…7Ô†¤g© 'Gl¼ø<ËÛ¦¸AhÇü¤*í6ò@Öé:ø±vññgŠ šu"Á>·©b¼9¬±‘„’‡)³Ð÷-¿2b®,J ÖÜ~Äö¨†’nÀHŽèÙýºNè_Ô÷t—™–j˜|mªN>„§°û¿J:äɵ÷Ó8 wâ‰éC(·<âsSÙIL¦†Ì¥ÌÂd*åNêOOuUiÓ8÷d—μÉ%§gŸ™{sˆ¥„kL²4˜Y¶."i˜ÆWÅÑd[èۛŖ ” "žä^ÖCžN"“(…ðyìZ rÆñt 'Ó¼¨†¼H—ÕÌŸÔPLn `þ¶|¦†B^k =ÆÇj™B%*:ר8ã 2ßgqP¤6Ý 5|,áÅ1égÑ4EÂûk®BüŠZR À¿+“]™('•˜„ItQÙS> ½Àiéà›†‘|d¸{vúöàÔH<¶cí U•ªˆòË,G^Ÿo>¿çÉ\󏿠3NÒ‹*Ëç59xô }À´˜:þ•2oßÅŠ“ë6@¸ _Nói2†|é Pwr§‹ÿ7 ÷¿Iú„%±›Ì~¯KL ¶ìMçÿa ÷»KRh†; »aÀ¬YÔnÕÄyËÍ|$µ§µÿÍÁ/_>}Ü,EÌø×æ²Òzú[À5Üå/×ë?7ƒztÿ ŽÚјá²q0û/^ÿPLVYXì |a¸ËÃ"¦Ÿyî“L…„ÇwÈœnž'䇑uöBßተÒ?ü×áßó#¿}»ýé÷µ"Ø~|»ýø3C“0òí‹R7V¿ž ñé 2 £Ì{§Úã0t¯onÊ^ƒMלmØö‡ÇÈÞìÏÛõv'‚¦ÄQMu_»¹ÐÖßo_ýì2ðËendstream endobj 5 0 obj << /Annots [ 398 0 R 399 0 R 400 0 R 401 0 R 404 0 R ] /Contents 6 0 R /MediaBox [ 0 0 612 792 ] /Parent 266 0 R /Resources 405 0 R /Type /Page >> endobj 6 0 obj << /Filter /FlateDecode /Length 2657 >> stream xÚ½Ërܸñ®¯˜[8U"EðMßlmìMj×q"ÕV¥l0$4ƒ˜$f ÒÚÉ×§Ýà<4ŽS›JšÆ«ßݯ¶«xõîæÍãÍÝÛ"[ÕQ]$Åêñi%Ò,*‹|UÔyTÔbõØ®>ÙúóãŸob^+ò•Qç .‰WaRGYUqºEÇÁÊêí°“<Ìæª™ôZÄÁWü§,áåа‘V7Œ4O<îÕ('m<Ý]ó*÷‡Š(¯:ôíZ䙲:¥UTV8BÙ×¶À8÷D·ë0M²@>MjD0Fµ†ÿ_µžõ°%Ši§¬"КnÆËÚ[ZS4ñdºÎœ/kU£-Òé³™v’_{Ü“WaZEEU¬B‘FIIW{‚Gë<ãp-B½t?÷ôñŒÛ˜ñ‹;“1Ý««bô,(¢,Á³J`WJ‡}J’ârÍ9Ûâ(_Xûˆ/NÊ£´‘c(‡ˆ?°N†(wªÛÔª#ygöDfaPŠà €É½ ž{K“›uóDËÃí,‚Æ/>ÅqÛyä{Lþžö`'ÕGŽ×ñ—_ã=«<°s³Ããª,Сžu׆Δì$=¶1ý^wª¥©NoF9jey5LzTÝf%>á+þ3º%Q L²7ÖêðÊ7ºÓÓáÜb6£’'"ß±fÌVXçyÀvòîojCH¢ E¥Eò»Ôa]Å(‚TdçEZT;­~,’á;plL«ˆj²Û¥³¼ßf4ÞPÜw«öjhÕЧqå_>¬ë$xý³¸Û`“ûÑÈf·³¸ ´¥XÖ"Tƒp ó¼ÓžèDUÇ¡Zm'=4}‘Ôy Ä­$z‰ãþu`'3Ò pÜ|$P^¹Þ<è_g–ä {§þhÿÝ´3óvG_z¸¹J‚xÜ¢àŒð0`ÉÿMüIB–’&)ˉf q?²§€rR„e“?M½?‘vzd°‘`wfK’6N½öŠYo™–½d¯—Rhw%ìçM§Âý²Bà=´áÙ{3L£éhúÁÙM|Šóø—û!ðºñç£3!¼dÌ;=ý8on¯ÜêžÞÌ éøÄWS1ø¬'<«å™ì!p²:X3×Ó÷ KÞgh»8‡Ö‡ˆóØñ¿Ö÷Liz**ørA °)3î äNFƒ÷DÈ+Bš›¡z%ÞÂùÜŠ†ýŒšNs²ÓÉn/ÙO¬„ùE÷¼±}9¬ 4 @fÁ\‘‰§c*nË£$š^³ìÞ4ÂÅ$˜Î—B  {ÞŽßG×®ÜÒ  s³Èx° Ü‹”“„ff½ÿ’A¸‡ä„SÄQg«2»ŠN(®åJ¼†ääHö=M)³¨‚œâ¿Ð•×h{1Z(Ø6ø…ßœsh ¹xXGail•mF½ñ4³¥ì À×-êD¼8 @M;Äérö>³¿‡Ó2IË®ÈU®H9 ó Ø ñø, Ñί¤©0í¡ì2E¼BC‰°Câ7,/Hå³—#cà:§wGÕ¾–%Q‘UßÉ’“4ŠÓÚ-Î¥"VF”¾P8©{N,!œƒ²¥Í s¡«bH'Ä@6Óõ¼—¥¹ÞùPÆPŽ\CŽ\žtÌ™6»Dý?á84YBìGÈÚ‡‰> ¡îo‰à[¬É’(/Šïñ&‰’ba ¦Û´?© ÇÍ—xrÙlzù¡sÊ"ó~ýxxWÆ“fg|÷~æÁk™ɪ?Šìóâç1ýƒüïòá‹aþäSQ‹Ë$‚&âÁå@¦ÒµDƒ® GW®@Ö| Ýïeã|Nº*ðÏÎÞ·\ ­ 8í\äµø©1#.sò¯%¦Ž]D˜Gò´%«%Ò@~trñ–fç<1xM'= ÚÏò,s–'¥Vxa/eS¢¾,ˆhž­÷å•1{x÷áoh»5Sq&ßÞÎk¯c%‚窠C¡øˆÈ>:ØKàü9y ÕÌÌ¼áÆ€®¹g¼¼Ó’Ⱥ`2êѧ Š´y‰+ÇÔ§hkqTC©B-¾4È ‹œò —‰ÜqAn× =ðóE0åT@¹’\ùPöŸ;—”ÄávΆêä°åVñÖ­kHx²‰sµ-²¨ÎÎ ­“® êÂñGÙšýä„.ê’œ¢!êJ‚0 àØ-£ߣzKø¢øL !ŒïŽnÃÛÙyÓë‰í¡Hß‹ãqðäðšw'Ë_B%UESç–4lHÙB£ö.:a 4[…š@TÌE9H>«® […ªI\ŒÅ±ð¢*¬\Ô)8¹1G+w8w®Xuì¤%¤eA"ìën eCF¢_AÒ½Syüâ´AÍ[{z~¿ó„Toꎫñ’”Ør¿€‚ØŒd ˜„.>Ý?{ná0Æ5¸¸ÿù ÿQ|Žh«wúR/SQgù©€*Šòe´–V,a‘Š@Í(IÃ’HL%ÃrÔF˜L€%fd±k~áiP@º à Ÿ–¦ÎÚ¯x]a«"x÷á'J~?`Þ>¼%Œjµo“!Þ9èªð^\|- —†=º“¢”©'‚ŒK+¾“hÿK—ØnG 3k®A‘лmruåeunmä¥-Õ ¾,A^vjbæ%˜üƒbš×5çz†SǺ¿Žút8¿öô0ØÜ´úéð­ &Í]‹„úUfèÁD„e'àJDê[Ò\œñpº}OAƒ EN›-„qÎ;«ÊœkávQ¾V#Åç…ðt€³¥xÕÜÙ<†K¤v,ŽXÔùI§;ÀE”ä·#Áç{ĉaºè'/õ1†Æµ¨åÏÃEÖW:Í¢ŒŠØ·¹*ƒ…Îk¹Èˆ1a©¹\ÄÔÝU}€ü§MØ˯’{j:ݾ(âí4ÎÍ4¾C¾\úŒ+zøfÑJMžÓ޳[ U=ïÿþññæ×Ìãâ•XÚþ"!®VMóñs¼jaŽ‰ÒºZ=;Ò~•C¥P£…u«‡›¿.?!äQ]–üBѾ†¼9ª¬¸¬$a²€ó¨L*,$«¸>i!§"áöU ‰ðx¥\Q/¸A#û}— ½ÿ%ÀMR­(Ñ oÏw ûú¥%Çìú"9퓜&ÁÃ$›/hÉžó1ÀõÒB< GŽÆ²$¹R‡Ër‹A^ôÉOú0§åÈ‘i"Ï¡J_аFndúôKƒÓåBíÄð†.<¨‹,mÑŒ³Ì¿¹¦• U%‰ûµ§ª*_.ä"‰Á@h³Ç%ùÞVà{æŠoç9WsÚ€êeë¹Å]bLþ [è|ûšú£gÖp¾ù»sááûûðý„Í¢˜€N7 3êÕ¿ã+’8ŠA›Ã0ô„Ý4í_Ýݹ,ZU(ˆO‘·w¼½ÛÂuXBTlpL‚¡½ƒÃî. ê_Çn4ùendstream endobj 7 0 obj << /Annots [ 402 0 R 409 0 R 411 0 R 413 0 R 414 0 R 403 0 R 410 0 R 412 0 R 417 0 R ] /Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 266 0 R /Resources 418 0 R /Type /Page >> endobj 8 0 obj << /Filter /FlateDecode /Length 2881 >> stream xÚ­[Ý“›8Ÿ¿‚Ú'»j¬Añ1oIî’ÍVjw/;{UW»yÀ ±Ù`ðñ‘ÉÜ_-uƒÁÃ:üàB¢ié×ýë–mkgÙÖ»›×7wo=× Yè Ïzx´\_2[^—[‰õÇJ®?=ütcÓ3çW ­€° \kã¸ÌóIć´ªÓ|·Þi¯Æ™i^}zÒuÜü÷†CѶ¸ÅΤï[žt˜çV|¸ùã“m%pó'xÐ ëÉt=ÀÏaNà[™õÛÍ¿ÎD8F„ÇÇ»$Ø#"\æÃÔ~W²@Œ q(à¸@7p˜ï‡ÓgãòÌL7ŒÂó¿ñŸ…|Âî ’¾SÓn*k:W:l`yÐäÚú¹k3×qARÀl/D'x•DëgÛàwÛ2*Ÿ±òQ‹*­‹¶~ˆòh§È].NÁ¸{8>óí«à5UÒT¼k:WÒ%¼lf‡„×ï ÜãEÓ˜)ÄÅpJ°òGq¬Ó"¯>Q5*wÍAå54ÌQ„Lkv§Jš âbMgKšJd‚sûW™Ó‰’&ÏéRMçJºàÂe\èÿ޲48Bu?ÛÔ9¨^–©’¦Â²XÓÙ’¦šº™Çætª¤©sºXÓ¹’FLÝwXhkIœL}Û¤˜:ÀÖ?îÊ(QÅ‚üäÇ4k›ã¦,û±r,‹¿T\Ïõ ú,×Àq²¤‰8.×t®¤K8ÚL¸„cœ©('ßýú‘ªW,Y\°©’¦¶XÓ¹’þ0 &ü0ô*„#G¼>bœ…ü:ˆM”4±¥šÎ•t±ÀeŽMˆí@âØ€É[UÇû<‰Yr”eÏc¼]N­˜{8§Jš çbMçJº§ï1Ç!8÷¸×ã(¿í‹'‚i_ÕcÓa¨;A+iþX”‡H£<?O‚VWÁoª¤©ø-Öt®¤ øys<Â/ÍÓšð{Sª¨>s´\= =ÎTžÒz¶Ô=¨:J¢:š © ˜m_Ò©’¦BºXÓ¹’.AŠH³"þL~0EO¢Ž*OT“K~Qe¥w#æãe3ûò¦äwã5QÒd¼–j:WÒ¼¤`.,C ^e“SDü5yLžUïÕ…<ÆTÔW7u´…üg.Š®`¶w§JšŠâbMçJº€¢ë2WŠ•ŠJ:R¥Ç¤U]š(ñZ*X`T„sÔ|wt\f‡Wrª¤©@.Öt®¤ @:s²9BSäï¦ÒÆÄ,-[§„P—»³Üuà㦠`ãâ*°N•4ÖŚΕtV0É V xˆM/UíoÖÃBóÒë¤4<`\^¼©’¦‚·XÓÙ’&îYJn3\gN'Jš<§K5+éï·ç%fìôÝŠ¸ì‡Îp1g¾NÑŽý§°K6rŠ¢¥Àþ:=i[4õ æuß¿øŠ}‡]ü /mùa¸äƒ¾†Á’úß#â›ôèÑÙÄÔÙø» öà4‰´8g¶ $Z gÔu½Iƒü)„78£a‚ôŸ‚1òö@ǃNb…ëœâ¥p]}Ä4R¸¬°–Vx7ÂjÙûà­ëû¢ªU‚åâj‰½ëö :}ÂRï IO/3'mçtÔDÇòö K¯Ÿã0î˶C‘ïÍV“µq¸g>ùo¸ÃÚôý±Éþ´m‘eZ; ìpU¡FÐT•¢êo*¶c·§Fæ§ê38¤I\êD„¥Å&…ÑíT÷™ïB¬ƒB€ ”‚Ø×~óǨGàÀPNݺ´Ek£sS­ #X}l*½p€F8zÞíÀš<­Ÿ×ž4Óúzºà˜Z¦•Οt3Š„‚Žª[“øêš1èý9/ÖB®žrlîYÔ è^Cš§‡(3ªÙDÌ ‡‹Uý|ÔïÖÅ\©D›Ãùª.° L¬T•Y[™ÞûˆJ=jcØò°OIÐÓš¿™ÑÞ¢8=iM·[Ùºá¥f}£v$_Uû¢ÑûÕŽ´W[…m†juƒ©n9€écé•õ-Þ-ò˜n'JOÛ—5—+•ÇHŸ¾‚YN³ôªºÅžµPµŠ’$5Gð –‚h߯ ä¼ìÜïl±ALJ´™…ú8Úl²Û°±ÉÒÜ´èE‘á½h-l+ 8‚dm›Ñ#FgèØTæ ›Ò¼VedÌZqëÊÜß“ðW˜Ö›7M½œ#ÃNRšIÆÜÕÕ+úó“l/ÆBbÚ‘Ë-ŠŒŒhÞ½ÂØ’.œÜACß9©};"¯ƒÆW»µž•ü¨÷­À(ËPÕÏ fƒÞí æˆp0h4%á„+ã…ÓzŸ¶ˆ8ÝŒÂÍÖ#Ms’VuSn#c¦ø]QDp2+ÓüžÞ4 Óþ ‰¾ưYë(í3!;Xâ¨Ü#ÔiHß3ÔI§z‚1ø|Æ¢NêFÓ )CÒÍ—ßp?d¶ïÎñ•3g1›P‰v*¬=–Å¡eÌ´$òÔü‘¶=âÈ0mh˜G7ê‡+´ƒi> endobj 10 0 obj << /BBox [ 0 0 390 180 ] /FormType 1 /PTEX.FileName (/compile/figs/classes.pdf) /PTEX.InfoDict 443 0 R /PTEX.PageNumber 1 /Resources << /ExtGState << /Alpha1 << /AIS false /BM /Normal /CA 1 /ca 1 >> >> /ProcSet [ /PDF /Text /ImageC ] >> /Subtype /Form /Type /XObject /Length 20494 /Filter /FlateDecode >> stream xœå½ËŽm9Œ%6¿_?á­·öÐ#zP®ÇFÝ9ˆkøñÿ€µÖ")ís"UÙ6:s—Ô‘¶DQ$EQTú¼Ö×ãÏ馉||ýþõÿzþð÷¯r³Ìào‡­Ê÷¯gß¿þüõ¿ÿú?W;ÿÓÿüýýù¤ÿôÿ¾4iþŸÿô3þû_~¥Ÿð?"Wÿå¿á·^ió:öWÚ¼ÒN´ù§(üïêúîÇMòå\pÐ3=~™‚ž?â=ÿ°Æþ°ÖÖð&Pø>ŸðQçƒþÿͦùûñë0þþ<|ΗÿˆßþcäOqÙ}žˆï@än¯ò†ˆ*/“~¢Ìoì>¹ðÅú”žˆ£ Í×_!¢ ú”^ŽÁ–—ÁÆPÞÆöÖ——Á~ö{^õã³µ>û1ØñÇ5×`5­yÑþjôo3‚>½Œm7¼©øú¥·©~£ÏÏ3ûoæ¶÷™ýË>ýåÌJ¬ý5~}ü¯«ƒµ-è?üZͦÖ?þèí³¦±z”ïÏœf –º>k(é³´J0Õû£ˆ/þèõ³§òñõk!zmD\££üîh®|–U`þ,¹êçB$"¢öFÙ­¯Þ§?·¯·û³ÎÕœõ­¡ÓõÃûnàׯ<>ûuâ{#Úç] 6þ7DŒÿϨ´ÆÐKq}ÞwG¥ùy·r"VÿJÄÇ}s”)]èöE®Ñëú,—Ê[¿9¬2Î{l0ˆ¶£²¹bý»zÙ­—Ï|gPÁ¿^>[ÎÑ7 'ú.ðëu¸ @¹?çHêÿÕ¨‹?û(B¬¦XG#˜;Á<Ôÿ’ÐäB\Cã+èáüœ3 \Â`}Ö×Ïçú̵ËW‡Úµ?6ÕDÛ)rŒÅ•ˆ –쟳5Núò Š)áS^êg»¯ hÍ@X•wD"a¾Ñ‡TmŽ ûþØg8»ÀyW0W=]“°BA¿rHú•«œåeÚ c„ ¾•^C?o="¡¼OµžæèƒIÝ~~Î.&¼ÖÏ2ºrUýý«–õ›X`½5ÿu1ôsÖ*¾ÖL}ýªXÖš£~§άƒO:ÈUl?b1Ƨ×^`^|â­·±&ö¯/D[¬ë}[`Yãð¾ø…Á<ÊÛgn}×nŸ-³õö9À½þõÅר}s0ún›Õö‘[ë›2öu§\}ÒõI÷¯s*4÷¿ÑB¿Z j_“m¼µ˜¢ŽÕ~"˜3VÿBÜešlYҨؿŰîá8bR`{mÐnq¨·ÞúçXèõsûúB@Ü{ßÖRµï©È™KmìòLÚ«‹”ÎÑúZâ©ï¯¯>®Ý7£ï†ð±Ym¹µ¾)c_wÊYßœ®Oºs*–D1É 1ðûWËK"ÍC.8jóD4Jþ–>o,µV¹‚ب°ÀÁðB\½QÖ’nk@¤ÏêZ^#Xë:÷9Ygù÷F,uìˆIv dK ›œÇâÓvŠÂºI a‘Ôÿ+8XgÛ †ûõJ¡ï“hmõdžDâû¤âÝ«úè­¼ ¼ÊŸ¿°~Œq[J«Ù@LŠ·Õl_ ò~"0ñdŸ¥8X¡6°ðs8ª8½w }ýãšÉ˜oý|‰‹ªŸçÅM«‘d àúù’áרåKåÝú9´º ¿À:À|—Êa8e³D$!D1íœi3ˆNöú=‰ôiÉJXHÃÖáÕù¹¢uv_ø\3K oÑzµ[{ŠuHÙwët5ÓËÜåkYW_§‹‹;hva’T•k„ƒ] ìÜ$2¡¶ôuêŒaY¨}Ù:]3€ÖA¬S.<|ýʶN&ªõ-ÿÖ7Ç]uº¾z_[™®¯N¯½ÖŒ„a­SY‚²Õ¾^Ú‡³‘õí…Í Ö?9ë˜èß'Z¤Îjðª$õ0íZ®©þµK7iÊ”`í53•’ KM»¼Þöó¶Ä¦à2û¹dÍœ¬»õõ9Pž»,SL@Š¼Ë¹ö9®,„MËP8¸l9.D¯fý-¦[`)f®wç2ÇÔ¥Z°%èkH—uy1e“äÐq ¼ê}¨¼ŽuYvyo¢¹Å l]Æâµ¦ký|)ÔdB±Å¯¢à s0x/K*`ÝYm(û»Eë&øs­ŒÁ ‰÷ÍL ï{˜ Q¯Gù¨Y«~5ÊXëM}_”›’}É–n†0Yz~8ÝÑ™»ëçB¬5OË|!d¹®u¹¸s9Ûf&5|}Ú"ŸuXïnÓ¾ƒ”O&̱ÈרFŸ‡Àhní½vtuÖPÖky~Ê2¿le ÓwÔPÖÆDó¶„×&_×hË”"Æ¿N!Ð?¼o¶È½ï!0¶º-æ¶t™ œD³ˆ¹k%ål U9QÚ,C´Þ/+B`mØË­m"4ßïpÍ7ÕÊý"ÙÎ2ª¼" ¯üD\«¿ ”Ô^Ý_½\`»J /ÄÈÉt Ëïá¼;?Ʋ9œû¨¬W‡ZéøÞßá ØÆlö3#ð 5SBëÃc‰¨!½Pɰ2OåØa l­Kà¨áòçDAúÒûóþ Dõ*oˆfØËLɇ“á‘õ?ü‡Îßrµ6jdXÐîŒkâû׿>]5‹Æ¢ˆV.ödkÚ;¶†øþ•ý(ØÙõ±‘—d? JZ¬cmdH°@¬Õœaa_Ó‰ð_xÇÞñ•?¥ÅÁX¯eÍB†!-3 ¼jˆ´ ޼_`Zt€úFe“_¿Òb8¬glÍKúH`Ó7¸×ó(ËRAm¨½^ËÊZ­ÓÇS2#ëç뉈6Ø™—ÈëRž««i^~¡ï²ÈË—ðèjm}ˆã*Xˆ›?/´öÓR¹X‡«ï×Z\8nè@ˆ2߯´£Kj©k(–…/"æÑ[yCdG¬n%!Já(h¿Âç¶ä9e Njƒ5hØO@ôF¢T(ý¶%¾Éæ=$I5¿V¾l8˜-èN%˜±Ž×ÇRæÏ×>øÉÛêÅûm4\rû;g °I«(wîÀ>aµ^a½.êÚx˜ÿ"rõez€Ù þ5 }g€âûDÜãè¤2ën¡.ølìàZ‚¤œ“`[Kjö‘¤ÝMÚZ9 ^5W—¥ Êr…¢±K£›Ö:†»Àfåk÷®Fé{ Ä â˜’ÀíÖ..–6 æÎÅP²ÀB=êÝB`ѬÞ_ÐÔ1³C»*5vöÞÊá ÔÏóú •›ÑÊåÙ–h“×R ¾¡_øþKÞYšlðR²,Ä,FÎ¥3F¥çb•6Øô1ÒGŒí‚¯À;Z°áµî.6T §\kNî@,~¾ ò8œ X'›Ãz&!²»Ë5œ¶8$ÀÅ—÷;\_µësw®?!¢"³Ãû;“¾0–Í‚î«]Íú_Œ\¥ÑÕ ‰(b]®³qÿŸoë•/ê5MWɤm†ÁÞjM¾ãö1Æ·–ûGSg@¥÷(ü¹>ºÜe¾#|¸Ðp³¯ w¥œÃ]š6ÜÜd'úp–ºïs¸•â)Ê«<ë>ÜePÍÇp—<êÇp—€¿Žá:ÃuDŒn)ÇìÛ(Û¨ò†X 5š¢á’bk¹¯.sK‚Õ½V/Fp»ÓèË;øÇµlv_dN'»ã(ìÞ«;wí P;œE¥×œšÐÔÅNs‰Ô 5Cr½,Õ/, ŠƒÆáüÞˆÊ ñóJ/ˆ&aÝ­+w醺DˆMéVœá›¨Žj‘²†¡ß¾ÈÃúÎw9ÈH½”é¨/M`§ÞZì¤U;|ë©H§ÎÕ 8â³u†ô Dfïİ 8à^ÂÍe³¾†>Wtî´ÞÁ/GÄÅs…zß¡dA×™% F¬[IƒÈÉtú#9¦ z§€¿‹uwufq÷9y/­ ”íÐÏ…X_Éüù݇” dÛj‚ta9¢Íä¶³h“‚Ä9Ô17çáIGHسõÛŽ˜ZÊÆ[<ä-11ød3rÞ¤ƒž’åª ÀàY ª¤É¶$Aß½5œ‹¢‚g:âmTLEM¡³!"ÒVᜊrõ]Þ¸•Tí›\ÛÛ±2@,Ú hn´&–€Y,M|õÌ›ßnäü²Ý0¶ÿc„Þb6Þ`ÞÃ[Þ"`ÞbdÞÃÿKã?Ò]?!†Ø1ËZø|D¼#¼Ê?ÿ‘î¦>¥'âìBù|D ¼#¼Êÿ ïÁ¶—ÁÞ5¶·¾üCñFͱɈò£›‘3þcSÑÛ *¾~émªßèóÅü[úôW3ûÇžûü±$Þ8°ž $û‚Þy `/Eu öƒ¡äÞ8§]¾$í3v^—p]+y@ÊHs?§ˆµÓ~>¸7nþmí*ídˆ¥Ø°™¸íçKOnpÉǬŸ¢±œ®v€… Ùfûyë—7êÚ5Mh6ô½À”8›†ZK¢7³ÞæbmÈ@9/_ª Æâ`é2n™b)_B,Û¦Zeg—r¯¸,úªŸ 1p¢AC¯x±õšBoáçpn’7Ñ ¼ÀÁy¹´ç3c¿Ghíp"¨r_E cJìÉÛZ§7 Á.¸†„ ,t?ÀZlGKÄ Íø¨°‹ÝÐ\MÌM_ĸnÃç]ݽ—Ê™ÉöóÆMbP¦Ù&rrf­<éL›µ3À¦±!0F9Õ{å÷=Õ·œ`«úy ÖÌÇãÈåƒ à˜íç<ï¢r"RžWs˜ˆÚlÖm¨ôÃ1‡ü4¤^l®2³b ,Bf+%Wb?.žGü3bòŵ'XÁdœCÀ– ¯KLºìnîÇ4pÚ¼Ó› yQ¸@ðC°q{Ž398G‰ò$6Ááq¥">&Ø"Ý[ŸàéT¬ ä)«hĘ8‹Ûˆ ä`hVÒø6"gã¼µ~2¼38o£gõnài¼Qnn«ý7Þ¿ˆµÕ©‹5xÑ3†é‚býkÉ”KcŒ_šúaL$–Úv9\ʦ‹‰1’ýœG®àêÒíë7ý4.3™ƒwªñqÝZØ”N;n®ÓO'æFdØÿn†3JûpÐXJ >’»Äp=Zïc¸tDç³ür?ÜÁõ.]5†‹û0L—@Äèšuç ÝiU0¨µñ†°œÍÄQµ.ßᣂËù?i„ó2é–ÐiëW²ívv÷Åt=V×¾zùR«²*Âtmí.®i Úe¨¼FÀ,¦vK•!‰-ñ Ì-)¶‰QGNE¤‚Ò‚`'C(Ê­]¦‘×ü`šú¹Њ7ÊûµUt»ÿC[ïÒÏ饥bg²wK äîÞ ü ÑgW>Êób9—EÚ²í°³~~w3þÛ”’ ??@ŠÁ e¾_iQ‹`ºd«ƒ»Â@8‡E+ï(ÅÐÍ0ÿº]‡éf„ºa%ÈCÕ‹‘Ì2Pbvq¸´HzÍm þ®oD½é´Rw:bHïd­3œQˆ­±Ì„”f³zVy€ àÐÏq3BµÉXSÅC“J”ZHbo¦›3Ù¡¹îB¸Õ™knš{ˆø~ úx p< bÝ.?ÿƒÜž®M`ÓU°\0¡.½#‘K±M«)ìKˆݦ­ p"šý"ñœ· \ uDû}0íH>ÅQ:ÕÙBÀ}ˆ¨§!·g‡b§ ÔVÑS^>uó€µ¹«lœÉ_†öÕŒ±N ¦æ¾›;#tæÂ¾a†¹›nã›hD‘€æ¸/ãÕ îZ¹+ÀµT;Á×*ëd<uÓPèÚwã eGÞm\»|‘dØÏoºà&mKhüËWÍé”]Ü-%Ôèϰš·î@`×÷’ nœ—á:!¹¿E«›ÌZÛRƒ)ýúð5õ±Ë/³NÒÓ4¤û þ¹×V»¶\GÖzÙ®%×xJ¼Ú+j\ºGR5 A|;eëg6Oeº ÷È¥{ANŠÄ8¹­á\¤Íå¼öOð¦nÚÇxÚ$SÐËj…c)ÛÏ{z€Ó<•†/'Û‘P—/&Û Ò½õ«ØÏ«|9Ù~^oND7›‰±¬ôÒ&cƒKž$í2eËTfÚÈé7DY¶‰ÔELÜy 4÷Hýr01?u-½Lo‰×ÒïFñV4ï5™ ½¹DtX(…ÁÌò±åYs/‚•»¼Hïhsá£;–E)3ˆàŠiNrü)«èWô±Ëëß¼Ô)kÆøF˜ÌßUÞVåh–÷¬Îf…8š]#™ålåaUèU u_éÓ€lÝØwÅ„¥ÑÊ;âD¾ ‘Ì ¶¨p3:4v£V!…{Ãd9qV‚y´IRͯ•ãx![w’.vû˜]ÎÃIΛ°×0®‰ °^Ú}mãCy½ÒØa2rVR.›_Ø.ÄîS%Wä~cÄ3zç dù N„âQ@Ì07‹*b(-¯¥Zå GD61•J›ŸM ®¦N^OqPñ¡¤­•ØU×ö’jì+n‘t‹ØË/ÒFÜ‹ _]´3D•üg\1¿»Ñ¼IK7?<:ŒJfâ€Ùzw GðŽ3óè,Œ|&ÕvP»zODv¯>6ÞÔp1 1YèzÏ`WctúÉ÷¼º ¯£õ>uy¶ykÈßVİ q…«š«¹Zp® qAVó¿óº$CЩ¡pÇéBü-ï\ø¥öˆïƒc Dѽ(C ÛJºùAú³y7ùãK·o!Ÿà@8ûB¡ïÑpÇöA´!ŸûFtÉð]å aUþÔ‘A Æe"ÌT¯@dwTzò4ÓXˆ—:G©Œá%ä©Ù^3±Áôé%¡M¹Ò™2­«×sÕz&ðo%o)ÏÀ]õ] ƒKµÁ§5Gíân‹jþ9ÜZk^<Hº3Œ¾¥ëê²Y è£Ùµ‹‡<«õ"—M|]”‹¾]ŸtÿzL—ÝoU·+H:}äh¶pÉÕ_»÷€w®G¶…w·ôáâbP´×–ŒÖƒ¶þu:ù?¢oR{*L™ 4÷Ð.˜è2£vÖåÈÝ:ž)_õuÜv–mÁ¾mÐÙ([ÔÖÈ£u§L|]”‹¾™|{ÒÝÎL;UI(^ƒ4·,:¸ò{Žcˆl ¢œa˜|/`Dðwa³¥ýn¬œœšÛ&9È5Îà¹R?Ë™xÍAF{©EÂ*ð­ßLJ` -󀮄:lúù9»ºÞ¶Mâ¢CÎ0ï…8Ì{\ïΧy¿kþ³ÛrZóo¤#I§yŸ»aÞ;b[óùáÆXÞÞ±?™û…ÞpÁßÊLc63ß}õ*o¯r6 ÷h–ˆ£Yt>ZyCX•?qLmC$Ëþ>Ö—\-bðÁÐÐA_+.’©ÆFd? ÅuKr ˆDHn&9`ª,€•‹.6D’ r„Ïw«ÍËT…¥H¬a—è.6‡´ÄÜa蘗7`ñ›]íAúÛ$ÌÂç"ª¼#x÷ìû¯dÙïU‰|¸Ä9.Ê’¼ŠÝ`ˆKKôd395@ÛŒ$éŃ­¼Ú*Dw˜¯¡Ëƒ"ùൎîÿöü2¼ùeþM]šÊ€}*˥Э'(Y|(ôµ»ÉvTˆÛ Íf °œø…ûílëD$*´¬ÅÁÓ¥l™Ó^v‡H‘d™Ç ø7 ĆÒû.P×b¨¡„À-ž{×.Êr¨ÖíâŠì"|]·|ª÷­<@ÅÑÖÜÇ®}S\Fë·ârâë¢\ôÍèú¤ûs*’ö¶háÊÀ‹±âÅlçiØÌTKž®¸¬¦‡¹ç‹aƒ>œ@@o~ìÚ¸.³[Úú×±kàÝ5õ-3VrO……Nâæ[»H®¨ÍÔ-õh}!tûK_‡)¤ú¶Ag£@h¡GmŽÈ¤:¨zÏ ¤S5¿S²@(Р¹|­è½¶³‰ÙÀâªñ‰ Õ{• XIÃÅ·uF+×uÓ…~l¾næù>ùþK' ÃJ·Îö7µ°ÕJùGD×–oWyCdÝ8™é&fïÁŸL©`C¹-²/eÉvñò¥s³r忎%]Ù[½»ÊF\} ]ìžÔ?Æýco5¬)vp3ÖW¾,R'ñØ z‚˜îÓ¢M1΂ç'jTyCpb¾_gŠOÜ\¨ ^2Ý a78`»Uçf&ŠlâÕÎä·%ºI¾Àm×ek…wî™àßVö³ nð•Æôy—#¡·NÇ^¶¬§™ÏyšiRè'¼\¬Œz€v–ÆÏI¹\1 ‰O´ž6·¿Ž-ÃÇî[2W¸õ=Ù–?Ææå6rœ”I–%(—˜Ž%èŠ[›îÉv9¸$òè:p…0”’ã2þzÊ´C7§çt+¡e¥°¼B ?·Û®.x™`#ñ0Ùϧ²Xdcgùw›^ò!íx £D7àßy€>`Â'Ö¶iÄ.©Ù]u0A×¼)ä‘\a¤T~H¨SÂalsœåÊ¡!ùÊd“®´¢I9Gôÿ]yvó²"¸©–#qÛñû@˜0€Ãóš?"xJv"tyÝÃÕ(®åã5úܶõšŽÎ=z³.P¨2/ž/ÅLœwy±«ÉZFÈÀw“£tN2‘ŸU ±µ±¼!Æ~2’!˜Yïzò¥0„r¼þN…#޾ªÊ"ªÍú[ZѬ?Œu|Goõ­¼ ö[Z*~6‹tLf…س*oˆ³Y])ý£û]𹘾$½"ȃ€®|*IÏñðÂëM°[h½Åt=ÑÅ„}*ÇcF¼y<ÄŽŽ¾È]ŽãÕ†{·†ê‰.K©ÇÏaƒ¨t=ÑÅŒ»š,¸ÈþD+t"ðD›ËñD—¥Ÿ ¯l½¢1R™1}Å%~¦©õÑýuÞ|ž»ÉW¦ZG`Ø@:p‚z&á°H‰d‰Áª"4ó7è¯ó8bè,Ö^¤z¢‹­7.=·Ã¯ 'ºØ·D¦C¹eNtPCe}/gl›ÖÜü°ä l]Ï7(w!¿^°yßžlöEÎc®üBOtìIêÁñD—¥uûcø]¤}×ñ@Ó‚ªÍ„ƒøùÛ,Ê•¶µG׊vz¢‹\=õõ9XŽSú¡'º¸jôýëu0 I¥1E‚ñ‰®@ I^â\•ˆ fº/Q9LúySPâäÙ/GÙä%Ã=`<–õ°˜í(¿ºÕF2O^ƒ³ˆ³ÌE~O‹ ˆU}ƒ|ƒWü¼i~'¼Ì¨môÉjs‡$RÓ~~ëç-«3Y?‡§ |Pm™á´dÎÍ3Ò÷ºI¾Fx3Ï&YÚçn$Å!'RùóÉŒ^xÉGåˆÁl¬-!40ùZQ·—r9Q®:'‚ëº`Ž›CLœ«åÃ¥2Ò2Q¦ÀÙôI©ÍøÇ®Ú”g_u&Ù4BO£~³þ¥ÁhÞ;¹ª[— B¤ÍÍ'2Iæ$õî>Å3Rº?ÄóäDF9r±vh¿Z¨é-ŬŒýMˆÞö !ÁT7e'sÇ$ÝçÑz•®‚w`سúÞ¥§ú,Öwvvrsì¹…j#©*¹ ””¨7ò,á1x>–ÙXŤ\¾ôÁ4_3l#O⎤ùä €]AâJßJS¢ä½¢\üN©î-žo‰/¿]|'>X$Sqø+¤@TIs¼°Å$i~·ûãEVQ<ßâ»á§"¬£{J"¿!ü%°¨òŠèþxÚ€`3ãÒ@Óæ¦ o0HÛ«|osPCæ§¡C%â{#Â"Âú,ÿ@Ju¾­ÇÓòés<)×¥Ña‰¦[J°ëñ´ýñ4GÉ8¨ÿ±‰jUÞþVÚËLéé)¸RºO==•Å|B,Þ‹`2éNU“/fá’*FPu’²ÔóɆ!=¿ìµ»ž)öÖ»?Þì_ïzÜÙûÖõ£÷½û{@<ʫۛªÍ;…gëUòÓ¿^©£oî¾ cSí¹Z?(£¯åÊ“®ºSáOC£…¶v¾ÄpCç‹´«˜ïˆYÍÌA‡¤.†žOvðŽ!ô¢£×îzïÑ[ïþ¤½ë½Hª˜ We˜ª«å >ÞµM¶[_ ‡”þu€eDß {Ö66¯#Wëeôõ œút}Ð]g?—°8«?ó,ð'D§{ –Þ«/$Ç"¨ù÷ž`“Ý“”ƼÈ̺ø|À¦Ÿ#‹ ™ˆ´L€0þC.¯¬LZesLfµj©¤"±ŸhWådÛóDq°o?Ï^_åaq“w’)…‹Q@øyr›¾1§ºÑÿbbTC]"ˆyM ÓWDȶhò ‘¨T…€s`dæ“8Å#_!ÍÄì eÑé#5×Vš¤î8x$§*úzy•7Co݃]Š}[WáWÂÁ_JñÂnäÀÜ|¹j·ß\g¤Í/ˆ;Çn{5 ¿¿ï¶Övì¶paÉ£Æä }È9vÓêÒZI®!UŽ,±ÛÎYì»m ¦ë_¼3?wì¶Îvì¶á»mVH±ÛFscÄn`®Çn›Ý¹b·¶º¥OæÑÔ!øÆÀ.O·@í¶3îA•c·ÓcC»m€­Çn;À¬†°-k_±Ûfë×±Ûæ×]:%NT>¤O`OÎËù4÷r.aIÊRÅûn›”­±Ûv6ò¾=ÙLœ'?É–}mIí<‘ºŽc· „í6±Û&#íÍ%‡³Aüœ!€»ü’TÔn›\›ŽÝ6¹ºÄn›<ßc·Mð:ÒË`þÙçb_N>þ +úoòážo¸}Cl6N†ÎòwÄøg^Iruþ–N| ½vÁß ò*o¯r_DÃ{°íe°ã¯ÆöÖ—èøÂ¨¹=úAÞü>¶·Ñ¿ÌÈy|±ûJ’÷/½Nõ}þ¡ã‹KŸþjfÿùã‹Ëò>dú¢Õ@T^ ¦åM|ûÃÓD ŒŠÑVJ…1Y^-ñXûõZ΀¯6j3µÝn½)ÒdÚ}£÷f÷½Y\S«¢•ߢèDúe¸ô8ÆoÄñ{#šåMM-é³oˆîׄÃ@OD§Ã¨Y­‰:?4k_<3êž!¤³Ü‡=®¬Š|:$Û䆞sÐVå¬jL¢¡tñl†ðë5`,ŠŒŸJ‚Ç,ä~J”˜š òÂ${•§1'‡è7ùu†ô}#eàÔd¨šL±ƒ˜Ìv"ä]À/õœs°.NqÚ,×ù*Ànßg¦c ªMh5.™1¿˜Ý¾Á¯×ù÷Ã(¥´·w6žڱđ/ˆ[ø¡ÈØË¦WŸÈ»!ÍÞÞáÌ5!ÝÊ÷ 2L”$~ñ<örù.X»ì*¶±k;ËÏá^¿MxcvË$È®&M‰!š½½Ã Sx7»H¥ ú:@Ë » Sfíi«T^{‡?³Ì=ÌiPŒ™8ÄŽ5ªoåýsžµÇ§§µŸëD’_å[;úö`3ú{·¹±,ñ'¢ 3Þ” ^¤ž5¤³úç¹DùvyûÌ–5޵µ³0PlXÓ£ü²Ÿ7cíäÊ•Ô××ïëobò<¢ï_¯ƒñóØf¬¤õ@4üVǼœ°7D·¬ÕQåá6ÊÈ6NKÕP>³ËÏL°Yš.ëâÙfîÉ¢9ÆñuòÀhF+ïFò #¯žA ­íÎm³½X%é{‚οàu›¨ÝxF­cuÜvšÙl¹`J¼o¶¶¼ï±ö|l^n#o|,#(Óì1 œd|Е¹Ú>^&“ü;Òü’02P9Ûb-ÆïË‘÷Ìr»Á –#‘»kK6xëÂ>œd¢„/ÂYßÚ­ô5Öw"Vkò;µ[Ù»_Ôz `35©`ôÝ66¯m#·Ö7eìëN9ë›ÓõAw3ÕºPJî“?ëFðå›™j!)$‹gö]ËnðYC}8Ðp£ö¥|$Ö:ŸqøPÂe´ç!’õ­)ÓŒ÷½YRt{3d—É=¯]%wëu›“åõ>úæ`ôÝ66¯m#¯§ÌµCûzP®¼Òõ ûs*šÙ³Ú2™M ÖÔ^ µô˜z½GlyO6μ¼íc8ޏ”üÅj{ëÍoBù×ïäEßLDÄT¸±`Ž(¿LâXm ìÖ•Ê}/¢ûój»oƪp„Ææµ}äÖú¦Œ}Ý)g}sº>论â™/lušNŠšk½‹§QÉÖטõÄí‰/=e+G‡í Ý5*ÎØÇ©qí1ʯÏ^ŽÚWèc>È D¶ñÖ½}üE)‹6xùÏ/ÏD§rOk8t¼éúº?’w]¤rõ]w¨îdLšMâ¼ÓJmfÇnTð:ÇsñŒÛM7#à ÚçªíöhÑt³þ/ÿy³EÎÁV™à,Í‹›ÅO eR^gº3½¬Î¦w2M¯Âò…®]λ³gœ¡S16;8ör>ã:­65%ÏÈ]O^~h¾%Ò7ÝtɰCw“‡ ¼Ñs‘øÌ¸xÄveâ/+¶âªjf|»aå³µ³ÖT»JNž5ÕÅÈ,²omƒÝÞŒ8¸¬tËûÍ%,B'[ÑÑúe 6íw²í&w€œÓ’}ÚP§! > g°½Uª3Ÿ)ïSÄ'˜4çÌÍXX¾Ì øRx3ëçþR€Å(Æf9V”Ì>=ó° $VžMuP›lVšœgýQ;ù–œç“?/²Êã üƒ—£¦Uqcرö*o¯r6kÏÀìfíM—ó;º0y´ò‚ˆg`pš( b/m„}'©[~#ìùœ]å a/&/+Úó4¾80˜»ØÁ¸«Cœ¦\:M±µà'Õꬷ”@|£'¿0¾Çæì›ÕŒÃ·V“c6LxÀñ2>˜6ØíÅ¡0‚ðÄ÷þDõ*o{`èe¦”ÍFô¶óÅ+þŽèº W£˜L±)=Ž)M›àìãr'm¬ ú›¹Ðm¤¨M .Zw /¾. 0ú&û0úîöcÖ§]žÂvGm;Ý­§dBF_O)Dú ÷=[ÔÖȽõ ŒÝ(ç}3º>éþõ˜ ³³.œ9çµu[A<àölÄÙ¸çÞd^ôþpkƒ1GÐF‹Ú²à¢u·ðâë²£oR¬{*üéåë–?Îʯ)çžÕ¾†¶AÑúÕÍÜÔ×躈‰  6r„ÆæµmäÞzPÆ¿n”ó¾9]t׉ /{²ÁD>’%º¿üâ!pY+9_!ÎâÌÎýåEgzÉÁ[gv-@;íGùŒµÏ³òÙÔDOó•Ђ¨ÑñÂá ê¤Ù!¹p{¬ý„Ém¼!ŠuBrÖÀa ¶OŽÐŸš>Âæ¹²Sbú äËvf6$èx”÷öû_?ŸÖ]›Û~žtëƒQàÃsv¿mÂý­jÜœËgÓÜl—Îr6éþ…ïbÁ[æ¤sî†ÐLèŽ,Þlâkœ8d¢1ÐâªmÊxî°š-Y€À P'¿uâû@àâ8î9mÿ‚! Í@}ð²îNï׿³BLð\Þû7ìòçB¸ÏŸ•¾PùŸ=›þ;7òª¢yRºô‡Áñ–B‰8/KÍWÊ'dñ½È#:ºK™Èç+˜È³ Tk’Q¼ù;H¾ë´À[ò¯T?Þ¸¤9­œ/àîÚÍvÑzSP¸']m÷-ÀaÎMGÄèš""ÞȲ“ˆÆ=jË:­*¼˜Š§õßN 3øLû_-q¶.1\ó{ù,Öºjã5 Gëµ[ëúºÏžõ-À¡<6/³«ãCÛž0¡!MdNœÁäiÛýéYf³ŸWp?‚ «:Þ(Æ <º¹äŒ(ÝÏjÌ¿PŠí–ºíáÑœ$M(³‡—Úh:\¤H,¼øb¾\Miõó¼)SO(Þ‡imË>ɨݴß":dÂê ±yD·(Ä<fµ„' )Ú‹¹B›Ñ$¯:ñÃÖÒryÏ´AOý}"ªÊi¿ íu#˜-ÏiÓië-'yáa'ôÒ€ouæ˜nҜՃ$S[–ðF˜¿@ˆ?ºÓ°%VÌ'öù–\õSKŠ ÇÍjÀŽPÞ¨]/Â[ë5õ“²Xß4œ=Yvjõ2\ ÚihHA½Ëw̰#$‡tyo´Áé%–ö±WãÜâ%ÇztDÇ|JC`—Ýt pÆÑ’$†R€J1ÕhæÕ‚Ä'­òlþ’&qŸÊ#kÇ9JËÌoëä¿)ÎÌ« `nKtÇu€Õ¦&™Ìµ3}#Ѻ{SãëšéèÛ%Ip t…Æfå>òKqN™Ë’\å}#AWf6ÛtOæJ Äå’Â\t™*Š¢ß2vÝ6I 1½o‰‡èÔ–n÷zG©–mÕõ¨(2h_F¢&°±Í‡hW|$2É*›'ŸçÚ`L„#šÔ®×FÈóÑúÐËêñu&¶øˆ¾1ûõî»@ µŽ]Þ.I ¥Æ$eŠ@Ý•r¥Éü%ÇDLElÊÍ>Ò^€Ñ0¶&’Ï(ydR‘®f±oý£ï1ÕºjW©Co½*íÆþzsíÙóA×ÝŸSÑMT6Ý%3„ÅAH@˜ì¶Ô—Íe»2eÊgØÍqÌüøèà Drí5m §|´´µ¯+˜4úfkÊûk®u)C/×õñ¨­ðÛ£uŽÇ׫ŒQ1ŽÐØ¢¶F­eìëN9ë›ÓõAw¾¸¶—‚/Ì2Ï2†=¼#sWfOe©}…GL뢸ôÀe|°Û ‚OõåÃ×¼2Œ+†3t+:é ÉTÃHŸžò2!@ËÚˆÄd¸Š£(é'D.zNm# ÎÀ £/®Ý }unëÿ0r•Wë_Sp‹SGY Î}”“yMÄ2«"W{dÄìB{ ’óµƒÅD #bt½Ëyþ†ˆáBÃ…#»Ãm¶îb¸M†¶·ÉQìé:åØÃ­ÖC+/ÚwùpÍg¼‡[Œm¸Ù$º ×Á®!öèì€ý f¤W8ÚxC4ËKÞKt™Ñ@E¦>Rl];ì~ûM2ÁLÔKÏ›Ýo}°{3åÑ…´e_LÚèôXl ­ê&¨¤oŸKU¡'ºA¼Wï˜aK5%çºWï°}Y¬Þq‡Ü-:j®Çpæu.Vƒ÷³<;hõÎlÄðÕ‹£èk¯^ä+™{õè«×1ÓÕÞÁÎ;Ï4¾áöŠØyšWÚØyÚ!„±+r2lîÕA»ëµ¦ô^^” ä“Ç4bЇ®,9;èììˆ-›†dËb +G˜°Ö! w ÓË>Üá–²†‹7ËÚ1œþYæ9ÜaA^ÞBvÅ긒µáVõ6ܪ]»×Á®!öè,°î ‹5ÚxCøê5º<oä«óèÚE«#Ì{õ޽þªÀ¾£ß8ÊÇîNW›/¦lê‹ «w('ޝÞçRUˆL‹ïÆeØMï=`Gì`UÞ^ål–ÇIg³DÍæ¡Ýë®ò†°*FR ZØjÖÞÛ[·y@4ÛϽ„^Éc6¢XLBxéîú4[MF¹Ý^wÃ÷¶Ã‹ÌäŒwh~ºäƒ DÐÓ«lßšf!x6n:÷V¢ßNf?™ÖËWÑl8éz€´åˆ ÈøýGDð„WyCpb¾_gêÇr¸xÓõâââмnyÚš|«eÜ'â;;õÖL?#¢Êß¼•§qx1ÊÄŠ ;ºÉç¬Ê"ª!žíƒõ_½þmlo}ù›£^¨‰4ÿ/©ÎÊûØÞFÿC®¹—±í†÷`ß¾ô:Õoôù›£Þfö¯ûô—3ûÏ^Œ*W“…™øÔ"²æšB€2Y˜A¨\{+Ì8# ²ù›ø6؈­ð*'Èàá@ð]ʨ-á­3Å0n_—.ˆ¾e&݉¾ ÄÏ«91’½íä æûu¸Êì¿aò›ß¢ÈW.;F|CÀ=™‰è¶i Ä×NˆrMyösQ}Ó˜í5„ë%§®;†¯¼ô¨} Ò-²Ýò,%Fôwì;îOSɹÇIŸ^–tòQ.t¶ ××.³bÃìû%°xëÉÒ™^“_W†úî}–Ž”&SIv·‰9µÙˆñéo8ŒÛ—åWÅût—y‘W~”dzk„öã…–ûø®B¦éüz²Dºµ‡K<û} ìýÁ¢ žˆì‰iׄ'¥a®ñBpX–à¤goì¶V¢« ²àêa—dG ñs»‹äåC»˜¤7Ê032ÏoIÓüS 6Ø­3?WN>&ìÕ”8ÂbXa?™P-z£gˆY1a” Ó%ÞúPîc‚HÙ«dñ~‘T½å%@¾mh·R•yDΩÜ|k|#.Àné†1)#’Å-'\³u7íô Pí2ßÇEßš $,T}ÄAMÄŽòå¬=M¢u‹çJLY¶ÙÈúö`3ægÆÌv[{|®/<*bR‚­‘Ôc„tVÿšm®!F2ÿ kÛµbC7mY^?4ëäÚd­›¹ê_¿YžíëYLîÙûkƒáÊÊîÝ+ö2d.&J‹öwqàUÞ^e5[,B;l |}æb)2µ`³]´‹‡{ò¹`óÔÙ¢qa¶Óe[Ùœ‚±`óm‡<*×D±`ñBÏ8l±p[°ÅNœlÁâEËr.Ø@ø‚-汫'{bÁ–ëÓßGÑ‚-v×Ì,žË:d¾i|ÁfÛözy WÐu.XìcîƒT¶C· /Ø@hQäkèÒÇÒcIá9*· &çÍíXù6—…/X$AŸ»œ›îÚ Œ­_rÊúúåÇ!LžlÆ[Ì 6Z°Å¶§¶`açµsÁf bµ Fê{Aæ;Ì--ؼOûX®¤u¾`1Qó\°yÄ Æ‚Í.¹µ`±&æ¹`ŸƒÑÊRR{Tã7éD)n2ê`óÇhª”þ,–û# ×u€Í²—¼ÂU\•s²u[•²>bغ›êÌ}®º!w]¬Êâî6+w5ɧXŠ‚ØzÖ2›!;a U ý|ºDösGðZþ íHΚL³íÂ7Â¥[´ò†¨rÑ R,nµTzúê¬6èj –“FZÌ¥‡(Ñb/ÍmåMq;z,©”­»§æ·Úú¬UÅŽ§µö´ƒÀÀ« l.9–¸8Í63Aå'k2Eõ6A<§W”ÒÀs†b‚6bÚ“i¢eÒnØêS`–ñݬA?nI™ì‡:å›qçê,n¦Yy7ý'»/!Xcz £óω¶¾Y™"F3íjRÛ&Ra˜Û.-• °ù¹£Ëe»«ß#ì¡‹zîÇ¢d4bnÉ9%™¼ü¶  Æ#”ê*Ä‚o€˜&ªêlð5ƒl^øž’³Îm;e.CHX}áôæ¨Ã¾ÀÙ)@(Eô¹ë6…0uŸÙj²j‹]Ë›)x«Ý¶å¦w)”@›_Ç»5öÅË;Áæ?wDQù¶ä­æY_ëL¶Ÿ_*÷‡‚VbîÁÈ­˜¥ä[ŽVlÕJ—6Ë¥bœÕì,.8¯Y6/o¦Ú´åhÛJ×–£¹é¤-Gá¿€oFŽØr·mĶ [EÌÿá[–Œ-‡búÿð-Gk¶ 5¿Ó>‚f‰g¼<ˆ-G³»7±åhWlÇH*™Ó–#@ßrBf}»"¨UKfVø¦_?vùÍngµz2š†zhR¢žµÇ>òNNÙÃGld}{°™8¯Å.D[Ž@hËR>‚f·*bË¡ëø–£Õذv —­ôd³ûÍ^nÉ3lËÑŠ…Ûø–£•í¡¸9sóð|øžƒùïæFލP¯j†ú¸OÄÛˆ<í‡ó¤CCà61/L ‘ÀIf @ˆo\ŽG*ã[q¨¸ôØ—"p=Úíæ¾€¼A\Û¹íçD¬éEK¯4Re·ÞùÜÔׯø:2`ö蛆}øõ:\^!²dô÷àƒW¿9àž¡—@ ^îÁ·–ÑC8£n¸x'îV nÜòu3fÂn59¸l\FV9t%2 ˤ·~ñ},ü\©;p'}à‘®ÔúnàWŒÎ߯ÃÕQÂE%„|C¯‡z‚Š8}"†&t¾uLN×LplJ*{ËóËûÙ Éà=lX“ :f0?WZ²(—gs‹ûT73¼°1%¾u4¢£ €bôÒ­3tFo¯lÔ —ný!ó>{oEþdÃ>'ÐYN—䘬>±÷Øaà|½ æ PcÏý(—5ƒÓyd§½èÁ¡j~iß©»èŒrï‘NÖÁÌGÅñsCàÚôÅæH*=Gºü†ãwÍnù5°œ¸ú—wÃòRß!b ÔPmõ©üÖ¼®ÚØ]•/Z×fêRÖ¤†€%ål„»üíã…Íôn½BÀóº¾wß>œ>탕 &\½å¯DûZÎ蟆;)[&ù ªš™TÔT´r”žé°öÍ™é·õ¾9±4œ4ÅÕ¤Lt\ˆ›Î†{0ZY…J œ™tH'ÄZ„#ßv&GîyE`ænýYoˆÝ÷ÃÜOœ])!1²þó ¬ò&'M³Ô|RgÓqdM1Çç}ð¢ú}” $qÀYóc8ã@€M<€ç¬Ì6ƒHÖÙéâ®c;î­_&¿ýëX=C‡dè›­-ï{¬=ÛQ~imâ©e§ eº©ý¼Áæ1º2ãj?&“6ÍŪç÷FÀ\Ô¹s;ßY§ÒTÈ`t;m›80 –ç+ø“g~õà_öåÊKµ+÷xGë|-{Ýúï}3pO…!Ò²ðæGÔN\ÝÑúEE,bñëå¢÷ ‚¬—è»j¾Žr¹×î.½u£œÝèê}{Ð]GPíE‰m„tpó+b+1€‡+–' ”á%ðPb8‘{(1 %Æ£×­ÄŠž%ÝJ¬h‡J,µ‡KíE‰b+1;3%V´Uw%ÆÏJŒÝÙJ¬èéõX(–“/$½"¿ËÓ©ÄJºžJ ˆC‰á4ýPbº „”jJ¬è¹ÝCĤt*1ÎËVbèûC‰å Þåõ¡Ää6?”Xj%ældJìÉfâ¼úTbDl%Vô6²+±¢‡»·cÿ¶+Ú™Æ"Oå©Ä0ÜC‰½ÿëJ ´y(1k+1€‡‹%àJìe0:üÔ³h@é…jC„MY²fà Á¤Oײ¼$¹2–ZÖ# L)EîÌÚ)cP cŒ$X¨|W;@ü\ÏŠyyRT!jó¤^YëùÎH¢8¾sÓxümr±ÁMè`æöúù¸ÏÑ¥á‹å‰Ø*ÚÛxCTŽÿ›Gì—†$a¢; |©G]ÒɽM¡ý|ÂO!ÿN°4'QÞÝ*¦]S”ÜzÛ5Åx×ìÜËïÛ®)Óͳk ±íš¢›hn×Ýòs»Fy»¦t·‹h׆žÇ"/<?„@Q é(×F·kŠ^*ÚvMÉt¹º]³ÀvØ5†]ã³kJv%@!PtËl b· bvƒ-rœÃ>„¼ÛFùðmí;PßvM‰íg#³kžlöe1¶PÌ®±³V·kÊðiרÁì¶kJì§§…\äcóbÇÊ{!•v:<²oÛ®)±¹1»Ä:쥻Kàa×<£ ¹^¶]SÃc©Vg¦'bÛ5A»¦ÆŽŒvM•SzÛ5µº ]SKX¶IgGùa×Ôìf€ÊyA;ìšš´®Ã®Á]‰±íäÛ¸¶]ã`Ø5†8Fwùby"¶ãm¼!®©É­W “š´«1»¦æàQÙ55ûÏi×à0í°[j¸Nåýò¡«2¦»]ƒCÎzÚ5ÕÔ¬Ù5>áf×<ç_gÙ-Khíß!¶Óa˜M)ù¬)Q2ŸT,<ƒ1Cö¶Ã0¥â¾YžeÑ.ï¿­vùV†åU‰G9á—¸“É‘cúnÄÈX²!(”N× ¶ íüˆÚÉØÅZ5ë_Ç^NÇQ&j)÷­ï[/ØØ¢ÜF½pmÊ\¤½N§.C@˜8]/õÝé~ÑbùЉ€PtuË®†JÕ ÍeÖdÑ×ÍÚL=&BæÝuk¢®Ãq„¼KùÔ õö•Ïò:] •.Ð÷úSÇçCöÚ¢‡Wsj‘M Üa¬Ìüµ±1LÑ:˜À" fè…*6Ç"iJP¸IK.HUžÜÚ»S Ê`ÅÉl6ÊÑUCTеo"’8Ü(]QŒè¢Sº’C7òà´ð‰ì˜ÐÒÇ©Öû1àîbQå]kùF.‚ÙOInû¹Ù§¡m]ï™îë³×!õóÛÏ©õ1ÛÆÕá)òµ—¢¯¶ú^D½‹N1Ì“äÂ{ÊòhÏŒ±ß±„ºêºË uësÆÛx0çf¹©r*” :©nßW  b]VûØmGÊÓ&ÂO‘aWôØ‚Iè0w l”ëº>U­H‡.Ó(ÛÝÌ줬y ¼æ‹°T'Q®¨]ÅÂvFs2RÙö¶Üúùp#ê:AoÝÈLÞ>œÐîEêæk@òŠf?ÏšH¨Ir6öš·!_nŽEªÍ/B z'©ºt{–U夂9,WðœfæÒŽ!!ˆÇ$‚ø…t°úöd#Ð]Ö–]¢ÚŠ'‚é_}EÝf­O[¯‡ç°ây¸¡¢ò^þd¤’4˜Ý'¤.ìRô¨9:…ž²êë=^Ç#g&®•Ÿ‘3†øÿóEógÔK§Þˆ†e»)몮!¾Ñ¡T…ñ¯«•ë¥k–ïµ±Rªç/¾÷‡ýosðc?™ïì§!þ}ýÜ­x³ÍŸ£²~îfãÃç{•ÙÏ\õóî”Èý¥[ŽHWW V–FÙÿª—%­X³Ã©•-¿ÖnÖ?üo£§ÿ܆µûãü÷ôs·RÇ“|ÞÏݬÿ¢ÜAÏùÏ.'r-ÿŠËðí[ODÀiúÅw¥õx…íg¾ÿeýÿÿX˜÷/endstream endobj 11 0 obj << /Filter /FlateDecode /Length 2284 >> stream xÚ­X_ä¶ ßOáG°ÖH¶å?IQ`³ÉéCÚà-Š»C¡±53îyì‰-ßv‹|ø¢4cÏz{EQøAIK"ù#)‰‡€?Þ}÷t·}—¥AÉÊ,΂§} ’”å™ ²R²¬ÁS|³Í§§?Ýq÷“oxºÐáD3)Š@f%+2T§»_ï˜,¹,¬Ä¬kYþ?GØþtÁ÷ýÝ/ðùÙ½HäçŽf“Ó¾ePÀ¾aû°ï8…}'Y S %%íû]sزM$²< Õ°úÎþ“ŒÇ1¬dø¡3iô¸‰bÉæ£Ö5uÚfpÝJÕö¶jßÚ= Á@w‰‹E".˜Ìò +K™Ñ¢ãxi`»ÅÙo‚ƒüH‰\,$+DîEÎÃ&•aÿO]™‹Æ3aX»È/<è½@á$ÍCÓc›…ÏGeˆ¢ÚÑÑ/órn*Õ¶/4Ä®®ID©mvƒmˆ…æ<œì S'íÈí´”õIA U4ú‚Ñèjúî[¤È°a9ŸY ?µj 4ÈÐ:8Ð^fÓ=û=µŠ·¹¯™˜Œõÿ·0ˆÄ‘a“ä¡nµõ±Ç³…‘ã¸t &…*3©–ˆ'eôШ¶ù·2¤9­æ iŽ2Þ¡÷žs0W,CÕ´ª]ëfÞý‰þû“Ž\äA‚}Ímý|Ô”âDØwmÓ¹þG.ù4N÷HPÔüõñ=ù`ÔƒsˆB¦µÜŸ:P¡³?e’‚A„ZUGê]@…ƒÓ4š gúÒÔ” øbƒÊ¸äl\–úÞx8Å‹¹ÅeÌbQ\S£]òav8k>ÊTC÷ËGÎãVûJà—ß¡¥§¦­Ç›1#lë®Ö]EçÄHvGÆÏÖhÈDl7n ‡î *á$WÞ6Ý© «~|”œ, GÈ¡¶X‰#Â&Æò߈#ØÐmжáPuô!ŠvM÷[AÎû䊇ûiî–ÿoPld./)¾CÄ|Al÷•…j•–P–á’ãð¥?š—³C^ZúpƒÁ“úp&xñ=jPì@€@â Û=eÚÈmf¾y¨n˜m Lbcß4 t{n!n)/tó‚ö½öÅé=µ—h­g7Í«(Ây¯ë8&eúÁñ±H½$§º(—XÔ& v[YçÃhç¸dG @E¨çpL;m ÉW`㨃0´sá Nâ2— ØÁJÀÛÀq‡À•Xö÷«§œÏÜ QÒ;²vN„Îh–¿' lëœíR¨Ñà¤úEm@ÛYœàånLÏC䃞®¬äÝaÁÅ¿x"^Ž™^Èðrk´¬Y‡ÑØt•c`@á?®ŒDUÔœ´Q7òuÅéhgEÛ–Ò÷¸É ìµ_=l%,á—ÂgzWö’œÅq²Ð÷¬‹.-©È`ÇûFFã?;õä%­aŸP‚â¾"qÐŽŠ¾ÃV9qoûWÖ” k¦áóÚÁ›Nh9GxcGøƱLêÙû ° a¨DÅÛèÝ_ïš#rì¯ Ðzãüý2ž  Ä­__K–&ÙLðD'P˜»U`MÀ¯;¬fxa»©o¥í‚ñô’Pá¾°³Ù•åeβ+*LßCIÁ”°§¨9èN¶)Ÿå\äy\-Ž|¢µ÷·—›{[5 ƒîÌ2™Îß:¯¯–þTHΊ¼ÀÉŸxP‚†%pÀx¶¢§@f,+ñ\Ôïï~¹¼·JVæ¹{o…#2L Wq|½Z¾[³‡Ê‚åhŽ„Ü=.9ßl·€Ø´c`ŒíC­ûAo泚=’]—‹Ü49KÒ›—¬ÿy1E‰ríõ3 2X:)lâÄé!ìb8Ô…‘"æ"gdvwm‘ˆùn«¡9;‡¼zº ÖÚcâòDž:›¾~|Œ¾ûûFF??F?OTðuÚ¦Òݨ¿¹æªDÌ!h¿2¿ìbkqóEcL`Úî‡ÃÖÍ3nw/Ñ&‚Ô×UØÆaWoa±í-Â~¸ðendstream endobj 12 0 obj << /Annots [ 63 0 R 64 0 R 65 0 R ] /Contents 14 0 R /MediaBox [ 0 0 612 792 ] /Parent 280 0 R /Resources 66 0 R /Type /Page >> endobj 13 0 obj << /BBox [ 0 0 310 130 ] /FormType 1 /PTEX.FileName (/compile/figs/relationships.pdf) /PTEX.InfoDict 80 0 R /PTEX.PageNumber 1 /Resources << /ExtGState << /Alpha1 << /AIS false /BM /Normal /CA 1 /ca 1 >> >> /Pattern << /CyclePattern1 81 0 R /CyclePattern2 82 0 R /CyclePattern3 83 0 R /CyclePattern4 84 0 R /CyclePattern5 85 0 R /CyclePattern6 86 0 R >> /ProcSet [ /PDF /Text /ImageC ] /XObject << /Img0 15 0 R /Img0Mask 16 0 R /Img1 17 0 R /Img1Mask 18 0 R /Img2 19 0 R /Img2Mask 20 0 R /Img3 21 0 R /Img3Mask 22 0 R /Img4 23 0 R /Img4Mask 24 0 R /Img5 25 0 R /Img5Mask 26 0 R >> >> /Subtype /Form /Type /XObject /Length 6113 /Filter /FlateDecode >> stream xœÝ\É®,· Ý߯èxmÍÃ2p€ Äñ"kã"±}xØäïÃáRU5<¼Á‹Ø‹wyTRQ$EQ¤ºâ=зpøç]<1ó·×·—ï_޾½ä(m F£Ëãå8ÄãåÛ—¼|Gã|ö‡Ç¾ý:Þ¾ùñ4$þùá›çøßÿôŸáOAâøËßñ]gÙœç~–ÍYv*›%áßÄúÏ=\A• +ØäOF—çSœäù®š…éh4½ ðX€Oã·êá{Örˆ÷K‡wMºÜbH*Ê~;Ÿýùí›pûã¿i]lâúìo_ÿôÓ?øîöºýýùW¼t>ÿïë㟀âíÇ×ïÎÐWŸÿõ%ªI¾ëò~Rjœàá@v žÖà—/áö’A©}ñA ý(}E`°ugôx8³“ŸÞ…N3O¸×<„lAÈ9Úíõ…ê÷®Òˆ¹_˜÷‘„lu™š“ôx÷6·öqOeëÝé¥ûèÐcþv"KZ¼-’y×Ç÷œëÍz—~ï1ûèD&šƒ2Ão/í>B¿oDÖœwü¸ÎÍÚ1së ɬÑ!9{»É¼åþJj2îYa°*hU€ V-³ÙTvCÈ4²É6 Pzþƒ>^›j¦F'•¿¼a·épe š#Q¿Š]H;ë†Ûé9UUdE‚\ª0`(³è-ÒI>:É®áq};y›9ÓÍx#²õÅ;HUÏÍÛuæDö\2IÔ¥»  ÊäeK¾!")yÊRS€&ÏÄRLG€»è°ôûà™°wV Ï3 ™“AM–€ª6ÚÛvÈ¡E²@t’o$þ­æ rê¢C²ä)£Ç¦kÜ£ZxÍÜN¦Tå¥ìd3°ÍnÞóx,9Û€tÕ"€ k¸Ôª<–¥iÌn ,šº,…gZ—q·¹ÛýU6;#éXiBŠsW+.÷—PøíP8Ë'ßNú—%OæQ§K€L‚þj} €%t¹ÞeV­qÖÍÓ€LF¹Ö…‡-ê€Ö°íâaX6æ´Ë؇mIßä~϶åûÖ°èrtQ+ÛZôDBUb(Ãô¼ °1”Fþ©/C ²ŒÝPêÔ½íD†²ÜY÷ZvwWaµp‡+ ÎÒHw¦ÌÙ¢·¹bŒ¾\5Þn®¼™£ïk#Àܼ]gnÛ$³¶Hζ!ÈÕ6©£2ÕÈÇ}®múmØ ™Ým›&²6Rz^-±ûÚ†‰ìuߦ™ÿm›fþ·mšø‹‡Ñ (Û6mvÞŒtU,@Bô¶£¯o·¼YøÞWx„¹Y;fn½!™5:$go_‚ÞŽr• ÷ ~ùËA}ŠÔw?cpPß7¨O× >IPŸ’ÆÃÍBèÀÃd€uIŸ&¨ÿ8Qì4 ¯Ô§Ùwàá@Ê>N~Ô_Ô'ŽTÉ.²EÛ#Ç[õ -Òp@#Äñê’# &Ù³E p¤‘5Ò`’Ý|ÖH"ñ{¢“üx’HÃÛ³DY# &Ùße‹4m¬id4˜ä( k¤±‘i°Í®j`q²í>ưHƒöªY# áQg«²Ì^3ÛÂGY7žpS’7&ãtRåÇŽÄÛ‰]‡ CHŽ4²E 7³ë ×Hã¤^ù‰Ã0åž÷÷ߘ0unO€MhÚå Ä ]Þ »µ² j¥0^Õ¢[ ’Ñ%òcIçˆIñû¶Q%IòÖN2T¥ò6ÇdònÝÅ2Ò®Û$“âèu52›wt@7aëu‹¶Ñ³máöö¬[¼ñfúïK¿˜›ëWgîÖ¡’Ù¬G%çÖ¥rͼœ”)ú%vøÄ”m“ÝÞ „Ý"³ç­‚Ù•³¬m% ”©ªÌEÚƒj¶‰°ïØF•dYíDJ$ŒÞÌ}ÞGgþÃz»ñÞ U ›°õκEÛèÙ¶p{{Ö-ÞxËïÙ››·ëÌ­7$³F‡äìí&Wðv”»ªbj´gñ¬¾ÒÀd£O€å}Ðå X<Ë@ŽË$8HË`êPsuƒªÌï28ÚI86psí»÷áÇÉÎws®ê®ÍØ«‰ÌCÑv[,ENa¾”@®¥¦€/Eíí µš)ÚBÖ·ûBWÞÜ (йy»ÎÜŒJf9!HΜäj.ì¨LÕo•Sà¶Ô˜I4U… 9íz0¨&‡78ÚåÒfŽ]¢õÍ\‡ä¡¼}а[oõ·Ñ‰ÿ¾½vc¼\ªp@Ý„öv7sÌrúvwÊ›» å}¹ ÌÍÛuæÞ[%³®’ó·» •·ƒÜE ¬>²RE#S*0™•”@È ¯*z!Α9`²j{s‘nvdÍqoUt¤¸œÉ¡ŽfFQ ÍšW ‘›#VîhšLÝüV«"urg©-3Šb·ˆ!ÌY³DŽ)¼'ŽÛ9ÅnPÉ<β{ˆ8»d—8ÝFÿ¾-ÀÝrÚ4 “”¼…I<©¶û%ZX~‰È¸m“$£¶Ü”j`–­=k\É–¡dP R´&'íÏŽŠÛ“$åXadAÙkÂãPÜ$ Ó$‰XšCTé”dÌHLG§´9ÕØTÂlÎ<•Ü]6Ý †0ÝêÓ­’²ðéìä˜N‘ƒÌ6Ý †Ñžu7³é&ئO7Á1]qíkº ×t ðÙE9}^(õËÇêräÖ„ÆrתS€}­:e[NÃfh»N İ™{‘Ìfî[ ÚëbGÓôÝS„B}±uM¸Zœo§¥ª ՂЈë H¨* ŒkZG4x\$Öå ÄdX92¡ #DÍšÈTFœIkKF­bIaÉ7ì«&£Ö2jÝ%œ8O:|4Í¢ ´K ÆäÄ6Û"Ý:0”YôÖhÑG loUGoðíÆ»û~››µcæA`—ŒÆzHé!øf!×ÐîHwoÊ|E†Wü§NçíHʳ#ðœa2"톣væÖ°ÍêÎÌI¹à¤N§¤­½ÈM#ï]|›ÅèÎo/+ŽOª(+Ž×Ç¥7Ç$qîq¼½ÅoÎ[àLÅâ]IÍ0Ö¶µwo—ÞÝ dV§Ç¼Ýä Þr×TA¼–‰fG¸mëÆwGÖåX—}X™í>¬Û°1s±rÐå[IË„v¶JqcÀb].À6ìÈRña¹èMo£Ɉ„z"bͨ)SDEj ¤î8}‚-É3¹ŸÎFœúЦqk~ÜjUÈ#Ð\؈~º¤æ‘°ÅX˜ì+4ãÇ àTOf$?=r‚uD˜h•8yD5! š?ÐT_Ç5™LÞ½IÇ í$Ûï¦f“Žu"›”̦ƒ¤&T!É_#9U‡< _¢æÚR\~”G?øYV”Þ4 ·}È ›r\í‘‚l ,79¨ò.ë’…'Ь(˜Q”ÓùÉÌdù±¨Ô“(߀¯Ë*ûOÈ®wHÈ¡ãgS…å$†ðß¶3ʘy¾?nç¬y©V»Ò+v!Þ!;2Qθ²&&x7»Ø&ó~™ºwôñ®_~ßT]¹¦êФêü½v³nèëf~‘κ|¢»~‡£ŸË¨q²˜¯ªk!S‡õiÕµ˜}hÕUcÓ«®R^®[ÕÕ«ºrÜÜb¯ÊÃá W]ù:0®²hÕU.¯ª«0WÕ•'“úVuåšÝX7cØ5×îUW–yÉ[Õ•‹ixÕU¼áªº:iUWPuåÞ~SFO³mUWVT_7òX/-¸1ŠM‡ÍXåNǪʒ(®RpÕ•/R—¸U]Y²ØÍ¸êjf„ªëÉÌØ£³¨qÕF«® ¤æUW~a^uå»ç¹oUWVE,^uå+,cí¦òÏ^u-k)K;mš¸õÆUWYï{Õ•……ª1W]¹|TªW]e ä­êzšŒ¬,ò85n—Q°åÈ÷‡Û|ØÍ ïrü2Šz…ü—ôf!_F‘¤5–ƒ\F‘̨ý³¥òo—⺌Â?rkku†ü2Šv÷Ä»8бÜŸîéúd†ùW‰¸Y¦—Qä׌ºÜ¹[ijE¸Œâ¤]F1` ¤êfw\¨ÖåØÝ““¦>4?ÔÌËûâõˆ×C îj‹r½BmÀ<‡½Ÿ¨fþq8úÙ@œ3É+ƒû&Ñ©<%‡â€å-¼ËXi—!?²†E²cȲ¬.Àó#ü»ŒòÂÏæ€ñBnÐ ¾G)z¢ä:Ø™g(8¸´½Y¸cç(HÎÙ òX9yþ%µ\%ÁÉÑĹ.ƒá4–®Ö*»ï–ÃŽÕá&{% Ki)úØìøç£ãàêó!/Rô|=´èòÒj5%ZÕìà¬â$égÞñ=/×Ym¬Ä‡.e¯Hqp3À·E­DFîJ6ÈgtÝ×S1Å›ë7J î¤Ùì’œ–sA¯æm˜Œ¼ËX¼ ðÖ¸Øëêr–“4µÅ Öã–æöì×cër83ï]²S4$å)¢àßzdr¥ò.^©ß!í­ØŒ*;™å‰%xv†Ø8tyz8+¼TÀeR»(A ËÆ‘FÌQ÷¢` Q7þóDêšVÅ"eº¯/¸@øPœž&TïrD1³¦Þoë²oÀŒÃÎUßwçj׫¾ÃŠûW¬/®Ä`@<Ÿæ0ÆÑúL̸íeŸ|°¾Ã¸°òå ä_uÛK>kÀšOQ= ’WN²0)W_4×Ïàñªß(šwNr•‰Éˆöå³’"WòU>{‘çÖž4¬og²¢Uâ4ù’/¶Ä§?i—ô?'Þê"ã¼ëÇ;ÀR”/­¤g@ÂRXC^ì Ø »~üDVw’#âǬLÊŽ!3¬°ë‡0¾|”uª”6ùÍC»Ê×I)0YñxÃèU?JÑTí #ß´«_"©¸£0x“~[À’@Ó{ Ê °èFȇ5†’yê‡7’’AEÒQÉn•0©QGS¸§ÑÌF®¡}Ê”OïLÔ¹Qä‰üe„¬‹¤\;%ìd›x<nuþ àFãc\ŽxèÕ“v—L]CQJ³òi“©ý§*}¢J]U Wž¤T#ŸV™Nªü4L@{S-ópø’KÓ—ewC}Až[ çßNú×4LÔæh.À'Üq5å Ðt I ÉäÀÂúU‹†uí«Ù ³K{€—iü\NH4cÕ{æÞ®¿”ÞEȈ֠£-ä% 4™”jp’@ÓɈ@s>»ŒÒöX6bC^sUâenƒxLa¹ ¾+Sw·Q+W·Q›^}‚àË9í¶¹ ¾ü³·]I|“楇}sdó®ß$æIÿO?qÜ4°›+™$½cbÀƒ·lƒè hðÜKŽáØÉžÈöÄ…§\´õ†º|“5>X|Z|ÆPï>×(xbþ:>íÔê’à(ê$-¹æ°Kkvùyð’¿ýÐÉžø•ÒòÃtÄ<Á½\|Æg»òÙÎ|¶3ŸíÌgýmZÉôa:KW¥³ÎÒYg餳·ï8žlüÿüsŸ_ÒÿÿOê€)endstream endobj 14 0 obj << /Filter /FlateDecode /Length 2509 >> stream xÚ­koÜ6ò»…O2`Ñ"õNÑÒäzè¡;Çhqh C+Ñ»J´ÒV”êúßß ‡Ôj7²íÆZÃ×p8/Žfä;kÇwþuñÝíÅõ÷qèd,‹EìÜÞ;a±˜;qŒ;·¥ó»›\þqûï ߬±ÏÞ^p|‡;Bp?'öGSl/þ¼`Q”$™ž1õ]g:®Ø ç]{ñ_ø³CžÅéM¹‘“¹@5˃%Ð¥‚%¡÷ûj}É#—]zldg–Vfn¿‘H%›ó¸Ï²(#ò>ø¾¨¥zT½Ü^]ÂßÕ(rE²V–¢’ºÚFšÁ·B oé¹2m"K#«ú ¢§ÛgÝ] ßõd“n3q×µeѳ}МåœùQi‘„, CÇ {H'¸¥ó, zx&`ÕRðo×MIý{nâX¿É{‚Ö];ìhÊýÐZ^4rßvû¥m3"õˆ¥– 0‘=«ª!¿6º‘NOÆ,ð#«ÝÐŒ 4™$‹öôPÕ5ð(Ô4ìªyÂañPØ òmªs ~CÃ(uÝÙI5Ô}…‡M‰jò7þ“ÅУ®hû Ñ^œ²,öà˜CU—sÄ ’àxže®lÔ@òIGÎgn)w²)eSTRQbæ’DR­\zjÞ›ÛC'Ç9#gL7Sõ÷Y(2-³$ŠGå#ñÓ©ù ˜N/»ÎZ.ÍØä¨´iÎѬ•Äíq¬”ªZ7Ú¡ÉÃÞõw9`2[¨¡(¤RWv‹ 2NÆ q0MƒñȲĜU“FCjÓuIƒy}ÉÁêð_þ¨Ì8n,Í„êÞâ3{tòÏA‚ù›ñÄEΣ¦¸£hVÿ@rò3)°D€û©«’Í*|Ä¢dTx4ý9…7ª b.eâC8!z±3/ËŠÎŽ­öž†‰T<ØuS¥ÂžÕãðPu¡iIÄ<:8ã½ìµ=¡‹ÛÈ­uràŒ£Ëé1|HóF£âÌ·—)xRT…4E=”’Zà/µÆE }퉮¨ÿÁŒƒ´íQ¡uÐ8:7ôW'wàdÓ“’Æt;àŒ'ÙÇAõ^>Á¬‰öö¤W¾1dæ%i@SÈòêø öY­1Ý8BÖas—Ÿòµ¡RídQá•TõÆN­ùŸëÝ…<¥»gÖ”Ô«£vòЕ]Ê|ÿH«^ÑXÑ‚‘}c¬†´SÅ¡‡M…’GP—5 wy]?R÷Z6²3¼áZÃf´ÿÈd浟Cˆ´¿^߀Ә$†ÀÅOÀ—…,HÍøc¥Œ{åƒÍæb’0déh`?É>gjt—"‚O¿©}0¿níL›7qÝ>Bã×8A 7†Ï1ûýß)adÍ‚,uôÔ-ü8oâÔÎ{ˆãQEÊÂ4{!ðgPP”÷5(À—¥bI˜ÂAá‚<ƒŽ0 ²‹¹ñ<çgØ%,¾°A²¿‘Ý `úJJGVœM驘ôËg ]AJ‘'DA˜2–aoª~3Zý~.L1Öö¦îØÈd¾¡Éˆ#°älŒõàZšAÈc†Ð¿À×y› 3Ä/¢K1-U‚³)=ÓRà Áe/ÃÓ…˜óô\JOÅôŒa…€15†eƒ‚ÏM!X¸'ßûåã1†»7öz=Ø ÊGã©ÔÉ&ƒ[‹—îBDK…{.§"Zj."baôü\ˆh)?Ï¥óDD”:¸"Á²œ@4gÞk»OýÝÝÈÞÞ!Ž‹}ß}ýE;€wÕÃË霉%,޲Iþj‚÷[z¾—ýÝMÛöÖô¨÷ƒù'[O rz mXˆh©6œK版f´Åü&¼=¤6qðJi‡h"ôWW'KÃÏXô"7ÙBDK¥q.'"zFÞåŒ4Þé×qu÷KCöñí?N—Gì/!eˆËãL:OD4#$e~¢€e6yÿ¦¿ûœY÷›ÎJßý”Äô®õ]¯àulF·tÛ:ó_Èíïä¸[d<_@K-äÙtžŠha!ÒˆÅ/ÁÎex–róL*OÃót¬-R˜f+p²)ŸzåLžŒ³¿ÆžMúˆT0Áƒs’>ˆ"ä✤Ï× øbÒç :ö‚]Èã‚©-¶ÔÊ2–ø€;æ,O8­wDnÛè<&ffmÒX×MŽVÙY6k–á+¥mmà§“¼½’õý•MË¢‚¶A¯Úã”°M8"ŒIÜ' i˜”Œ÷y]FÍ_šÂ P‰ õØôùßcA€q?„Æ'À¶Ïd~§óBOÕÉP,=ôfÒÑÛ×PyÓà"€³WD«)Âj€ ,ıà²ÕV€šÖ 7º~£µôÜ×5öʬ«áÈÏë~ÓëÍsÉiþ|mF°xtHš)+Só­zzne Nns›I6ÅU-ñÞ4•¸„%">,ÄÝHÕw•­¼ Áµî !ŽŠ8Beg=¤Š®ZiÖ@ÿ ( à¦Zo¼ZWeH$5­«»ŒæÝn(!0«€¦Š†Ñõ2*ú$¤DÐÕ´ÔÞµJU+Ê¡ëjÎ=P¢É‡&=÷A×ï°Ç._I“µOÜ\}½(Ãë¢s¤?2ÀÁ𑍄›owX»ý\u¡(¶°G óy6àB¯K±8@ìéˆ`ìÐ5x’©ÇÂTq¶`è±E}5ˆ}³Ð–Â*›a»}}÷R£r© „gÜ]åÅ'bxW*Õ&ï5S­J‚Ò„àÎгáûoAâþ3.æT7e?ØOc´×X1Á¸Uü±°¦¨¿E‰Ø(§lè9ážÕ£ f<È$ÒÙO¾˜(p@M_?Ú:¢®-c¬å°ºrt…Ò廀=[lˆbgÁxñØ["‚k>‰é—˜ùˆR°4M>ãå¾€”²„'ÈËÔÏìUR™Ï@ìÓ((ŽiüAˆ`ô=“:0'“÷göŒX0™"BóùÉËn¨`ÓŠ•‘–vLà~š¾*¨5‘ÐX$«Ðt¶À~SߟûIÓ²‡<‘±8Ö4M-M>¼ÇÖ=C`ÿ=Ó®ÿŒ†CŽmóR>¡æCð|Ýwß¾õ¾ûß%çÜõ~~ëýüŽzCæPW~5ðz¾0áƒvx:H$ìûÝëëk]å­þ’ô‘‹bm·¾6xÔõêÑ»ôî6>Á¦ËkØìúXAÿ{¾óBendstream endobj 15 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Height 61 /SMask 16 0 R /Subtype /Image /Width 101 /Length 41 /Filter /FlateDecode >> stream xœíÁ  ÷Om7 €H3endstream endobj 16 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /Height 61 /Subtype /Image /Width 101 /Length 278 /Filter /FlateDecode >> stream xœíØÍR‚PÆq·@f”8à"hFh#%h5‚¦éýßOµä°}›iñþoà·~Mð?J\”26˜.Œ;° Cp¦*„–ãù`y®c E!LØ÷a¼+‘a0tˆp+ˆ³UV‘gÒ7Ù¡Â Ÿž_w{¨šºJg6"†¯^>Ž'¨º·:¦º‚x‹²=~]¡:wM»c¤Ú®7¨.}‹"ˆ ‚"ˆ ‚"ˆ òŸ‘¤lúóªÏÃv-Gˆ+óú½ë¡:ì7Ëu3 gžUuÓBµÝ”êú%Ü dš%Tëe©;ž01 æ2+Žf¾úHü*¦=uášÚ¦ú­ü(”ë2Óñ¥èƆÁ÷ ZÂËÜendstream endobj 17 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Height 61 /SMask 18 0 R /Subtype /Image /Width 101 /Length 41 /Filter /FlateDecode >> stream xœíÁ  ÷Om7 €H3endstream endobj 18 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /Height 61 /Subtype /Image /Width 101 /Length 278 /Filter /FlateDecode >> stream xœíØÍR‚PÆq·@f”8à"hFh#%h5‚¦éýßOµä°}›iñþoà·~Mð?J\”26˜.Œ;° Cp¦*„–ãù`y®c E!LØ÷a¼+‘a0tˆp+ˆ³UV‘gÒ7Ù¡Â Ÿž_w{¨šºJg6"†¯^>Ž'¨º·:¦º‚x‹²=~]¡:wM»c¤Ú®7¨.}‹"ˆ ‚"ˆ ‚"ˆ òŸ‘¤lúóªÏÃv-Gˆ+óú½ë¡:ì7Ëu3 gžUuÓBµÝ”êú%Ü dš%Tëe©;ž01 æ2+Žf¾úHü*¦=uášÚ¦ú­ü(”ë2Óñ¥èƆÁ÷ ZÂËÜendstream endobj 19 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Height 61 /SMask 20 0 R /Subtype /Image /Width 101 /Length 41 /Filter /FlateDecode >> stream xœíÁ  ÷Om7 €H3endstream endobj 20 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /Height 61 /Subtype /Image /Width 101 /Length 278 /Filter /FlateDecode >> stream xœíØÍR‚PÆq·@f”8à"hFh#%h5‚¦éýßOµä°}›iñþoà·~Mð?J\”26˜.Œ;° Cp¦*„–ãù`y®c E!LØ÷a¼+‘a0tˆp+ˆ³UV‘gÒ7Ù¡Â Ÿž_w{¨šºJg6"†¯^>Ž'¨º·:¦º‚x‹²=~]¡:wM»c¤Ú®7¨.}‹"ˆ ‚"ˆ ‚"ˆ òŸ‘¤lúóªÏÃv-Gˆ+óú½ë¡:ì7Ëu3 gžUuÓBµÝ”êú%Ü dš%Tëe©;ž01 æ2+Žf¾úHü*¦=uášÚ¦ú­ü(”ë2Óñ¥èƆÁ÷ ZÂËÜendstream endobj 21 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Height 61 /SMask 22 0 R /Subtype /Image /Width 101 /Length 41 /Filter /FlateDecode >> stream xœíÁ  ÷Om7 €H3endstream endobj 22 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /Height 61 /Subtype /Image /Width 101 /Length 278 /Filter /FlateDecode >> stream xœíØÍR‚PÆq·@f”8à"hFh#%h5‚¦éýßOµä°}›iñþoà·~Mð?J\”26˜.Œ;° Cp¦*„–ãù`y®c E!LØ÷a¼+‘a0tˆp+ˆ³UV‘gÒ7Ù¡Â Ÿž_w{¨šºJg6"†¯^>Ž'¨º·:¦º‚x‹²=~]¡:wM»c¤Ú®7¨.}‹"ˆ ‚"ˆ ‚"ˆ òŸ‘¤lúóªÏÃv-Gˆ+óú½ë¡:ì7Ëu3 gžUuÓBµÝ”êú%Ü dš%Tëe©;ž01 æ2+Žf¾úHü*¦=uášÚ¦ú­ü(”ë2Óñ¥èƆÁ÷ ZÂËÜendstream endobj 23 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Height 61 /SMask 24 0 R /Subtype /Image /Width 101 /Length 41 /Filter /FlateDecode >> stream xœíÁ  ÷Om7 €H3endstream endobj 24 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /Height 61 /Subtype /Image /Width 101 /Length 278 /Filter /FlateDecode >> stream xœíØÍR‚PÆq·@f”8à"hFh#%h5‚¦éýßOµä°}›iñþoà·~Mð?J\”26˜.Œ;° Cp¦*„–ãù`y®c E!LØ÷a¼+‘a0tˆp+ˆ³UV‘gÒ7Ù¡Â Ÿž_w{¨šºJg6"†¯^>Ž'¨º·:¦º‚x‹²=~]¡:wM»c¤Ú®7¨.}‹"ˆ ‚"ˆ ‚"ˆ òŸ‘¤lúóªÏÃv-Gˆ+óú½ë¡:ì7Ëu3 gžUuÓBµÝ”êú%Ü dš%Tëe©;ž01 æ2+Žf¾úHü*¦=uášÚ¦ú­ü(”ë2Óñ¥èƆÁ÷ ZÂËÜendstream endobj 25 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceRGB /Height 61 /SMask 26 0 R /Subtype /Image /Width 101 /Length 41 /Filter /FlateDecode >> stream xœíÁ  ÷Om7 €H3endstream endobj 26 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /Height 61 /Subtype /Image /Width 101 /Length 278 /Filter /FlateDecode >> stream xœíØÍR‚PÆq·@f”8à"hFh#%h5‚¦éýßOµä°}›iñþoà·~Mð?J\”26˜.Œ;° Cp¦*„–ãù`y®c E!LØ÷a¼+‘a0tˆp+ˆ³UV‘gÒ7Ù¡Â Ÿž_w{¨šºJg6"†¯^>Ž'¨º·:¦º‚x‹²=~]¡:wM»c¤Ú®7¨.}‹"ˆ ‚"ˆ ‚"ˆ òŸ‘¤lúóªÏÃv-Gˆ+óú½ë¡:ì7Ëu3 gžUuÓBµÝ”êú%Ü dš%Tëe©;ž01 æ2+Žf¾úHü*¦=uášÚ¦ú­ü(”ë2Óñ¥èƆÁ÷ ZÂËÜendstream endobj 27 0 obj << /Annots [ 102 0 R ] /Contents 28 0 R /MediaBox [ 0 0 612 792 ] /Parent 280 0 R /Resources 103 0 R /Type /Page >> endobj 28 0 obj << /Filter /FlateDecode /Length 3113 >> stream xÚÕ\koÜ6ýî_1È—c34EQ•nHÒR$Ùnld±h ƒÖÐc5i*iâúßïåCóêŒìK©]äƒ!‰¦Ž®î9—¼¤8¤“Å„N¾?{uuvñ]Ì')IcO®n'AÈIG“8Hœ“«ùä§©8ÿåê‡3ên:<B4€@€À)a›Ì(NÀÛ¼iórq>c†$$ÐN@sÃ;™—¶ö\e…¬e›WecKºÿ´wÊž\ª¥,Û<³Wσ ˜ªº;6ÏlÖ«UU·ö¢ÈojY?œÇє쿉&Ý_½˜ì^~ؾï·Wg¿pJ'ø+ Q’Lâ($1“lyöÓ/t2‡þ7†©˜Ü›ªKøƒ7ɤ˜\žýû"41aÜaèÇÚ xD;¼(P>À.B’$)Þýž?ânx‹8yä I7øŽ»žhéÆƒ-õE2Á-@P Ü›<ä€$Sj+™}’ å"RìTC“¨ É.Ê®?ncËܳ÷°56Ò0÷ÜçíÝ`FIÊ‚®ÒµR…¼© ÈÕĈÃ+nóÆFl/ Ç#4LHBG‘  +™Á–z#aÃ¥DÓ4‚O±HXŸ¶ÔéHFŒ¤B눑€¹0lÖ7íÃêñ0tÑw}ÙÖÇ#0f¦+Ø‹—Ä€‘( 7½Aò +Àó’Q$€DBK`¨¥¾HG$CŸÅ€ÄI DkùÍC)—Ð C«9Ï3ÝdÎbJ§_ÿÓ¦="Š” s·UmkË¢x¼Ý?ÖÊ“ºW¡º}Tb¢Ý³øÒ.¾¶Ç¿¹¼Hð•·( *E”X$¬([ê„më©MGð) ëÓÁ–ú"õ´õTÀ°Èú‰†Þ:;ˆ™#Ñgâ“ï´ð&bVuþy“AíáòFV›úÞA¥ Ñ@#!0ÜR_$+€ô¨`\Ìf³óYÀ€´—–»ÏŽksÑ*ía)­êçîl©/Òé¬&ŠõHÀ#«¹¾Tí±¹;wŒËlÂá™M$¥£ˆ‹„Á`K}‘z¾ØÞv4³Éª¢PY»In`°¸›ñ4ÛQëºYoûIÙݽ„ô&¿)\/جoÕê¡¡?Õ”ÐþÉí'SDBS=ÔRo$lÊ¡‹Gñ) ëÓÁ–ú"õ´¡œC ;3³.m°™•IHm&]Þ«ûn"~BïôPÁ^¾°‡÷²]ײðoCNh: µX$,µƒ-õE²Q÷º< ýRÆ„ Gí»íØmŸWææ¿¨?W,&…+,–«Á–ú"õpʼnÇÕÛ1õŸÄU H ËÕ`K}‘þ˜ql¹syrb¬ÝM‹Ômã?( Ä8ü ‘Ðü µÔ©'–ôì’l>ï^°“Ï½é  £ÐEÂÒ1ØR_¤:('1ut¼Úι¦m÷£Lײ={Ö%ÙÇ>$m¾ Õ ZÅcÉ K KƒƒAŸwkÉSNƒ~4’þá–ú"Ÿñ4&q¸ÓZj‚?¨[岑¶²Ç»¶]½¸¸hÔg¤ª¶|óµÐ,¸2³Œ¿Ë¬›ÈT²Ü¨§Ü)i{ÏÀ´ÂÏ»‰ËÖ»9æ"&,EX$¬[ê‹Ô#!H ŸßÉr¡öé[n‡û&–«"WnÈþòÇ7›l7JÏ‹¼}ð¦8$¤Ñc‘°¶Ô©bJb³<™âí`ä4Å72ût/ëys|2&Ó_ vãO:¼m8éH$4éC-õEê!=a$aO'}çKáiÒoóß»S³Å~‡r]D©î]­uiè·÷° ãQ€EÂ*`°¥ÞHÈù8n–LŽâS,Ö§ƒ-õE:=Ç£˜$"FÎÇ=ûdzí<Ü[—ò|ØË³]|"± I€L¬_U ¬$Ö<&œ¢,V)ƒ-õEêi¹ "ˆÿœÄºªçJˈ½|W5­M©Ëª•7Ń. £Q8Ç"a9l©/Rç”~¼ÏÝëT·çVu´r±¿ÒGÉ:àd×/·îÿµZ¬ ©ûÛýœøk€.ÆÑ ­¡–ú"õh dÐVh`g^%/o«}‚!f;ê?©ŽÝ²kd–Uë²Ýo4æªU5¤éj¯9ÐXøÓΉ‚QhÇ"ail©76Ù 8‰ø(>Å"a}:ØR_¤žd+€²›l½l¯ßBsÚ^ÿÙ¼¼Þùî©Ó¯ˆ´+ˆ¨™{RÞud‹êEc8ò1tƒEÂêf°¥¾H=º¡ú‡£‘§nÜ#´V(5™ã_®p‰éZA#!µ2ÜR_¤>­P’¦Z±9w ¾,©èöl© ‘ÐRj©/Òi©„iH(ÃJå­jšë«MÚþåhE0¢|?‚V°HX­ ¶Ô©G+"2ŸBqZyWÕê‹ÔJÂIœŽ¢,V+ƒ-õEêÑJ’*°ZùVÏé±_XÇ$a£H‹„•Ê`K}‘z¤§$ðRÉÔJoo¿(¥D‚$Ñ(JÁ"a•2ØRo$ä|DÚDŒãS$Ú§C-õEꉾ($A‚¾g²œï|þùx¸@/Ù±8ÔAs*õîÁÿ#9#"ÇÐ  «›Á–z#ac1äæ÷I#ø‹„õé`K}‘zb‚ŒÁ°‹ošë7%×_uщ Î(%”FñGÚÅD$£¨‹„UÑ`K}‘N¬ 51?X+þúNeŸšn £þÕ|s—¯¼ Ié( a‘° ¶Ô Ûv”¤á8>E"¡}:ÔR_¤Ó;¼…AHBæT¿óûÙ![†4!Ñc+’û·8ÔIÿ‡£Ç¶8| Ä£[°cÃÖ§¶Ï´ëö£I4ŠØî&œ, ïf®94]š«7ËU¡–ªl¥ýU­Ý$³•yÑlvÕ,éù†[xÄ,DP·ÍØÕþ&Fé´é~–«/Vµj²û×y0­ô§æ%œ([VTç,šÞëU æRéËÏçA4U…-êŒ0;=õŽ1Œ‰ÝxË¢>f2 ¡íßîo³÷¾Ï½²>gt:Ó·OÀŒPOf zæÖ9·y¶.d­§OBÁ§í]¥—_„"œÊf¯Þtå²µgÎöBÚƒ®™ÿL)Ëì­ù<¯š‡2«eãpõÚJ‹£Ü ôö¶òý2NÐÃÜf¨fm­æ–:»NÄìkÚº NïªeUT‹µr×f>©à)î´åb-ª1‹ îIÊ9<'2žyÎ÷ïÏÃhúÒl‡z&ʼnYÆñ4[×5¼«q[ãá¤*»¢j¥×)èºMµ®3÷ÿ—siOô;ä…\IÍÅg-€¼)Ôs{«Ù´Ä<·m,S;·D­êêW¥W=1šLµ¯ óÞTLÁI¶Ôîô %ÀÑ­ª­ï üþ< S½“Š©TÙ:HS'Í2w¯©k,e©7º4µd2½Ñ¶ëµv¯X(ƒ2Õ8ÇÒ=[¿Ó †$ÖZRú´V²©Êæù1ÍC{Aiú˜ä!YÙæ°­ü¤ßÌøÐåÜúB`á(Ý¿–k½¢—%šƒ`ÚØÓUÕ4v™¶®¢ªrÐEë-5´¦ï¾¯£脦ÈÒ ¹”Ý ô¯;l˜ÙëucL†r±òÀY‹s0\oRgêÛç¹:†0(mTaù‡sK üs®@€sUf¹… 7ÕoÔbÜ6:ó;[¹î4˜Æ)‘Ùg@œaû»Žvöš€|'„¶Foä6;ø™EM ±(¶mÕg ´u“ÕùÊí8lÅèV‡ 7çª³ä †lñœP¼Íë׳Wÿ5<ÎÞ¿ž½ÿÆ–rB»í3U6êÅñ½8(tP3“C˜Wpk3Pp›Và¨%Ù,Rt8ÍÅͤÍI0-3}dÓr~»Øsd ÿdôÊ)endstream endobj 29 0 obj << /Annots [ 101 0 R 154 0 R 155 0 R 156 0 R 158 0 R ] /Contents 30 0 R /MediaBox [ 0 0 612 792 ] /Parent 280 0 R /Resources 159 0 R /Type /Page >> endobj 30 0 obj << /Filter /FlateDecode /Length 2681 >> stream xÚ­YKã6¾÷¯0r’6[¤Þìa2™ zL²™¾,2Á‚–Ømndɑ䙸ßo«¨G[½YìÅ,)>Šõøªnž6áæÃÍ÷7w?¦ñ¦EªÒÍÃã&ΑÊMZ@SÈÍCµù-(¶¿?üý&äoàƒdöÁ.ŠC‘ÇÉf§ ç} ¹ÝÉ0 ƒ·µí¶2ÌJ¦ÚîTŸÃPզǥݤa’'¸d¸ÙÉL$yJký¸•IÐv<3ŸÏ”9œ#ƒÜD]wkË©H¤Yá' íŽ,ƒ½¡VïkG©qädºÇ¶;RÇ=s»öߦvýÉ”_¿lx1žõ9LÂÞð‚?Ú'Al|yëWÄCnv±iœÂU#¡2–tc ®„ò®ƒdÙÙÁ–º^ ŽfµÔîyê©3½i†Q ™Èâ°p¢J#QÉ~~$­‰+*†W¦½¹~þÙôL‘ÃøfYÂù¬Túü³åË…æò›/,]ñtZ}ÂTkšŽB>˜¦4ðLÃ.ž .C¯„œe…Âã§Ùž(ßjj>üò+}2û¾àïé½ø ‹÷fFaÏ=SN± eÅÊ)ŽlUœm]1ûÀãþòÔ»¤¶²[•¦Ãu¬¾4îlÛó/`'„¦wwæƒg¤#‚Œ`XmowK½Úî;Ý]¨£Ïáízꔺá/õ[ü¹mÜ}pvY¶gw6·¼ÖLT%¹HÃèuòÑF¿Úº¦U{ÃËÃYÜ+¨\‚«ÅAÙ¢m®æ§û_ßÿía%Aw6Àᣠü5˜®q6œ/(Y$½rªsg›'¢Á¤O¶Öƒmx‡Á© Œ}EIèË6M‚[âæE“æ]¿«3J‰Ê »a¶¦fî]\Ÿ_œzî-‘@§ÊŽJÕ‹qg%¢„·¾Ç7LðÑu NÄà«'iðá#JéíVJ<øîø=M.'çrdP_ˆ/gtu¡ÉÛ~AÁnCCN߀Ñ2MéPð³M^”Qç˲ o©%{EÊ·M;¡y&JÌ-ÎüyÉÁbx!B¶à–5¼š>³ßz®æ‰Îš¯ÏX¶¶)mÅ’ÿjó‰½ 8÷ëpam#ˆÏúLxÎýè½Ï½é˜lÿÛRÞÍ÷`éð×'ƒ•Vã#„Ñ0Ì œBPþnáq¿[³H%"žb«m|X2–•°Å÷ýÚÏBpA‡o8Ÿ° =š+æI‡žHuÆë9HÁ‡E€ç¾ð—>º»{dO£¥þPHT`ß玧š™0Ž]ö4â°rïy*ÁE`â!å 0 ‘gDŽƒŽh³£ÚîâÚ†¸ã–ðäÚ–?üò‰´öþ‡÷Þ&Ú¥u³~F$»hß»”,õYrg€#öˆ Fã°ÑÄ#.ˆ„À$ÈÞOäo~ô§<ìÞÖv¸ðzÓ!ø ±(âxé2gbŽ„#­œîGðºèyM‡šMAÐ!¨\`,èÎUf½€±ŠXd©z=œfùNÇ,o~Y]Øv-xϺífÛ×{f…éR²¸q5{åõjYv›eCóÒÚ¦‚z0WsçªAák¸ìi'9®41ªƒ!ŠA?PTp,ƒ×¨Ï½u¸º.±„VS3ar7Õuþµ¯, G×uûÄ›»¸xÀбH&âI¥öI áX§9Ѥ9ñ´Âa°çN?žehÏv ¢Rút2º£-l³f›œ¢L…”¿âˆáF 91õ#ÑcU;?Ù-à¶r+èÇBru{œÜxÃN‹ —…ÓÁ3o,Å•[]©åuíÑ+“¼’a±š‹Ud(óò<, R¡¢Ø×å×å?Áív³J×X†pkäó5d˜ˆ8Z)áÍ'©PÄS–Mbpu,þÏj ·¸bØ\$"O²åo Åm[3p>—æqmN`C‚œ`oà=N^Ö¯-3ß í®"³…þÌ Ü,®)»rûëÁSf-VÓ™³|¦Rìâ7m'hàT3÷÷|âáçÕš‘¥Ëƒy*¥„8¿®Ä!óÑ2ûÃnåÈ ýަºëÇ90ÆðØÔ£Võ0ADMˆ,¼=r¸í·øÏÊô× °Hqo©ãQnÝê)"kÚi®°»,²Ì÷7Þ °7r## ªF7T±)7¿ýn*„«‰¨È7_ÝÔã&IEZ *×›O7ÿÿKD‘e¤ì`\R‰<Ï®þ(Á?œ qÿ“d2Ã?JðϱÖÊž¾7^Ûû²³'40WÊÀâ˜RÑ¢¹H°˜ Á§Z—æ@Õ˜eíwÌïËáìÿZTߨî8Ö,57)\5Êñ^&wÜåK9O¤ Áô…K Žº9Ó]¨ÏêÔ®cšX5mgcXj'³÷p€2f~€x÷n÷ý?]º·ûøn÷ñâÆ"$¢¶¥izófÄ Ó%Àï„ð¾» 8t…Ã0œÞÜÝ•ÇöÅàt }ÑvOw¼N·¿ì¶»LM‰­ šê6»{®bÿ™=§endstream endobj 31 0 obj << /Annots [ 157 0 R 165 0 R 166 0 R 167 0 R ] /Contents 32 0 R /MediaBox [ 0 0 612 792 ] /Parent 280 0 R /Resources 168 0 R /Type /Page >> endobj 32 0 obj << /Filter /FlateDecode /Length 2840 >> stream xÚ­[msÛ6þî_¡ñ'iÆ‚ð oz3nzmÓÉ¥w‰¯77IÇCS°Ä†"U’Šë»X¦dZ1)}°âåÁbß° W|²œðÉOgßßœ]þú“ˆE¡ '7÷áùL…Á$ŒFbr³˜|š >ûýæ—3îfí—L4@@„Lr5™P¨À»´ªÓ|9›Ë€O}&âÙ•Ÿ¦ù>Ó>àÙ ×953LÿŠ×›ÌPCqOe–Þ•qùH©]¯ŒÖ`Á=AgeÏêB3OËfLš/heÂ}Hë•[>wt,ÌÆÀ <ÁaM'•q^%å.¡a0e»\d@’û+—“îã‡'ÞþãæìÏ3U> Á¥&aà±Ðדd}öéw>Y@ç/0Ñ‹ôäÁ]ßR“lòñìß{ž…™öÂCÀ{ œŠ¼Â˜–} ¾†‚~A‡¯=¦T4œ‡9ßÃnØE¨¾±€bQ‹ïdw¤WRÚ²âhJÇ"YO¢A) ÉÓÖ¢|Î|Ï$Íx‘aYKjLôi¬ä,’­õ]giiØ[0¯¿Ø»ône²¬øÙÎA~ôÛŠ§˜â'ÞP¤¡Â;šÒÑHC BF %wžEÊÓ£)‹tÀ <É„t±‰“/ñÒôØ„ç1_}6ñ3ÍØY@̺=êÑ&#8xuñD,Þc)4Ôd¬„§C‘†òôhJÇ"Q4ÚµHiÜsȄ֤Øïã5a!çÓ«#3Ûr6yUÇyÝg^Š…a3î_eñ‡IêÛôwTžÛÓç|üñÃ):܇" •ûÑ”ŽE: w®™Nî̦8±ÜÿóáEìÊ»®7ÕÕåå]Zßm“/¦fE¹¼ŒÑý^Z]`Ë´¯A¤˜N¡ƒ‘êÃñ”ŽFè[1­OÂÓ¡HCyz4¥c‘^¶± ’L*gc¿ÝŠ[~+fs!_°3?d\êWZÐZä“™¸zr®cÍG ‰Óˆz Ò`QKéX¤ç¢–\Áõ×$Ÿy¼u§Ë´ªMyûSZ‡òXäŸDC‘†ŠãhJÇ"õˆCD,òpÏ!ó<'ŽÏ<à. ™Í¥VòÝßÉZ0(¹-¡0€uO"¡¡HC%t4¥c‘z$$}¸¢ @ÒÌ ßhÊ*µïøºÒù ß¹`œ‰s¨Šñò 4ãü$òŠ4T^GS:é¼hš•×ÏEóÒ¹+/Œ"güðÛÊWKg Ò`éKéX¤҈Ç{•Λb½†ƒgîñŽpÎÃ@É óJAps/ä](b.î|OALy2 ƒ{ï|¼}ÉxxE*£)‹t@„¾ÏüÀ‰ðû ¤ºý5'é5R¼®oßA°Wßþ7­Wi~ûÏø¢|r“Í+]FÁ&G‰ãïTžÏxt‘E*Ò£)4ôN%CøIx:i(O¦t,½âúîTR³@83™ÏÝuê×laœ”ÝëÐ:]®jªÞ`£ Ah&‚“m(ÒP¡Méh¤¡† ¦Ó§áé@¤Á<=–Ò±H/ë„´{·†‡EÏ{2å©¿s¼æT8ø±<à°@ó±!¢Hó±ü5ßüX~­h‡r㥤&uDÀ¥'ÙwrG|¸)lB.â:¾Ww¡žÀÁ•Tédv0lñ!^ŸÉ`ú`ðÿWìgé󩛸ŽÓ¼†?Ñc&{P¥(2ªm7óº˜ÃŠ®ç!Í2ÂNs„ú:“|ZdŽz;™ É&O%)Ö›4£%ojãS(ïËbMµíÑøàO«b[&¦¢ž8_P¥4›,N =‘PI¶eir‡çrKŠd ì!@ÇuVÑå¤%¬ÉGIŠrS”±»Ð舱Òf¢¤HŠÔšrd '¦âa&`×å—vê¦}Í‘mb¸Ùv+íWF’)¿ýyg%‹U›JÓ:oÆv·ð™s™Œó`«*pTm3äšò§¹±\…“Rò ¶ÆÔ”l«ÚJêHkÓmu û­Ø€9x;·ór[ Ñæ°£É?ØãïõÇ·)]ç“ÿ»MÓÆ"߇Qð6Ù ×(kŽðXÓ8«M™ÃºO*{ÑÇ;-À°{º FrÚˆªQÓfI«Éܪ=Æ Ø–»·:¥A̓²ƒé·ÍÄÔ8j-S {cÊU¼±¢›`d¸/vرu[¯í«é$?^áppeòµcHe#GlJ+jY˜”Í,.\sMÍ¥!©Y¥µí•Éî©ïIÝç½Æ€šª¸[4Œ¦kSÇèg¨™4êà3 Cƒ¡éÀ6EÅ£ÑÇ=ÑåwÁpK=4äEM•§}ÅÇ j`²4Ð-º0÷–MÛ¬~Žô|ÛÊ,ÐVÎîmµ‡¿ÐSQšêµ#SMë2].MI\Æñ9•m"›cšêpGµ³—°dI~Í‚­âºÏ;’§Á9vÉnŠìÉMÕd‘Kz +ÐCF 7«Ôa8Í¢¤¬ YR 1ÍáÀX;˶  r*Ò§ÍNBMâï1H8i¥'¿e’é§O…è9ŠmM¸NóT£îØTPiýu‚\r ´“¬¿È¨Å1悃±&f]“_Æe¦$c 5\úôÎn…µ Ì‚¬›-©Ç‹¹÷b×÷µu ~4ÅóöÐëõ]‘fž÷m×¥ÂöSOµ‰q¯yE‹ 7²H«¨-µŸè”¤¤NÛê|€gs9ãÚµ68w™OBE6(ð]Þ¾–Öt¸…¡ÁšeNèTž·7¢ uFCœ~â$W.œ1‡Ó»G“¬LâT»Œë¶×7»Í¶oS€:ô51˜zÒ.Ëx³J0‚Ç6Á4MH‘;®?¦KF5ÝÇÕNF)Äma(ðøeàE]êînÒéäÓ܇É7Ä—È(X)·9ÅVøð<@¡vËî,b öäTÆT$q^ä¸zÌŠOIA^Vq¹ÅC;·jŠŒö¼|¿éâ·õ-ÓÅA¼=p÷X0<¸1ÊÝ£]à“Gz7ÏlXæ–~çôÁÖÆ¿zV ðý*Mœ¬ZZÄG<¢osóõS”)ÂïÛ’Mæq´œÖŽðð-eL!ÙŽÆ/yÑXŸ;­­I×4ë:e7žìä\ÇT€‡«Ód›Å.ÃÙ…“np¹§”óV¸äõ²û­=ÿeÃl¬R!íÚPtNzx"^_¸‘µºŠ«ÕîdôpqI‰$“§U¨BJìÆmÉæ¤€}¥EÙNy¦¦ÎÝt\h€ éb-v‘dÛªm·žš«-(ƒméh´·Ú=»`«»êȧØå‚:HöϽ‰É«mé"zÿ¥ˆ>PL«WD¥ÜoÓò{ý¬önVÑS÷&µ÷ì†â»Šß\b|¼áÖè8ŸÃu7Ñî¡n/OuÛU ½›?ÝC…1%Þuƒ…‘×Þ—›K­ý~è~2ŽÒ¦[ìèÓ4SõÀ4wöy³r¿è(mÐ OÑ­; ËŠâ ÆB»··äý_6ØJYu3†^'Ò/öÎ 2¬¬×f‘’(à1Yò/{ÏawÔIàÀÍi{œè&÷î³ à ”;„šPöçÛ*)Ó£ÎE¯îƒig«ëxaw²QSó6o·ÕîúÍ›ù÷ÿ› !¦ó÷oæïh~H›ßX$ ñæª?³ÜFLöm•Ý&x]]^&àëô«¡›Ne³¼Nuy÷8ŸÍ•˜æ –rš/.a±Ë}•û?ac­¤endstream endobj 33 0 obj << /Annots [ 194 0 R 195 0 R ] /Contents 35 0 R /MediaBox [ 0 0 612 792 ] /Parent 280 0 R /Resources 196 0 R /Type /Page >> endobj 34 0 obj << /BBox [ 0 0 729 253 ] /FormType 1 /PTEX.FileName (/compile/figs/workflow.pdf) /PTEX.InfoDict 199 0 R /PTEX.PageNumber 1 /Resources << /ExtGState << /Alpha1 << /AIS false /BM /Normal /CA 1 /ca 1 >> >> /Pattern << /CyclePattern1 200 0 R /CyclePattern2 201 0 R /CyclePattern3 202 0 R /CyclePattern4 203 0 R /CyclePattern5 204 0 R /CyclePattern6 205 0 R /CyclePattern7 206 0 R /CyclePattern8 207 0 R >> /ProcSet [ /PDF /Text /ImageC ] >> /Subtype /Form /Type /XObject /Length 45267 /Filter /FlateDecode >> stream xœì½Ë®e;ÏÖ?O±_à+ë~inà ŽiN¾Æ.#±ÝÉÛg’c Jk­Â89N#Huv‘ZsN‰¢H‰7å_éù÷•^þü#¿€¥×ç?_ß¿ÿú?þzýáï¿fÙ¿ü#˜üüõúŠŸ¿þù×ÿò×|Þó¯þ»ŸÿýŸÿ>ýoÿùí•üóŸþ·?ãÿçÿþ¯ü'ü‘Oÿíÿ‹ßz§ÍûØßióN;Ðæï¢ðU×ÿ¥—þËÿŒE.¸è™_~™ƒžÄ?ôü_ö¾í^j¿.ÄO 2~ùsžùÄÄCÿüëýmšÿ¶¿ã¿v^8û_ýOÿþ¿ü—ÿðŸþã×÷õÿýïìGÿúÿüþùDå¯ÿüýßQÿî_ÿ„¾¬ükÕýLŒ3ýš»~µò+íüõöÂV‚ßÏœX{ Ì?Êëó¯ó1»üZ«Årz~Òâ¿ÿRˆ¯÷÷OüÛ¿Ò×ÿðPµõ§éßü?a‘ÿ/ÒçßýUŒ:hø7¯¤ÊùW­ëùù³‡-Ô@J»ÛË38€OgÊÍ™ð²Üœ²m Ä*O{Ú OOãÉ™ñí ±½wøÿ•æDïWµ™kÏ;ØDU´öÙ13umG´g”ÑÙ|ÞošÒ¦™ ÏÌxÆþŒ¯KÎÂy6~l’T=¡36QéW7¾°Î>óxû…˜99¡·ƒ»úÛ‹³xòeб1ï¥ÙxXz9hóöLÄnøy÷y{:•ùü(ÅIõ°|ß}Û=áç@TGü¢/Hr[®F,ßÕ=ë»øb¨•ànèÝL@Ôá½Oc„Ø7¾(G `ìcö‡T“r¾;÷÷qƒ•û0rÊ M~–j0: ýÊ÷¦ž³s¡3qôÛ™zÌ$¸­ó ¹ž>Äšø`ÝF½1+'£kïs± v\ŸŸ?œ§¹³öGk–Å]k1;òbÛOûù#ßmoå:8?'=ÎMvF½À\~jûÓ«ôDHßxÇâéRÍ@Ì ?†°>rÀ»x—1ÂgB|»g#PÌõšJºæ÷!W™÷ü>*]¶/*e{m1f¢Ú_>B“Š“Û‚i³“»˜©X::S]?½Í®É¾ú̽£´„(P+„Í'BJ-yGÄ>àB= Ôªíj¦8Ó> ÚlÆ> >ò¡¶ÐóØ×Ù|G‡bÍs<ˆç ÒÎNá󬱨Há û€ÑëŠ}ÀV*DÛ\ öBAЉÚõ'DU| ¤ößf 6—óé¿ý¿eñ(ŸâZí4ð—öÿ÷_-_× ù'~Ñú#Õ ñp×ë/þ^ÃßÓ£éT_SÿåÝíªò·#ìȲ“ëóAȸ2@[a;óìhSÅ;ûJ{–ü3áÚ‚5Ðø’ ýÜXöjpqЄ®Æ¤ÏÇ Î aÊæAämËèC÷ÎÚ® ÀåzÙ–ÍŸÿñÏíù'D¬!lÃaŒ¾üƒ8vwÐ…ÙC×­†°c˶£ÛövÛn m¸#h?ŸÞ¡hä9ˆYi»üíË•‰Ñ~ãëÝ;óLEr0åuÀ‡fáÏ),5ºg·_þ„8Ã%BÃmš} ×äìËp±>®á>ç…| §WÞÃ-¿æ¾Ú˯گá>Ê»¾ ÷Jùî#%û5\‚g¸DœÑ=ß™@3V |"ž.åAÄ”Œ‡½ÁNÃÁÖÀî{k„à;ºòÍζya÷‡~íj΃˸¸˜Êâ„Ðw®íÞÈ=µ½-ÕoWfÓ'ä¡‘ ç÷AØ7¹µ½Äbãteû·š«¯À¬«:hÖÕÅbáôñÙƒvv©vbÝÚÏÙGµ?⊠ë½áÒáûÀÛ‡3Œ½ÝÔÌÓûŒ·ÛFØÀ>¼o¤Í{÷㈠p5f¯83>Wñs;Y¡wˆî?￸{°²¦h?oÎ Ñn;d|,)ž£mãP] fò·u×Þž±Ô†[œ¾w³Ÿg­Í=²¿.avWæÛÁ—­ND&³LLÔ>¬f]Ýíæ¼l4¼Ú‡Ï« Úg÷mtKX¹fW¼(»¹A!=âÙäÂ+›óR7H–ÖœólŸˆGÊÄ)Êöp°4¼¿ÇT€Õ«w¨Kò·•1œ ¦‚¢í ‚ÜÅöêáÚ{e8± JÌ2æ<¯çV43œõ|õ2ß&ú±îùa¿"DÉsøXóOˆä$ÿ9¼#Œ%JEØéÈ@g‰‡6ÏlèfŒÎCtµ³<–Óè¶/|& Ù> ô³G§)T"âôðL=r Ë+D®uØÀa©p·:ìßÏšX®ŸÄÉXˆC³´¬?!‚¨zä‰ùyŸ)LÞÄJÚÔ  j¡â|Øú‘C6üœÛŽ‘±V͆\Kó=ÎæZ8ÜØo?„‹uóËAŠíQ¬ Ú¬z{‡Ðë¶¥z@JXÛ*[WëðÛû¾ÇÕ>]%¹@nÒX–°’Ër•ý Ì«b מ_ê Κùs"Œ2?ï´9Ÿm$• õßq؆où@ô ‘0hß'Ú1Ç3©ù ðBs§|{/¸“ëDùHâLó–Ô6ƒéjoØÅ=ÝY(˜ vDÂÂh¶í,UëÄU¢À눈ç¬ëÖÄëa~…cSg2.|ŒÙ°Y&«ÊpÁLðš ~n„¹D.Ü >ÃÜ6&r¤LbwY^°¨Lñ),õ¥°nÑú r¾Ú»ËBm:Œ{¹BqÔ3îÆÛm¸>z´ç bTê‘ÚIꊯÃöeˆÙ¹¥Âç2SIø\OZÝ&dÕ£Äû*ñºñ<•x5—üQâC‰ A%nOï£ÄÍŒ¶n%nó¿ŽÀKk[ß羕¸HJü ¨Ä… niqBq%Þ Žk¡ÄCöQâ gK-¶–Ã2€ÅhÄ\W{’¢s%Þ’NOTâÆìû(ñäAÅ•xÝàÞPâD%^±ï—ÞO¹ëJ¼3 ”¸Q¯%Þ2ÌâÆ/V“Vü8íϹ[FBp?åWnkNJ)qñµýÂ÷,{–8Û ‡Œ¶}9"â ¢GÞçlw®›ÚÄbáÙî)0x¶kKììg»h?Ûµ%C Ù™:g;!Îêå#1ï}‡Œ‘ð³]›ZÛ<Û5Šy¶kØjélw@žíˆ¸ÒeY{C¢Æîí g»×™r9Ö[h ¨…^%ø]-t¬$©…ŽutÔƒÈý¨…þæuÔ‚ÀP ájÁžÎG-< kT b”£ð>»õ ’‡ZxûÒÿÏØÚñÈõÚÃ|mï…(ÎH×[>Wo' ©çµ3ï%âtŽ| ^^» NÂ$DxfÖüýæòq6œsèzÀIé a<»¤«»ƒf3ÑÝ3‡4ÝAb^î¢9Ã]dÊÔ¢»ÐJwEI³< –ñvwYÀ¶ôt î {€æjóïØë¨y2?Ç¥wu$uwu¶EcƒyQD³Ëÿƒö&½äî ‰µ}ÜA¢Ðnbî ~7w wtMxe7y@InØM&íj´›Ìþâh|úž_dçœíSœîî ⃡;È(Ë€OÙˆî W6sÙ9áè?î Éý-ÝAöA˜0Ýô€´ ÑTaýãîÑ;4$“\oÙpŽÃTôK¯= õ–»ƒ&­*á2ba8®µ'Í0tMZƒÃô:žìí30§‡Éývg3ãâ ñã¾a›ðY|mXH®_´_ŒÊb¸†¼™.¯_,_#/x nÒ 6·pzA47jÎá›tl¾>‚MS Þ‡8©„ÑÄx-+aß="^«G>xíösÃõÚ­s“ËÏ×[>zäŸîô˜\c·â¯%âôvøô1$§õÈáx/ˆjj*C:N;"4ý…ySé´ô¨Ôì™æã,-¶ ÃIðûtˆ«‡‡ž|ä š¯2"ÜKZ´»ÿ:û 3Î>Gç!/ªG§æ¹@DâŸOÄ!*ù@`b~Þg þ¥ê‚wBµý>ˆg¯ýјúˆN·DñÑN;­> ‡CÃ5š04 À¬s‹-8VMøü†1_íÉ¥í´£ýt?§ÕwfÂÎq&¥:Ú= ³{vO€Š Ä™VÈãOÄY$|ä1NG?©IÒ_ì¸ëôpefèÂ{æ´ˆT¸ž7@xB²{B‚~y^íÅÅ»½În8v¸Bmô u,-ËÖˆù•ãúeþ]Ÿ˜ÛgÜÒǼ /Œ%Äa >ò¸¤P!}ô– £!lôÈâ’>f*7 }1cùú"X2ðzÄ(¸b3q¸ß*‰ðfP ½Ø#P¯v˜ ÅÀ5a?ˆ–×ä^71°À``!é7ôÚ"¦O| ‚-5¶Õt¸â ~ØF˜›£)­0Ô~šóÕ^ÝÐ$®Ø®p!‹5¿dà×ùÿ¦¹½‰ã«Ìí‰ÖÝ,™9`’î‘Ia†ÜŒÑ¸Dâq°÷a2Ýíj/îärfÀæ5»[5`.^X€m·À²ÿ›Þ ‚Œ"¦Ó¼ëOˆ˜N=òˆùm0äh~­ë̯ـ_æ×F˜Ïüš9ýP"WÌo«¾÷öy?qmؘdC¦<¬îªàdM3÷Éd+4ãëì–1¡‰¨nŽƒuÓ3f^Ý®»J<ó“gæ\yÜiÓ ¶?h° s»ûì ÏòÛ¶®ö ‚Ù2èKþÙØxÄbÓa7ëØ,·Í$÷ŽYgF’ݬx;’ýî=Ür–@a“,üÀ12í×{Å¥ŒíÁ l+@Œ½µ«ñ ö± ctÂFŒ§£†¨ën7ï "rlgãÓI°2ç4¶_ÃÏ+Ô÷rBw°Òð,šºÁL~z2Cú%JÚÒ>Y¬ˆ ƒhßbÕìF¸ä¡+sèl”¥¨·‰uDì¾²™‹šGçl.Œ~Uâ~aó @˜»×»m7²›°_š nŽªy•ÛҾ؃¬Í‘ÄTÌ|µOlM†k!i10baó3:¦Š{!KÔŒ%ðô=øê VBmº6VŽ{D¸¹9¸œs${uÙ#èÄBìvP7»"–!ì‚ s/„Ç<ÛÓX–Øæ{,Â93­’ë®7t¦£&ÖœI›)d£}`¸¶¦GX%g köÀÖ²xæ°~¢¨Ú Î!›'´ˆ¼ÒäD̺io„8Â\où@ä 11h?®[·A£äfð¡2½Ål³XÝnÞ3Ëm?‹¹7É.öó_´Ã8hÝÉ3(Șl³jC5÷7pëŸ!U³„¨4¡qǦ‹¦@÷ÉH]=ÄÄt{§‹üé&¦Ž ‚× 4eòåA¿šÍp…°©àîzÂò b£0aæ¾V_ïÚèquö¦#Úa Ö¾ ·8ö`#`ÌŽ·ÛpÝA…vØÔ‘Kb‹Û !Fx”*¤×ôÓœ‹Û€ŠÅÀMZ¥?¤öæEsoQé|ÑnÉic¿Û‡öt.;ú„F±r'H9`¦_‹Ð/|/‹‚ä6ŸæïƒèZ?ƒGüOŽ §óý€ûÅ@˜ÙÌÚNr›sñ¹ óÉ ÙûLÖ(ÚU¢=C§$Œ 5Ó½ÖÀ·Ûá3¶áÍ #A/5¯¤`•\?Ë…Œ§ öôz{aâ^|={ÎaôÛõ=¶ÛiŸ4-˜ e²ül¢œUÈØ_A×̾wY*h"iÕØÔø‚Æ#sÎøö ̲îP„Xê‰u6‰2ê-`0i\íѶË)+³I_¤l†ŠH¾j¶„´G™ Œ‰èap;‹= ÐR¢ãíCvfû:7‘®E0jl]±Hllý¥¦¼ºú¡ÌdᄠܳD}ÞH׉ ¬×Ó.²xÎáVˆP3Èõ†ˆÃ­<Üάóˆn'|°çpëÛį8Ü΄¯cãð‡ÛQêÕ¾@nÇ‚rŠÃí@(²·c‚ïy¸‡[!btcÀðû#‚ù@ÄáçéC¾?ÖG€~øK¶J~Æ– ôÃÏàŽS>«vXbò¬¬vÎép;ô·“ÇCn5¿<ܾÎ?Xn{nùŽsÒR ÄÏA–èoGÈ×wÀ}5´pK£²Ì… X¢A™O8­¯î©…®sê'""m÷iÙIýÂc°Éa“sx%ćÖ'öÚàÆáìDç&€Ü¾DîÅ`Õžpje’œî‰a€›”âáá”-Ì 6/KÉî¨/ˆA ¤?"\¤Í­4»ñ°‘O“!ÝÒ3Ó½ÐAt¡˜>˜;‚ßg¦^íŒmïn˜1°èc™¤êÌݬøùTMºA½=–ˆ„ÆN™€ñÿ~šòÏQ*–ÀD+æ-+A­sÞ¢/&=ËN{†Š׊TÓ+:!wðf&!6¥÷†©›®póh(£ýiÄ®àé­åÈŸJ¦r­W„ªø9Q˜ˆy·—ˆ|é$3Â<®:„‹U¤ÂŠÉx]îX —¬²ÍmÛM‚06Ädæ‹1Êîʶ“¨­\o0ÄdTó|&cß‹¨»{(¦ÃÙÓ'Ñ>•×mç±¶—"ï±ù6ÄDTµUÄ0ÒÈH€ªˆˆP{*8÷ ¡@‰LãœiÝE¼*컆(Œ}–±O ^Æ{D¢xc_åE¨GÑ?@LFæ D„Ñž%0ºw¦©‡•ˆP%"qFWU1à q†[•¨ŽáV¤™h¸È=¸† X ·(sÃ)Ê'Ôp#–íYš Ãe‚÷nR 7)âÃ%x†•£[û5…Gˆ³Qà#ŸUÄ0»l!~m##œ1lE!¾[#äVä!¨Q Ýì|–#Ù~ëh¯Ñp2’k7EvYE ©¼Ízþ¶Tmõv+±Ò¯È@(â±§Œ¼ŒÁ¸Bgî!=Eˆ?8ÀL³7út+‚¢¸¿ý€M)ò8‹¢µ—öÕ#²'˜<#ÒT3¦­÷T3¦Ó lGç}ÿ…@ú9B »j† Ò?—®Hë“Dºÿ¼‰¡LcÛØö‰xÄØw¹Ú‹4¾…@å¢8HöŸ'eR›aÇ@Õh〠B ;ìéo¯W¤}›` 4pGë;ã+ßÞîâ,F Pš¯Ÿ²G4BV®¯`#„@¾±8¯Cã+Ò#B l)B Ló ô©èéSqò-}8÷.·«ôŒÚ‹bõÍÔÞYz'V†sõŽHçù!Ö+òm0?>>gRÖT $JzÎZ½oE’÷SàéYSÂl$2ÍÒ²¦ œH¿AÖ”!¸œ,kªg8±™eà8IRßѡȚ „f<ûäÑ f,ëp·zQØæ!kÊëÛ…É!kê‘5%ÄE(!õ†¢ê‘„’¤ÞfÊ'/ÞYS=SðÑ3'²¦ ,wÖTg¹fM8ÑnYS*kêB˜X÷§OÖ”½=ƒhÈš2DƒÐ³¬)猭v¿Š %¼å;ÔÎ2ZÈš2p0L+9#ö™YS]E†5u8B]ø¸Þhr.„‚+k*‡ø–DÄPJ°í½Û­–5åƒÂ ‘5僦¤Þ J;g/#Ù>2@Òr·×ÈuX™Î ?³Y(”õߌFEëÄUbŽÓ‰ÖÈšò§)ÉŸ‰½¹5ˆQðùç©×„OFÍfEÙPÆðšeM]dMÉ<>Ã'kÊI¹ãüñí¤f ³Û™Ìé¢3÷[Ò‚v»]í°drÓá”UyÌѱH ×@æä˜ûÆ@ò#kJˆÈšòö—²¦œXÌžMø+À!í«ƒÙ±½OgCå|qö_ûºÚ'…‘5e óÉ´r—¬!|-B¿ð½«½Ò”æ ÛT dê…ªõqÖùD¨"†!xœvò€å”é¥ÊÁÅR@R-–Rµ}1X¬ð¾KÉÊE{ö# +bôr,ÐÔ<‹"V£—$ùbÜ J1âinkøö³­á×µ­aß4ìû™ßuÁÐÌäú“”‰Š¢+bˆ®¬ˆñ6™˜ß0& "Æ…°´w¢Þ6NÝ AšÞnh‘cý¿R` ÜÇꙫW;ÂmâéHOÒÛ©·ôõ¦ÂNè[€šŠ¦ŠVu"žFMŠx»jVèë¬i¡¾I.°ïGnplÑžurÂÓYåûôvRN_']Õ·ºûTXÔîÉç}¦¢&™\‰—½ •xA\×QâVN·%nÕpÆQâC‰Öœ"Râ^(ùVâV-'%þ€J·‰¬ eab¢kzQò•kŽJ¼6‚·xÞy”x,nWâ¤?*ñWÚ¹·˜êz+q!B é-ˆPâ 3–· ä}ä’ ªÞrÉ‚˜O¥žÎ0ë;[rQriÿ*w;¼XRâVÜhÞJÜ*A­£Ä P‰—¨G@%.•ø’;\‰?ogñ#*qãžr”xÙ:¹¯I¦r·HJü ¨Ä… n©Y–tWâ5+ŒJ¼f™Â\‰×¤j{¾Øj˜õµw¢|1n):WâeK S‰w×£ÄËÒAÅ•¸Šª…'â(q«ü=Ž7bµ£ÄË1Ã@‰õÖQâOïÓ± :_¤[ÈÛØûÕÎÇ#1îÒãàg»Úµ¶y¶{tøÙ®Âò«³Ýy¶#â"Hó“É'â5ŒÉoˆ8۽ΔË1 µ`ÕÆQ Œ¼—Z°ÚDåV V»hµ R7T C-„«{ºµ`µ]Ò­XªFj¡å—³›uµÜj¡!S<ÚO "S áŠG-0®_jaüR ¤Z8ª…WÚœ]Þª!‚mô–D¨…VU÷ÃÕ‚uûJ2/¤ZhaVsµ`Ù§’‘ìr³¤W"²ÍÀ<…’ dí)ª…º5C®j(fW C-AµÀRAR VÛç.”äó %Yßæ)„dC¡?“jA¤ µpT BPZÙ ·£Z•I‰jÁ8dµ`¤¼öh­ÜucA»}©–£bww–»P’3û>j¡%iW -…wjˆ£Z’uÜÕ‚•iJG-´ðmQ-´Þ¡ŽÞçkïߊœUT ­ÞzÂH•óQ -έZ¹‘&íjA|-B¿ð=®Ë3ß\E iaˆÊë1w]«BTM¢x¬¦û÷ãîôÅXµL¶…º`)ZàíoŒ 7¯°ß} ü{m^í˜3ÍîßóÀÃÂÐBw#V³šÿl1Z²xî@€•Á38£k¯YßP`[<ò°•1ˆèˆv5[­÷‘í¾áuGÏ»+™¹3¾á|ÂåÝ/=¿N,«‡?¤«âÀºct¶ÎÌž»c‘÷cÝù-ðϼοûGaüýðà?!†]õ#béqm)ûî 1.DELÕp?- ñOøh ÜŒh„ŸÓQ ,wí_Sé^Û}XådèÀi•òÕÉjæ p/Âþðã^>„ ZBû°Ï›/Pñ¾À9ñ´EZÏóö¬ ŒÙu找qþÔ÷3¿[Ià˜ß­œop)s¸‡”w‘®þË×É„ÿµí8œßaVÙú%‡ŸEðm€e“6™NIf¦–Ú3õ×=Ôî‘ø:1ðÞÿ}µãŒª§­÷ù~»)žu¾®þ³oc*ÂÝåzº¸»-Þ®øøzö0Žè’u¢ïJ扱±]#çÓ¢L¼]”ãסáÊ¡;¦bG ¥W5„ÖMçõŸ¥èÇ#U5¸¾v6v¬j` å3ª‚Ī˜—®œªŽSäàûtHU ‘ÂÿÊGB`î}‹T ‚û­ÃÒÀYÈ1Z,(™FiˆðÉ@‚Låx¼!B:鑄мÍÔýW&üùdƒt^Åáœ>Âõ:;éìždD#Û}©æï[ÈQ49 ¸åB7ùÓÌö˜é¼½xÿèmäŸp^éÑwe{¸7´\í¨ëãO›k“«…ñê†hyÝ}è8x™IéÕw"ÑOw¿",ÞÞÃiƯ¿ž/ú&º¾ÐýûžŠ©-}‚‡€ÿ :픑fȨ$/s—»n™`Ð= /À3œ¥MÅNû+ž¶“~Þ~h˯'Ï‹¾A¾GßS¸fQ^/Ú#õO××4`C¤ûë¬Ô ¾<}'Bc‹ 0Œ¼*ÒY”‰ôPŽ}]_èþMϳ]åJôÌZ4ˆzä¡òc†`ò’i9ÉÝÉNÌ“Ž4ëá˜uÉÙR™¥ßÉÈæc™× eÔ^¢þvïÖGpØ0ñÊô¿»‹ à[#3 vñ4öñvíMâëØ»Dß8ê»f Æ6ÃsÖ”XÒe´¯ Ê16FtÅ®ìm21¿(»‡ ár)SBȵÙyo u¨»AghØ~Jä4:ÓK¯ö‰½³ž^ȸ?o_JÅ×—ÒIз5KÙ%Ó]´KEeê®çíÚ›Ä×±w‰¾Q.zCK16µweàé2‡o'åôuÒU}{¡»È›î*Ù£È=ó0ñ\Ú&yà¦÷ªC‰q#'ò¦ $wl:ò*6â²p¨äM;³! ÅãÒ •7¤RÞô…@BQ h}¥™yÓÎÐúrtö¨K0áÙœçÜáKáìÅ@»•¯v„2oÚ¹w}¼içn.ֹ«ɼi‹ úJåM‚I›¹`mQîZÞ´¯ – GdWRg ¯®„xi¯'|ìw{W-Kb6BR.iåÕšñضû­F¿ÑÅ÷p°<Î%ˆcˆÕ#ªBh“| t.¹®›jÒb±s‰Nq.‘CQç:üt.1Ï\ ðût(Î%BÄêÕ#ñrPq—&S’;¼¯\Ûy„C”단Ê*­Ý Î%‚˜K©þ D-aõxCèò6Sp{nU÷A¡š@¨.MçÍ/mÝׯÔ@ª1E•M~ÍDƒc§R´»ÁyJ(r‡Z™EyÚ×)Tc^œrª1÷WV¨ÆzŸN¡É4(TªñN¡«Kt~ 9¼;ªîá0 PÆ>cÛ/2¸v•%C{—H6.5Ê5ìQqµ ÕH¡k…jT¡š@ P?}ìRþö—½áóõt ÕxïÎéý:bÃüc×Þ°®H6•[—ê5õð+°rMJp$ÐHfôol±±Tó …jƒ”‡kÔ¥ªcŒR—ÊØp;V§d¸ªñ©8µ/Ü]˜n‘^YoIí]"Ûlûεw¡'Ö)Tã­ ÎïH‹–Ã(Ú‹òœÝraþI¼ ¶á#¦Eèb¤EÈ‚'ÜÖ±bf¨TÝU iÑþ9œ}õ9nª‘m½wÙ‰´gŸ™úuÒ¢;¯Âˆöö‹·P[Z´yx2Þ.ï)‹!-ÚÀRør¨´è aiÑÒвÝ÷ÚU‚iцh,ªiËÙüK¬Îâ`ƒäSZ´s 凧Eû`XÆ*“ùíl×&iÑŽH_aD²Šp,`^ÏVµÕ`ª¼ÞÜL#-ÚAJ¯.7ãÄ×]ž5¹¹DιîŸÿÍiÑí3-ºyZtÈÏÅ“"~ÿUêÛ=ÐúEÃÙøA¤ôß2-úïéÑ¿”jÐedµü~ÅŸ'â'ùp?ñÈ"ùç…rus¿Ö?ÂsDî·| øˆ½vù6Ǿ”²¿V2üq„j3n ÎÆd Ó3y1ëï¿ aËÙ°1jêç­;hR› ý§€hÇÉ_7,|™;J ‘ø¹d?ÇrµÎ>Zö]»ßˆg£i Ÿ LÅßž´‹øöÚ˜ÍÛg80”Z6ü|¸3é;I;¿èÊ(‡ÎúĈçíàíÏcÏhˆ†vÆoåo¤ÂüH2Ðc»¶{åýcËy;Ÿ™ ¦jÕ{ï!ËÏŽ¦ Æ>ïvlŸ÷òý®S?Ç6Ë¢`,‹‰(§Ïó‚K{bÓrad ,…Î@ xTD­1Qæ¿(÷Ìl»û3S1öY|0^X~ó ì3S®vDâÛÓ}9Xô±$Rás+áç3ò©¿€U”ÂI5]9èCÁeó6«©ñç…ˆ’¼³s¬X™­=]á,ÀîÇt盤2p7P~ÏÔ6U†èŧb‘‰÷ Ö_M3³¸¼^‡5<]’kpÞw…¼ÈûZ¯¾oõ%r@LļÛqjw°‚T‹bN”]|{Og>±ž.Y…XlñÀ'¦ö`oºa`Yg–­’r¿â̲.qEœ™­EœY€Š3»gf 3,Î,ëUÅ™Ù×yë®Å™eÝ(‹82ïê‰FþöÁ´~µ¯sÍù37e+¨;¥¬hWÄ™¸jÄ™] âÌ.ì=o´s}P“n€S* +‹·| ú…`D¢Å™eE|#ÎÌ•¯83Cð ‹3˺“qdF£~g{:ïö¡Û5,Î,Óªqf†`®žÅ™¨ÄÙg¹¨8³@ ÎÌ@r‡ 2ûXNWœ™sOŠ83ël=ñÆ6”ëþ½kgv!g„?ù ˆ33°¶+ÎÌ)Gœ™“ò–Yw®°2°cß/í¥Fœ™Sv^qfÎÝ9âÌ|ô3âÌŒ6«]qfBDœY>÷âZœ™«Dœ™/E•$Xì“_]£ÙmÌ%âÈœ/îÔY{½ÚÂ83ãÛ’®83CŒqfÁ×$ô+ßûR@M»(D“ŸÓv¹sˆ„8K| ®B4Ù¢ñ敚dÝpjÝîxÔ”Ú8ö¹¿Ýy¨n]kÇ'™+ãsX·á¢ÈuEŠ®·/¥•™M7ש\ A†k¶«ØÞ-(ò „Ã>gÀãõn!"xX|"”ëo]ˆk|f—“ëï#PbÚÖÇ—rý儿s)$Ù¦nUÂP»®r^ 7+]p+Á+W ñ0¯OA[p-)- çü·Ùõ ïIkÉÿP®nð ½ 6+­˜”jY-Hþ7÷÷r«÷ KëkS·Ï9k·¥àg°¶!F¹Úw1•Ö¶nåV¯íH{3…j5´ñvKþ7°#vÖ@(ùßÂxÌ^ǯÌd .òÃf¬!VŒÉÿ^òßÀ|‡Û`¯ú>F *ßÊÙñŸ Õ“ÿ ‘˜‡k; Ú"˜ü ’ÿäš•@2ßÎ8]l¦J÷1KÎçådAZWw¿Y‘E­£}ëšp3ŒÝ‹ä§,“óm¢ÄFHþc3—`,§ÉÿŽ€È6k‡/´ä™ˆä.Ÿ &·X‡ÚÒBuíÑÞµK›JhEûPñó9×2,'Ž6”¾âº³ñ^h$ÿ;Èê>à«×Á`e-­MŠR«c°o8ìù΀άÖ{!š"ÉQ3÷ª‹ õ‹üšjTô$»“&÷¨ù@‘ÖáF¾d»Å;ú¬s¾üâe,8›wm(8„91îc}Aì#8½%8FÖJ×1k?ê‚cdå5º`%î‡à5n±ôvD KpŒ—¿Æ1ÊO ?K0óË5GpÑ®3"/tÁa¯GpŒª¬5⪮ôtÁ1ê}“³æ Áد‹ŸT, †3`R"!GßJrÁÑYŒ‚C`!(8:ÊKIpŒ7dò–”yå‚ÃæåÄÔ[ßÛ]žÉÆV¯­Ñhâ¿Ì3ï@§à±—àQp¼²™ ŽÑ”ŒEÁ1šr \pð”(Á1j\ÌÖc*ò£(cÕÃ(¯÷DÛp×µmL@ àYyôF¬~ÇH*Žä‚CK Çë`|eͬŒbÄ Áoü8B©vöRóŸ2çÖæÇËJÝÊPäÌ¢cñfFð¤AÂdörÀÔ„U늧‡—oŠ·+[Y_·eêf¨­œW,ò—CpljçÈ]ä Œ ·h‹r î3ÑÕNÈÖ÷‰W›oaËÑÌÚaZMnÓž&¾¾¸{H1O…ºÞ‚2^kh"¨“L|’®&3òüz[.,&ßç!tÑlž[·ŒÄuólvÿ—nžÍs½Þ<›Y–7ÏèEpól€ºyöBPg®w÷¾"”˼#Ž2Ÿ3Ò—_×#ã5A2ñY=òB?à„sŸSæÂµ¡:e.yS¦-ÀuN™ wDê¹"g”§ÌÕT~íU‡R?eZ.³åpÊ\L-ä)smíü”y@ž2…ˆ9bzÑââ„òÎ+EœÀSæ ¥ä{ëã:§LËÈ’ébk„ùœ2мiñ­vïô¿ÜWîtЗ§Ì… µÏ)Óf'Sæê‘Bg»‹ÕµVyÊ|]Lø¾+oÙ„¯8œ˜ŽY‘n¾Ãl;ꘄ@™Žyt^S›3¢í Ì+O›¯àb¡„ _ÚN¹3Âúvm$Ù÷£cÖV5;og¶‘?=ì¬t‚¹ÙIbÙüÑÙ&%$ƾAö]ˆgl¶•ÓÓÛ8âí[«‹_wÊ•/õ-èúB÷ï{*0÷¿ý ×Å·þAfå3läÚfcÿ¨î—YªLR‹˜YWàÃÃsâéáÅxõöCÛÕܤȾI®¨$F ¹–ÊΠWÁêé5T¿V3öqÿú‚ÉP}x؈ŽMOsä|û¡ ¿.ʱo±È^èîS±7ŒÉ*›jQmlV<@ÙÔbŸ»ðª!X¸Èö}^*¹˜ çþ`1Oß¼Ú¶±Q6Õ@¾‡bU!5-ÒÛÀŽy·Ð U65’zöÂÖÿ„PÑ@ Ž¨õÔ50sgí“mRbñ³² ”9¹'ujñÙ3r¨ôŒ·ã†¯:¢FÛIÛµ×5g×7¢Ì bÑUG4!ä÷z3· ¡áÃ5³oÃÍ1|1\CŒÃ5°œñå=Bçq¡ØÕ{{â>ÜG<·«Æ†‹°·.Á3Üþz•zÞU…¿"ŽNã#ŸˆPr¢\JnwéeWr»#î ”ÜF}7)¹—ýjÏû:oÒï–k+Ì  .ÇAl/U@sŸïë’ï^—ª¼{ãNiû} .uVúBªñÈB1½Âô«»=N®¡óÎ5t? Ú-¦×üŠúOp8ö;×0:¤˜Þ@(¼.9ˆ@ Üñrr ³ÒÓ›fžéÖÁV1½ˆ˜¤@‚´¸§õqˆÊG> á}›)ø{Ü&;àKì¯tš¥§?!tGO pGÌG´;z äEcH¤7 ÃA펙æë„© TS¥ù\ãª+´…Ú=™Å~âŽCTÄ Û=¹Æ…AvGO€º£'gtIYqoe•Å#ÝÑcF¨ûNªfÅn÷ç%R!çÑG¨ôêí¼ë^¯ªK¨¾ëu#évú,.»£ÇÀÍJ¿£Ç&”n¸Ðü¢ØÍÛüÃ" aÞPTwV|ïhIß>GK =~’ª8E˜·!·íôi)®:tOJR‚)ezCEýhϺ`ÔÃ^ZÜ>†0ïܘP‚0o%ìDßp5A„yBaÞ™•Gæm .«ç×øaކУîOÈw   fÜI˜6öqRqÜ1¦$Ìê ²i[8ïH»ç^A<½ïÕ*Ì;óö§O  ¿K {µ‚Ù’6/‡Õ¬ïmܜײJx ½èö(‹l4÷†Ë)¹/É'Šl„0ï76ç]¡ˆ0ï¬ Z„yûÁ»n§j¼ŽJaÞ>~Jh¬‡€0îÌ4æ-·¢ÚkÔ0×zVz@â+¯B˜·óÙB[¾cÞí!#Oßæ¥~ž¾¿dbûØ.!aÁŒ³Õetk`P·]i÷~]ßt6æÒzòiî'éß4þ&€–|jN:¥%LåPáK>50“+í¸*PɧÂÏö4ØÌ’O ìØÆ!ùÔÌ2¶äSëŒJ²˜챯¤Í­ó¶>µS„ ùÔ½@$Ÿ^‰Ú)&ypÇÓꉽå‘/bhëÎMK>õAõ¯“|j–ÝpËhŸºÑ‹aâz¹³†ÒçÐ΋‘|šupœ:ÌpL>50³ ”m=*ù4H>õ§~oÑ{½+ÖŸñM6ÿ þ7!ß§î÷v÷&À‘|¤Ròé… ÙÊT‚ÜÚÊTòa#%(ÙÝ¥ÔK>uRÞûåío_µ]íCt<@¸x~í¼4ɧYw<#ùÔ@Ýï=D»ÎüxÜìm(X[7!›¿¼~äS_’ è};YbÎGÐpìw{ìF  ·.SçÊ‘ )ùš„~åûoÆÑW áYGˆàü1u¿ô"Î:Bð¬cÁ²Ø$Ly¸ãa,üPÑ?ë œ×Yfô(¹³:_®³Ðˆ+™ý¬c¾8Úð¬£+ZyÖ5ªKµ}À8ëqFWTÎâ GH=òˆ³Îhªó€ö¦Ô?댦9æYg0“ˆgÑ•ž Gæ¸6 ß¼”ÍCnn@ý¬C'ê9ëX02k@ÉI‹Ùñ³Îëü;KÌzoÍÉ\´…ô5³NSæõɾø:¥v²WbûR©÷ßAz˜„04óA˜11žF©;Ë}À§2s”…²`}»ÎAê{l‘f íãí-Êá™(™§¦b²ŒJíÈr"VjçÕw"½Â|¥vâí*µ_G©è›èúB÷—©P©<«’ÏáÄnª¼“Ý=Ke ÁÓ€ÙöÌÈí»ëNg8Cº×ÊÙÄÓ(vo?´mq(4¹­¾Qg©ï¡Óf‘í9v“þtzÛÜÒ__Oª¼ƒ¾<}OJ8Mt#óŽdŒ<ŶŸ”ɱçÊ`£{÷Jw8GhrA)DŠÆ'"¥”+Žn.(=Që”+‹?\P®|_ÌœyÅÞ”+E¡=k7oëeš;2t!('3·)(ͧ=Ž ‚Rˆݯ»þ„¹¨G>!(éh— ´ÔÊË(4·tWçJº­ÛåbÁ8NÚJRÄòéä»n¡‘»^F¡UTn‡‚rÅÑܥ旂òuþ¿é«¾ê4ü†éÅÚ(Äa‰®«Óßzäz-li×kø&Äòµr½å¡GþéVxnxÐÞ‘‰Ìò®R[¾¹°ð&ˆ'€4eÈŠÎÃ<Úæ¿;• wž¼“j¢=… nÙ©ÒXM®TÖ*ôƒöÚ2%øaU`,ÿƒðƒ¶žæA{‡ðàA[_çA[}£–PßCiljçÈyÐeâ -Êñ -ºò -ºÇA[ˆ8hïvs;hï¨aêmû'ÚeŸuÐÞas9û€ýE«Î"ÛbkuÐ6g¤†ºèHe?hŸ¢~Ðx&"JJúA{EQ?hÛÛÉ3tÓn¥ý ½ ¤%»ó}5;'"_íE¥Yü m”ÁËxÐåxÐ]yÐ~]ð»r;mÞШƒ¶ùÖPÝÃÚ{ÀìíÍ;ÐyÐÞ#Êu¹Gœ`´޼!ÚûA{ëåAÛüZd4Ó{†¸ÂMxUï‚ß*Õ«}©P.¢VËÀAÛü–Ðþ~ÐÞ<•ñ }@´Bâã…v&sÜ Í´p?h"äŸÞòȂ戡%'–´÷Ò yÐÞKeŸü ½ç]ÐW®Àk1 ̯ڣàȤ³“fu9£R–´wSõN?h Œƒ¶;hçAÛ©mÌøž—³,´¼:X•3}éf÷#"ж+zäч¼imz0Óâz‹çŸÕ#@LìG…h^«ÅC–“ÖeMCbŸÅ7%$YØÍèÈálˆãL8Ù[€ßï3%ïÇÄÀ°ÞqE.n:¥L£¹aÙ&.{œ ÏÛÍmððûYN€[jLáì0„ùÃdoO›±2åð˜}q®±‡faK0øû –ŒúÞUZÆóKæÕ;‡? ÚÉqÏlɲ¤%|ÝŽ`–3Ñ·š¼ú¸+ð´ÅÜïóvÈìÌ*¤\ÿRß‚®/tÿ¾§¢Ê(Ü‘CE„}¡‹sƒ1ÿ”å„ì6ËE)0ü™4´$€5x†D·«mÒ—ž6cê>o¿h‹¯ÛSfZ`ßÜŸÎT 9Ú:v ÑŽ*÷ñ4RH®·g·áÆ×“K¢èÀ«ïDhlx:FŽ·_”Á׃rè[Ðõ…îrw˜ºDÚÆÜkåqÄù@Ü‹mÀÒ; ¯_D¼v úq^ËG>“÷¸½l_kŠbf4o0oVô“ç渘Yº3ÙèšØzµgb-ƒ¦_íp-uÆ)Ž¢J=pˆ-:O©@~NÇåyÏÄ 8B=m‹Êm…E"—F~Ý&ÖKB ošXö=&Vc‹vŒÜŸA{ÙeŒrƒ¤«'w¡Å5™°e0^Ò —‰»jÌΰ' ¤6D[´q•œ°UÂ4°–ÄpöºÚqWd< ãÙõö!a‹¯“oÔ7çLE <`•O{â[‹·ûÌË5ƒ…‚±îÉ:âŽ}q§±E;FOƒ2×ÛA¹øzz¥0ÎQ&í‘|ð;}ûñáç/e¸¼"@O:™ˆL0ï]둟c aâêt#÷D~ͪG÷Lœ‘„›¸T5Ú«oil¡T€Tt#ìÀÏÏ;kÇÛÍ»P\ʼ±æ­w?Žè¸¾Ó·×œü:W-Š{ywˆH°Fšï[‹ÜOd·˜ˆéˆöä[W—î 7Ôˈhy•´ólÊí»/ið$ÁáI—øy—€Ëé‰`Z ÚïµÈgÑfðä¹+“Á~-®ú“9õ2\WñZ(Ÿ(òUö[ ߨ œ×°P’ŸÁ~eÿœ5ƒ¶ÚàíýXwfëX nÃ// e"Žê,$?§^íYÛ7/à3³>"Êˈ…]‹# ¬½²3£ž¾÷à«k0?Ìn¢T,‘Ý4Ð%£ ëÆ¶Á `ÅÏ<µ°î 1a4Ml§•˜¦}æA”qµ/í›Ü`1—ôÅ+qƵ۞o"Õz ²ÆfØ?ˆ8Út"ÕìqöìzÇ¢°Òõ#„d@ö·©‘±Â°í —5ÂJ5„$¥1.T 8ükô/í•JÎ3‚wo Œ`l3„IÎ…Äf¨?*ýæevèx0+Nlê…œV"~"ˆ¦G>zäŸþ ÌÄ-âÊÕ!?7ÂôïAX¢êDvTæaÃdÜâÉ%yCØÓ+x¡ä¹Ubô³IŽÜ*Ô[%cX¬çfMKÝ€†s?âBA§Q"%1ä.‡¹” X<6ú€Ü„Öìu84ãi¸¶FS¢¬z×è @ñwO ‡s€'hölìó¥=ái?êÐõàÇL¸ß`Ÿ«ð¹ön(æD?Ð9a Ñbf²k7s•›ŸÒ^‡mløœoÓz|áæh^˜™†c™5ÄØ¹•¤lF»W&Z(&1¢rÑ1Ø…Ü™ëË_UÆòƒðå ªïú¶ƒ êF^š.…ൣV“ Ÿ 9áÆUE ~û¦ŠÊE6³à;Ð…ÂŒkm×¶¸QJʇ_ ¤ä©s¡j™ d—žM›4 9Û†Hx]Áë ŒQwÇÔÕWe|ݵßSZ_×e"éëšýÛê`öÏ:˜Ýë`V+ÒótØ2hÜhõŒ¥…ñ¿°ÜX±f}ýÅß[óïéÑ¿T³&ð³k~Ûº¶(¾I›_5Áî蛸ê`g«§ÏÂ+CN/¸ZËêM¿ÛÀ´Ÿãœíðˆºæz;Û¦,ÿ9´o£žŸgÔZñ-b¹@O€z~.„U 4åhŸ3mù‰@^õ(¶6ôb’Ú稙ýo*hO“Ä>Ü‘´ŸOöíÈ4ç®Ði»H{¼ÅU‚âS‘ÐÙ]_À²øsGœÑ!"ãq†+‡Ûbö}¸ḆÛP{SÃE!Ü"9¯á¢8t´ãÍnq•u î.òØb¸äp‰8£Kn%úDà<ósùDx™j §äÙ¹x9‚°5ògÖ%9òÍΨ}±;VÑŽ’±XZ,5?ÔWTÄbK>áMÜÓ¿Þ–ªmÿkžœÏø}!|›üŒ/w ½ ¶3/­š±­ñzÛA;ÞX 8àAl"Œ>¹¡$©j†‹‡ ýœ}T; {.]:Œ…Ú¬†˜|¾[;®iöZÕAszgœ>p±òãˆLx„¿ŽàÀ×+Þ{·‰hÝ{ïÓa`Æ`j€ösœG¢g%ÿ˜uaQ©ãÛ)›D;ûzæbôË›c?ϱ6Ÿƒ?ÍÙoO1÷˜ˆ,fYÞ™}Xͺº£a¨«\ípÝ’‘n‰+·õ›²à­ÃFrÿÆfà<ܸí‡óᜇÐO-jø _سƒ¥ñýCS!AZœö’üuc8#@L…DI›®y=G±2œXT½:17¿žºƒk³ïMlxc:³z˜ÙÇB¢¤öáQä?×#ïˆáA¯“¯%‘e\ è/´åà Yr,§ní0>ørÚÎà÷éWC`Æ#H\îŽ0°Rä>6PžÀ6;:lÿcÁ– ôáâç}ÜÉ‹âô!¢Æ#Ÿ˜Ÿ÷™ÂäM¬T˜Ñlò(x€¨EšÔ-û6þÛ^¦ä koÜã¸õ Àá=±ŸDÆë¥˜-ìâUtoïzÏéÙ@IØj< ¡åà·÷}«}B% ¿ÐÅÀE‘ºñvTpC–}w¶º!«ÐÔAãÏ…Xà€Úœˆ6rc—k!Ûè+ˆu‰ƒv!zÎK o Š/ô¢Û†ˆ\r¢@­@ÛuNó–Ô¥S±°½a‡šÏ6©Å Kó°m©±NÖ n­#I+äá¯wLpÇpâ":æwqc‚Ň Þ3àˆŸĪ/?èú ¯£)Œ(ëö&íz¡pÞžŽ,­Ì>¢ÕÒ–óÕÎrêÜt”Î-aýUĽ‰oÏ£g{*Vé‘NRW~ÝkìTÞKæš(ùû3S.vžòæç$e}0Ò#Pk–~ö_ûÝŽÒþ±îàäP¹rw(Õd‹EŒNB¿ð½«½ÚC1e³GİWÛLªõk£ž]ÈÂÅ:³žÅR;—< ï:‹¥¶#ÅŸA[öõµ­©ü‹¥Â°íGšáõ\kEÌ׆ý<³}û„ÕòeÕÂö‹Ÿ‘ÑY>MfÕÛc[£¯s[£¾qþÔ÷˜_MíùtËCPfz¥½ï¿‚rÆ}õ+è:ý*Ò·ÉÄü€Ïáü~A‡TTêpÙМ”X{µ†˜ó/Tî0!»+%GÈvÞ–íˆ·Š§;Ï7ñöÎí2¿®þ³oäTá9 ñôô‹bâí˜ü<“Xy~Eß(Ô÷›Úkœœò<”9o'åôuÑ•}{¡»OEóRù—o(8(%Þ¿1Ü`‹>J¼%vJÜJ—£Ä†¿¯ƒ‚op]%ÞRluL‰·ÄS&²åÐù˜è–_”|Óšƒoáí•G(ñV¹ÑƒJüB@‰¿ÒΕ8/V:J\ˆCñ•Ä:ˆ4Ž\j˜‘\j%^¹ÔPpUr©!RBr§å‹K-a~%—PPJ¼î‚Pâ–­µõh†ŠRâJ‰ A%^wpÇwÀ®%%ÞPóAJü/­m}ŸûVâ1RâJ<Ð-íœPü……ï—7ÙG‰7ÙN°Ø,Íý‡À_i]í))ñ–âô%^á4•¯;*¦Ä- ^†ý¼Ö[‰³\·”¸•Û–Ö.XŠ:msµ£Ä[¦™BÜøâÅjÒ sl‡«EJÜ.å’‘SÕHJ(ñ`tú…ï!Y&÷,:ÛB‡ ¦cÿ¡ƒJ<òŽˆ³Ý…0ÝÔ& øÓÊ2S`àlgÑu’ýÖ~6Ðv¶k+ %`gu(ÎvˆÕ«G1ï}Ge¸ŸÎvmÆÚÆÙ®ñPÌõÕFœZìl ÎvB‚ô°¬½!‚¨g÷ö†ÐÙîu¦\Žõv4…«…^Cð›ZèZIXØ]ëHjÁ³úQ Î'©¡.DÆër>jÁ’þÇ­:êK-ôòrv³Ô÷à·÷}_ú¿·Pø&tz£”Zè2·A-ôN µ 0ÔÂ…€Zx¥È9(I¤„¶‰¯| ÖAh[ã4ÂEîR ½Å ¡zãùj¡ãöf‰ý^cw µÀ(ÐhGñ3©…ŽJµG-ôÌçÁ¶ý(æuƒR BP-ôÜ1Á£Ýj¡î‘ ºL>P ½ÞG½{¤.ÔB ­º,ÀP ]b©…!ûµIÒÞbÓeb¿Ë&µÐ¹P»6eP ý콋¸Wî S =‡1µÐsx !µ`¬£ŒX²Ýeƒ„Zè%¤¬†öUŠ}ã‹cÁäØçÕÞé=ZèçÜÊ•;˜nj!„~á{W CòÉOn¿/„ÿ}Æg>µù†€rq„Ø#ûu¡uTú–:»4*e“ç«UÄøÌÒ¹çB@>ŽÎ“ýB26yGÄêµ@‘ñ'Äy$ÓéõˆÏ–ðs| FzAt3ŽWf•;†ÔÍöÓ‹)×ゎ©ÇL8Ùw€ßï3årl ü»d“7ß,‰ã˜œ8p>òÐ#÷kƒ'ôZïáf¾û-ˆÓÛICj¼ÖL¾_+DtN| î×.nëä „¼?8¿!¨ßlf°¶þ!w±¢¬‹NùÙCºš;hv2Ü=žý ý|ælŸÇ]´ìl…;ˆÁMrÍÚÕ,sņî @ÈdHÕtÿ&8ðu¹{àšó8|º÷^ÞS[ž z+¢ÙÃÿãí-ô’1éäÚw|¦ÿ;h¿›¹ƒ†;(pMy¡f½%÷·Ï›ìjf7™ýÅÑ8GøÕ!;'’ç¢}§›;ÈbÈ(Fàš+œ9 ±Ù™œ¿ÞØÌe産_î Éý-ÝAsR.ÁäyG|ÿPÿtÜ)ÞÿIÃ9j SÑ/½6{è-Z– ¹ƒf‹ií)1 wФ58ÜA¯ƒaàÉÞ<£'“]¿ÝÙ »š#~Ü7ìÞ½7†õ'~ÑÈ#Àå*×#({ýbq\ø–ÃÔ£3½¹…Ó wßZNÀÞìØ|}„›&!Þç²$'²¯Æ›36Ñ!âµzäñ§×zŒõýÚÂsS ¬ÊöË[>|äŸîľÛÏÉ¿/DôvÐ ðŽè›rZ|"üNúWDiî¥ôUd—ÓÀ‹6¹»PˆÑ}»³„ËÓ×Àï«Cޏ{ôÔ#hXe@¸—´œÓAwbà ·è`êåìïîm= ?"BƒÏâUñŸ˜Ÿ÷™‚©Bðv׿/„ÆYèkÿDXHû bÁ-Q°1ê~‰–~CmwY ×hâÐl& Ó³ú–.|~Ãǘ¯v\;ãOg÷sú§»‰ ~ÎÆÏµéí®IúˆS` bZ)?g‘ð‘D÷üáËOjÕ§:úHpuVfj!ì™ôq%\añÜ#}Ê UŒ%Äa >ò¸¤O $}âµ¢c $lâ‘Ä‘>±»‡¡¾Ô 1þ‰ ü€î³$Wn&‚+ª”‹kyaÐZbh¬Ç]óÑNs!¸&®k1pEa-1pE¤¾øéÆ"H¿©×Þ1}zä \‘< ®¨i#fÅÝÃÀ7¥ˆÍÑ”ƒVjÄÀvåc¾Ú+u`àÊ-A0p¥ ™ ó ~ÿošÛÛáxšÛÓ™°†¢Yn“t Ê‹3äÖ7-On1°÷a2ÝíjG`æüÎEsñâ¤9Yý_ùLƒ?eç–ÞØYˆ˜N=òˆùm4äp~­ëÌo+ öÓü¶B¿$æ·Õ{Bƒ\1¿­rïŸdNvmrÄ%ùgZÈC79ë”4;Mßžüù5»0¤eN¨×ƒü}!¼¬›Jû‚èP¸î?¡g¾ãÌÌ‹ù\;ƒ¸#9Ãd ¶ ã~@”]„«‰Mº÷esÉ7Ûp–‰°­DO±7˜´›vfÊnFå©þ€öËÈRaøº4zŸ´_WîÛòÞk#c¡ m‘•[òƨµ3¤WØ®+ÿ¾ÝÔ\E;û:#rº{@è·Þãç‰ÂØ6r69Tb4p¿.¶›œË~½D “ù/VdÚw°ªÛ­BWP딕¨‡½3³3¹}½±™‹šNGg÷ EAUâ‘/4ãŠéÝör%‰¢îý׾؂¬ÛâDm\E|µOîUøô –ÅÀˆ•øu¸*ÁžÇðÂ3ßïƒÁÊb¨`÷!¿áÇ= ÜÀÜ83>ddŸ\ˆ40.C· ôc~.DÁϵMß79k,Z% ×]ƒE¶¯`Eïê gvȪ}p¸Í©#«do²fn-=ÀÉ@œ(º-Ãú ø¹°ˆ¼ÒädÌz÷{@_ óxË¢Ää íÀmÝæ^lÔ gå 'W·q Q¶ŸÅÜ[È,öNóŸÚi„£ÀmÚ:ÕÈA0)›häî× v³1`u.Á+#tŸ2RW„˜ô‰j<:ÃÄÄBï˜Lиk¼ è 0RØô»„°ôñ²Q0R^«¯÷ØèauöG´BÕI®™8ö,1;ßžá@¨lwÙÄ\’¾hH Ä–G©2ðΑÂZ¿c)R õ®—£W1E!q¬¾$g´&Ùìµ§3ÙöÎpåN’r»™*øš„~á{Yü‰¹ -þéÈ^Zü5û+ìý¸7ÔíÔ¢®ìØó"÷¨± k嘽c²F‰]¥·gêT¿ÛÀ.΀û óع`TOÔK–ƒƒrýBxßõ´³ìy»'âíRñf|¾aû}×ö"Æí“"¢¥‹2~¶ œ;q]úÞÃR{` *W×ç ™b`Ó‘™Áý2Få2Àö‚7J¢XÆÿ0˜ˆ4®öLèo1B†Ùd’²Y†cÄBÚ¢ÌÔDÇ'{šL6÷õöM;ó@®¿³9|'éZ£ž­kÕDô—v™òj:”Á¶¡kçLÑuøZo+¦]fñÄá6Róë ¡Ãm p¸9Î#6{“>Ø8ÜúÕ\ÍÛË1ÇTsU”mHÈiŽöE‰ŽÃ-\ñÿ8‡ÛÁPdnÍ{P®Ù9 ŽÐè.úD„A| âð3VX˜l/(Žèð3VØ*qø;¡~·pœò©X5±ë¿F;çx¸ úÃíÔñ‡Û˜_n_ç,A·*«ÿv?Ïjø¹Áýíùú¸¯ÎfgÉй4ñs!ÅB ½ÚQ`ÊŸ† EoÓf{·kðu `¡šúyáóœn„‡—ýõ×qø’VRDÑç:{_4˜Lûf‡?¨c—A´ƒ6‹ížÂB#Þ–?Kƒ5í3÷~SÏý¶ü\ÛÆð\ŸWü|P«cß1×1®5|LB×צֆ÷z2Ù7C«ø‹¾È”@þ9ÆÛŽrÒ©º¹# Õ¦vá¼/Ê^fÄ"p§«V愇WÛOϤãÏùõ§è¥Ìnplýü¬Ù¿-I{|&iOÒÙÃÐÿáå£í´û†ø „…ð<êdxÚGE+Áï¿Æ|A<Ïï¤_þÀ~}Ý~ùÜóü~ÿ>~½rÿÒë²eš¶/}Žàó|}A<ϳÃz ¿¾.¿}ÿïÍ8ÿÿÉûAÞ)}~4^q¬r%˜¬b9*¢?^Ý/[µRšAa /Ü9*¢2—îœ2ÄÂî†q¡¼Êuðbµ¸ÙÕ¶m¿ÚýæuËp[_£¡œ‹]LìƒÁËɼ®ÄøŒÉ^–<š4IeU)ü¸ˆÆ¢·þ@ÅE³ÏæÕ_‡v+(럈BSÞŒ{ßíçÖÙ·ÖÚØœºÕÖÆn¢3Ú'.Bm~²QÎïœï^ Ò~ŽÒ %å/¶³[m’8Yì"f'ÅÏTÖE¼Ý¯ŽN,%4˜ÇceNL”ß;Š[5­ï~3»nÝ´±ùµlo(Ám—Ì>o̰Ð~œrÊfÞ«¹¾‚¶\}c3ãJ{ƒí­â´×Ò4ÁÛ#Ï^Û@Ÿ*Û*uog×TØ.ÙJƒ[‡êÖ%·V1̇“¯û’ QòÕîÉBþtNàÚyÝ êÄÂpì2#¦QÇúÖêW,źÄoƒùññÁ"Ì[Sm|Ãmkyµ>ã=\B7¯Ž† “ »_×dþÑÍ~ý¢€ÿïG2z’½•ýÂØ"no ·Y^²ÝrÆB?xáª~ñ2^GäÇB„œèpB¿ ü~v ‹|Gpô¬•NÁÑáó–à`\´Cç-Å!8:ï±U;®%8Óp ž$8`] ÁA³ãB„àè=n¨6Iл–¶ ŽóÀ ŽwƒÛç-83í™Spt\pGGæ‰GÇýÒCpAÁÁB·ööv «ZŽàè%.‘7ÁÐy£}ŽÏ`´7ñŸ ŽÏÆFÙt‡Øˆ‚ã•Í\pt8;Žà0Ä<‚Ñ,!8hÐ>‚££ G¯º_ÙC¯]Ž^t0Ú‹äˆ ãÚ~ ÆsKptIpt\ rÇë`|e ,i»ä`¹à ‚ßøqDE—ý¥ˆDñë˜m~FÑæ§1 ô|B“·çr4pÖ>¦q(¼u;·Ý³1`³€U‘ñn÷ÚO›°%¥dwì8ƒú°§ñôðÛ«ãíÃkÚÏñu[¦ÞwôM‹œ}?B€c‹vª{9(cBÀÍf¢ÜÂmœ¢ëêè»èÞy5i š#8@X¹©x]órSƒõX Lš³!š¨ÍÛÓµ;0;ÚËîÁÎgûÂ.VŽ­àçÔVÏËÚáq4!àËà™ˆ©kÒ­”b<½ýŽY;WùzÅ%Þ l0ëYävŒ·Јöì%;F>©`ÖÐD`oRL|’®&3òüz[.h\ºÌEˆ£³¬àÙúÂqo § qˆVàìáÁ1`{±Ùwûò`MWãžmÌ„ý•Ñÿé«»h?ŸÒ(hŸ’ÙÃ93fo/ð® 4mØÑ¾°sµÐªR°×èö«Šâì ôŽD÷ªw@tì®­6£¾Ù6CÊÆ¸7æ¤Á¾ãõ檷çy±ó÷“G×Eóh‡"°×U#'b jâ}û„ŽD½¿b‡Kµ·ùw–`Äñ®^æõ÷AI¶ðDr.ý9¼#l¼<Ù…0.2›”ýlG ô]pwEýí?'I‡-«éîç!–ŒV'ø"âôðLÚŒ„±wp:MÔ†1)Qºƒl—Ý÷ož ¬ ¦du)p@äâ".'ÿD¢ò‘&æç}¦\é-dWŸí¤±{4«ÓzCøÛI3>޳œ(#r¶“3˜Û·“scÃFM1÷½»|~¾Î¥öå9i±\YŠƒÛÉ𯷓vüÎg;É›ÄÎvRˆØN.”ñÒvre,};iweí{;¹xÞàvÒÊž^ÛɹAŠXzÓ Â§}ØvÒÌwóÞN2z]ÛɉëhµÛI!¸œ¸0RÛI¿ñãÞNNcÒvr¢¢ž4ÅÄe£G“,\á­ö…ò ÚN.,Ïvò¡lÞg;)6âvò•Í\l,8Îvry dl'WÖ };¹’NÙÔ£+iäÛI^z¦ÝÓ„§ãì®&lÑŽr·ÚNN’¹¶“¼¥MÛIfœh;9§Ž”ÜN¾ÖÌQ›naB¡õ@è*1C˜¬åUbòÊV­«n”i ê.6»JÌ@Þ fÊÉ@¿>^Ï Æ.F{ÖÅ3v•˜~%¤®3„_»ˆ«ÄFEš¯ P7X]»J,žÆUbñv]%_ÇUbÑ7\}×Ub1¶Óî#ÇUbA]%”C¹ê kfßI÷6Œ¦ëLqÕ‹?¿t•˜¼hØ®óÏͯs•˜w§é*1ïlŽÛ‘ll~¥ŽnO²±_W>˜ñ:»JÌÙ5ÔEÊò6»Jl”›{q•X€1Bà*±xW‰ùÛÉ3´å¸ÝËÍU¼¦tÒîÇËÏgØãÖmµóB »JÌ)³¾ÎUbA9\%tå©ãuE¸¨q§xç"‰kŒÁµq±mYݲ7¾Î5ª†0› ¯Q5°‘kG=àáÚ@X™]´µkTýíýë\£ê___ºFÕûÖ.®¼n[—ml§ÓÎò ¼FÕœûë\£*#(¯Q5ЯjÂ5ªȾ kTãi\£o×5ªñu\£}]_èþ2ºFUV_ͽ}0}é2P;ï½Jø`Á"Æe¢VÈ»-À3"pUi<‹LãíA[}¡Fß´¦Ø÷³æˆÚgÜ4^GX„¯™q}Ÿ¯è¡ëu½o ]ÞëcÓÓ¹Þ”Ñ×I9õm†­½ÞkîŸn¢,54ÅoGtÌ^[6ÙØ6Íciâ%_ òЂj'Ö¥ÛZò}Q« Kg‘Ó¸íÈÊð[½`òãpp}ßè¼pø¥£S&àx ® D ƒdLú@è Ø@t¿ÀÀÍr ïtkEÑ­b²Â`š²Â84Ö—®x•ñ'®€5êŒqµ'ÝlWÀĈ+`öëKWÀØ$o÷ul bt,Éñ‰ˆá Áá6díh¸Vá#ÝÃmS׬ùp-ÆùŒÏìÝ{ÜÃmC·£½ë¦w ·ëbj ·ÇÕ×íy\Ã%x†KÄB¸>º¼5ù@Œ°·wuÙn¼5—×Û·6 ÄåDAÊ+ qã­+]r ûìÃî,©í+º³òzZÜ¡bÞ8 çÖÖ>«¹ëëe©ÂH‚÷³zö²Z½ƒwrõÞD«wÉ]_½ƒ÷Ù±»£Þ‹Õ~^Á°jG~±V¯ÝW—îÕ«{Ô¹zÍÐÏê«Wˆ˜ÎÑ^otD°³dçÑÄAÎΣb{ì<£"v¸@ìj%îËÍÎ4RE{Žkå7i»ov¶8”qØy Ì‡ØY`°³gtH—ÿDœá&)b«­]þ¤i•›v «­{î!¬ârg#Ø£.aµÐ!µOÉ.®g´{¸4 ·#ˆCÃÃâˆâþz½b b±ê‘D¬^‹ IgõvÔv×ê¥Åó¬^UÅêí±þ ŒŽr)+ôŠöÝÙ0Ms{ËÕk— ä³zi1Õê}]ª°gáj˜Ycõnl100a3`—Ûº?×úZÚèØåúrÃå¶êrÛ þ/l q¹­›±…Äå¶n<ÄÎÅ.·µÎèb·vâ—ÛÚ`ò:í äå¶fC⟸”ÂJëK—Ûè÷ ãrÛ Äå¶‚ÚWÚ¹…i"Á6.· Dp˜ÞòÈ¢bÐ.gÖ¾ÉïI/¤kD·ÚãrÛÁ¸OmQ¢âÚ*Ž…ùUûÂç¸ÜÖÌ«Ä嶆àY³Ñ<›nGK8ˆÀå¶jœ`¼]&¸ši ^ŒËmÙ nÝ>…jSçrÛ •.·½<Ú !Ã#|!¼ÜÖI a„Ëmí ÒÙn¯qR^6+Bqß¾6®c„õ~ß«kɾËmÝ´·ÃÒ=u&CmjM+Œ#Þ‹ïaòJ tëïƒ8œÏ«‡?¡l„è.lݜʭb†QoM*™½wÆÆÛbxéV³rí¯KÙ%/e3‡˜Á•Íä6+”Í:ñ¹²™];gW6CÙqF×´2ß¡[ôÈ"”ÍÚ;º²qÖ;ʆa†GÙ̩͞+›9ï›Ô>¯æ‰˜ðhß²†äEƒ/¨‹kwd…´Þ™ÓVóK·Ãëüƒ%†¶òô§ ¡Ë‹Çš¸KýDÓ#ˆ,ÓÒ"®c̉2ü4[}¹åçB€“ä犾ËGw³Þòs!¨"Ú«xØw·«„Í<¶x}“qÑ…ªŒ£¶ž=mfËzÞ>xiS|}ÒN]µ·†;}ù]qA;G>ý:¬ Ì”G”£ïCt0;¾N&æ—g窠‚ƒpÔ‚ËL@fÄYÈ! ùôuö_} PSA„U3«_ñ´ÝHZÏÛ»t“¾n(Ò6U¡¾‡*ÑØÔ^µïÇÓ¤Ìy;)§¯“®êÛ Ý¿ÿ®ðâù^<=¼¸uJZžG÷û¯>Öø9ˆFD<"Äß‘û÷ôè_ bm¶Ûdù'¯fˆªjLùËÀÂjLÏj2P• ‹-¾6khzö`£_œµª íë”®2DjW;Ó¦WÄ5P7…Lü|°p³» œª±¸^@WNP´6”èðŽP™·óŽo ò>p„¥¼*|p°ø–g¤ú36°ñýà>u ¿Ü©]íçR¬‡¾ õc.þÜ3;|³éíºr« UAßuÙÛì3´98¡¬w, ×fŽJ¡@i5¯#ÓÜeÐúh{*nó¬ïf“¥Jn…L+¨üõÃ!OWâꟴ٢ڶ·ëÂ7°¸Øê)òm*QÔƒ¡ |û´§Ï¥C^8á X'Î(@<óì¯#8ðuÕ/í½‹Û%º÷~³äè# ¼ÊZcì½^í¬¢‰:qÍ [ñŸ§¸RiÛ×+ë¸:@Õ‰;÷ô§Ç—êÄùÛ_Û<Å÷ò‰hù°ê§]¬ž:í-X5e'”ŠR·.ʦ/UZ;läuâÞØìÛ9¯óÂÖ‰k¼Ó–uâÚìq RÏþý¡’£ƒýSÙ»R0§œX ¬gÃ]éj/HrÒÓ9®[[KÄâpzõvU’N k¿¶F6¼ã+k•ËŽQ1m]I`/]åÝ(¸2 eVT1DTºëÞ®J}6 •Îu >`ÞwÞQG/O ‰=±î˜è„{‹ ,ì7Æ&Qÿ Ú‘&å–œx»®+ˆ¯Ãøñµöö:³íº–X¾Ÿâ{}¬ÿŸÐ‘ãö +è¬eØî÷<9Æ ¥YµíÓ:**iJ”DJ$EFߴɽïÁ|l^ž#ÙÃJ‚2cñ]SPŽÉ‚®&nÆOÐ},¾Å;ˆÉÈ»my*<Ÿ>ÍMS<âsâ xqf4lƒ]ˆ›Ü2ÙžÀ±{n>0,ÛToR©c²¿Ïˆ^¿²zI8ÐJ€g"æI•WPî)`æ8­ÏÊ€%øºVÍæªXõlò•”óЙ€\6¢v%ràÑ`­“\ÈÊ]ô#dË ªïŽÚ–³hýPF_gçè›ÓõE÷÷T`ªÿ°…tͽgMàÊY;">se-Å–™È‹Øv Žh²,@Ž#L¸±¹}$u´~hëï ¹k¼o¾çNò?î9»¹\‚wõر¨í/P£uqò¯{° õ­E$pM…#86¯­‘{ë‡2GVn®érï¹Ý1{* ©2±"Òk>ëvÏàåvÊÙç½IÛ¢Ý$É^÷®n{+θ>øý3™™X ôáÀ™¥§¢3ÛßsdÜ{¨p@eb „º­A–ûFL¥&=°«èûœ@Ñ]I*ž0÷>)3Ærr¼³’:}z.hëái[Ÿ1»Æí÷Œ“ Öõy$wDÜ1öÐBÿDøpÃ5ÐgØpºö] WGVn—$×pÚ9çp¸M‰¯T~·b¸Uk3†[ã†áVÂ4Üj¸5¤™F—ï´"®TÑÆÂïX»Æ-Ó® »F¤ûEÐcÅ“‘î™À쎵[¤gÄrïïÈ ßÅ×¶\µYF$8á•aÝ‘‰ÕÀ+mÕÇVµÝÛÓ‰”Ýí`{x¡bë[ñì¿N’¨ò¨áçÝn{ää‹}D²žHÞÓ†ˆû¶‡†RÐhË+ùêa óΦÖÓ…qu0pÞW‹žö¹©ðä͈ëw@ñÏ@0qXÔ¦ÜÖ‡ÒŽÅ×™–,úFÞ}wÞcóò~²¡¤CÏA”cŽŠ +3X|L&çw\œß™ž…‡îêòlLë®'n˜Åië*–çsN·Þ_¹´4só*?qþQ»ßÁÁa]xÚj|Ý×úæ`LÅA$þ}Q´îçøø:OÚÑ7&-‰¾{R“›—ûYVµE™Óº(ç_?„Fß^tÇTäwT¨«z.‘ŽÛÄ!l¼Êâ„ú?(Åä?Í*ÀþA(²ÿ©ò…ˆ˜ü=+pÆi¶GN5+ÄéœÇÚøD\Í–ª½.ÎAHcÓ³§Z¿C;î!¥~}ŽÇ=_·7LãƒG…ÓKÒá ǧ‰bušêÅD*ÏqÿzÎC½(ÄŒ«p ᫦³|k‰Ùn/'óøñAH…ƒ ~¡ê¨ïçQù¹[…ƒîŽåâ&‘h×¹I>¹Ç¬\A¤Â1ÊÕ[…Óó<ùÛž¯ç©4>Páè*œƒ€ µ ­¿øl^R€’ç­¬,äÒ%Eî*rñ’ï4)ÝC_Spè)Ú¡Âe ç,#Pðc™aûÅ–uG…c 7Ø3H½oŽ!ÆQá`*Ž Ç†3c´¿§§´U™Oí¼uΑ$±Ž kþ¨pb ¸ çc0ÜY;Rd rïA8{©Wº³7}.5HÍÆ6*èižpü2ÄÔr7iUóIOÛ:储Gór¥ gÖ¨.·u,F,ˆZO ;ÜÀ&6ð\\œ‰Aé"F×ÞYgü)šüB,æƒ1„gvÏ}\ëˆßZ"3Ås-AÓ rI{ëÙ¤_ŸWyŠí:lAîÈI÷9†pExæWôyÏ?–|KgbÉlë7~<wV_¥Öÿæ û•p3¸ãï¶Æëzg?7D+¯rW瘀­óX+¸>¦5²FX];Ô^ ¨wy ¼il‚¾eVÑß—.nc¡3ÔHb•vÅÁÀ†*ªçƒ¥Œ¬[gX<Ÿ0R5éžek §æF³ÞòÉÅmå9óCù$©‡Ñ=’LâùA¬Sr¥¥È$º#.Òº×'¢Üå3ô”õ<ÓÝ)›Ždïu(Ûë$åFJÄÆÁÜh#¨&ëIÑ×癨±;7f†ÓÓYžÃê 6ÁsšÍÌuN«;ìkvž‰TúÜäD¹"lï ÜjýBØýÝóiêô_=òÖ)PáR°ëÊ‹´/…+¾«”|ÛÇgÊ?Ã3.HÅLwFÈéblŠÔMˆ6Q^µˆíh`ÑeäB`GP6¨¶Ö)àë<ª˜Êýzt?Ø"äØË]¾ãª ~½Å p‰#eýgûÕXj'î§‹W‘}åëñsóŒ7ÎÑ Ü«|!®s üdÍúÉ6~>Ž*_ˆs²í'·j‡½»çw"ËÞSXÔÞˆÐ%y ì:Ø.ï)%d?g »'·}nº +&¸Ú:¹?­üdO²Ëc;W?nëæKÊýâh‡Å ¤lpÄ!ýˆÃêq¦o†rï!åŠ!Ü h‡ù¦˜tT®`®üË>£ã7 \êÞŽ‰¹:ýÊ¥Kìž,—+²çÐR þÝÍlPkœ Gè¿ùÇî+ÌÓ 8„л+­aßë}žÜÓˆ}Fº\›!w8e\ðKÜöJo”÷ð†@íʵÞÂ㝷H%ïþµiàŒÖÝØ_§±%úæüH}?üj„ÃNå®pSHI‡2Á û1£-rÏÅm÷­Ø$àf×D7ö-ò…à&¢ÇŒëˆ¤¹˜ææuÅm‰æõDF^e,ïûXÛ=ã‰97¬qž_Ööt¬íW aqÐ5Ñî‰mk%òGÁÈë´͘ju„ÂýÚç˜¯è ¡Ñ±hõÍ‘HbÐÞ>Å™ú•Òzd=c#®|HtŒ`‡v8Fˆ˜…æy¦VQŒh£½ n“žéÇcDß`Íú;>º9ß̇wΘ}îTrî®ü}¸vUÃÔÅpg?è7Üjj¿†Û• †ëÑÕ5\eöáPÃuDŒ®* Â'ÂÓÿD•/„‡Ä†Û•¦¤Ó)Ëcë/‚¼ì($6F¸´Üéôu¥ hÓoN¾Üñtý*Ÿ‘š™±ÕÀªmB‹è —²žáöÚª´Þ¦ˆñŽ,¡l?pcè†=GúŸð;`úøxÞ.xOxÖè—0ïøûaù÷øü†ˆD#r4Û¸œ=ý!<~?ì2Ô3ýL&§ô?¡ô?¨ 0éÈ)'ùõª¿÷©Þm!Ú¢#CØ8˜ ,¸T.Ç2¦ÿiˆn¦¡Â-mùúFú³ÍOQV–}‚Ã]ƒZìÍМ'˜tqV!Ëþˆ|>æ·Æ*ϺºÏB“C¹Ê÷IÔAÙ¤K߯ ,ÖÖYF‹fâ×2£ ÇŽ˜çÞ4[ký]v4ØédáÁ¦×ö©pFJŸçü­p8#@N…³’ÆeºæU{(W‹;‚®¡þ;}u<6ÄLW0¥ÿù \êvUu¥ö<g%»K}ÿ‰èÊSU¾Jíy# -àžSÆ–„Ùϧ¶íÃ'µ¦y‹=`u°œ#À_W‡”Úó œaF•@Ô;¿¡žtaNšäµÂ—Í+ ޱaÇ*µçAA”ºý qˆZ"CäB™VE´±ÔzÓkt q +ÿɘF¶²÷ɨÖá’ÒÄv:]f–Xêv—OîÛè2CÍÓ€ÊÝt#hâzÓŽä, ¯ÜM¡esZùB´ƒðÔ,vGz¾Â‰Ç; J ÂE4ü„˜»Éhà™×Z;~6Á©÷ŠÄ,rœ‰¤œtœñ¤2ÉýlÒ¼–íˆ}²n°û>r€ÕöÕ±¸:†3Çí«GˆÎùõHø“óë‘îgÍ€r7Ý$58x)`†WHŠî¡=wœªŠ˜ã¦Óá¥Ø +@®¯œ¯r¹Dèб—Ž„Û½pVäŒÌ›£Wy¢JÛ_î£äé’艼g$ïMt(ËLöc¯“O³èsÎeÍWx»ÿÅÚ~¥$ÑØO¹‘ªøÇ6@OcEP:éífëZ„~­{wÈpÁD3#<éJÏ®°þDœ½qN!ˆ&»UZ‘ý 4+Òb³H™q6Ë .._‡zŽ5æ)á‰c¨Å~WÚ!s¬ð,EvËMM‚¹¹SˆÒP2e“Î_Ö¸@¥:ˆÉÎzm-ÖbŸwhÿ:5Ñ7Ÿ¿ÙΫµÞó«‘Äý Êð”C/¦ÅŒÎ:]ñÐýc29¿ž-{ГþFdºô4±ú¶Î´mÅæð…qÒcvúß”9œÈñD/”Ü®ÚK÷›h}鸬¯{ÿÕ·.÷q‰”r¥ÚZÝéj}9#ò¯ãÊú¶élé}ß8cSùˆ›SIe¢u§œ¾îtUß^t§ÃÔl.ÄÍ¥Î@ô\ïz¶z qC¤BÜÜhv !~@ ñQØPóÕt qCøQÇôbYŽ‚šHëj½':·[ÈÛØšŸÜÀ9o!ž¥Ä“Ïr3“Ð…ø…ØîÜsÑŽAS©Ð\ˆÂÙP´ò…h‘ÆâÖí~øRîÑ ùÒƒHåð¥ìI*Éw,OüaS$iWyQŽqýÜCýX.ªß袑#1íºA ñƒ€Gm_p\žBó¿BˆxImëûÜ·R¹¿â lÉç†2¹ <Ù…xîq!‚ŸTжÙr Í7cn‘Zå5ùAåz1Ëû!n _Tà¯R´z—»·8BBÜÓõví;ßÍ[Ñev1=³s¥=®\·ÖÄÛïòYŸLˆç|i¸cS$Ë?g]‹Ð¯uO_"9/ùÝî tÉ€ŸWú'„_T¢Ê7Bw»a²©x¶sÜíàÉ&†1ÝWÌ—³Y Ë9@wú+¹¢„Ë9:¤»ÝAøî*H÷¹ÃÀªí8'@ßÛ4‚d¿7wò[‹9h¨»ÝA8Aò ÍÚDÍçôöÐUîc¦è(5CRP,”Œß8uñÄ]|¹Xx¹±Pš2ëR,èbáB6çi`õ1¿¬Q,9ÌK,”þº»• ¢)ÊIq‹r¹èI,Ï,êb¡¸ºb¡ÈKUb!@ Bî‹/Ú¹ßYs-ëßY»µ¬§•/D;?ÖÀ·nJ[D±Pf4H±PæI›Ù@”qÔnæs•#IÛ].c›ÄBñ̸.„gÉ„gßÌë],‚b¡´X‹«c´[,Øü·#J´g“ó{]õîp±p!(AnU\L±Pކ˜b¡œdÆIËŒC—±ýâz0 e܉z­»ž£î±ý3|õº¹ÂÄBi!EL,< [(ábÁ*¸Ž²r³¸î¦t$ÅBéÁe1éWÅöËÐË Å3ª|„¥ ß[µsw(ÓáSºÏùsü|¬{ˆw"ãÍíÏ…È|¼ Ÿ·ù ™<Ó¿Hgä7äðÐY]ªÊr72=·”ÏzdºÀ9¨ì†7‚ü±®HdüFõ*ßß½õ#%æAD•¦ ù‰8ŸíaçøBŒúB ,·ôã+ªìÒª°j¤”øÅ}ÌR™Ùw€¿>g |¬îÈbÉ‹yKoMb ÎÀwä#¼Êݬ¯‰hÖ¯÷ÀHïV¾§·MŠÔÓ¬ÒÇŸf=Ÿ¼wΫ|!®f{ެß0„¬?æ‚“Ê'BòÍfÆ\xÄ+=vÂgèY*$«&G° –á#D<'£@Vûà(Š~ûUúV0I—ƒ[¦£ Q~0Yf€Y ?f×C¶“v&Ѫ½4?¥ÕÎöЦ¿|eˆl_Ùš´Î>2²já1óùha(ÝbÇЇB…âÅ@[!z}%ÐþNk@”óõ–Ù ìI¥h4›Rë}Që{õKçMá =MPañ ÍM­~½ ‚sës pÁ[`ëìhŸf³Þ/ äØó:å™VD·<c¨óC³ º»0«Ð)_à¤ý pÓCíLpO¶ž^›ŽMX›‘|1uô=–bA<‘S^b©–Êfñ<Ó9”…T8Ëûeö +¯@ýd(¸ŒQYåYøà 8Àªâå¦B¬¨Mô¿;+iNSш±ç©­§d꽈Õõõ…r²Aèɱ'6û>|]\ƒÁΪ”¦F0xÚ‚ßø DR—­ÑB·t©lK¬´à[‹‰Ì²Ð%0ÌœL×€&Êá°ÅÖŸÅRI ‹…ûކCØ6.CäÆ#Ëõê© †~Zï n×DTh1ƒ®‡?v˜@mbaX¤€(í¬ÚZÏž(›v%´ÂyžuHï:k¿@+xÃsjwps½Tå»ZŸó¬Zë[=«2úî«¶ÒÔå=ù²¾ -⮣Aec|å< !þÄ£ïa¢)jÃ6ZÊôØþ-ÿœ¾‰®/º¿¦‚Sý-Ì~æÞžIùÑÆZ˜ë¾²ê d§1=@ú\Ãq„åØü9µ!©OëA[}]»Æû¦=Ãñ=W«ˆÊ]Z©v·Ö™¨&¾žµ£Õ7£ïŽÐؼ¶F^B–ˆ2úºSN}sº¾èŽ©htB”¤øÄöÙ{ÖmëÁËí”ÓzáþŸÛÑn’¤Qã”¶álò6yäòòÅe^ñ¶ÌÀ!Ž‚;±!\tVû»x‚ÊçN>€;?t·%Ž÷…>ö àoýÛ:ö?'ЬÔޅ̈ýï~m`yÈÉŒÑ;1‡S'«¼G9ˆu6Jbë]³‹ç㘊|æ>À©#y btU ý í±U0ܪi¸U+?†ëGV ·HÖj8~dáfÜù£<Ç• ÃÍqŽÓpS*1ܧ0 ×Án iÆÑÕ­óý'"®T^å w¬–â–iW†ÆGc~Çj|îX-ó ;VcÐXÎåÜ¡ºÓïâkžŠ±YÑBjkB«è»;&<ÎYéçc«b÷v&3ßÿs!ôì9÷¬üDI¼Ê¯n†èZåvæé%®†ÏÖ1õ—“ ±#¡^óQ”ïëðoª¿×áŸæÑSÞƒÂvu°§Y¯{<Dþö«GŸZTÐLÐùg ;ëµ!wOëM+Ø¿^ô"ú&Þî}ÞïcórÜŽoýP¦ Çý¯¿‚r¥±³%î§¶Þ“ÉùäŸΟâÙiòÁ¢d.{ Úˆ¶Úv¦Ñ£?—Ì–òýjg”«¼Æµýâ­3úI|Ýû¯¾PSឈ¢6ODѺŸããë“v³«pá*œ™¤¤ ‡ïUÿvïü}T8ckÅS…à Á-†n@ÁM†nH^>(-¤ÂCzWáð=é߮Œ=ç*œ]…ªpF©ÈGíqè‹ÏŽ²Ôøð ¹Á¹´².>¤šóò+ÝT8  ð÷QáÌ$MU8±Œ¨Ây/3l¿™¤¯rÎL1Sጭ©¢ gìP’ù0@Äß®„o†2ÁNÈøN§|žsÐäª}©pÆã§ g¸Æ‚*œØ®Ây†;kÄu—ìe΋d/ÓLjÁhˆýæ&yËEÝò*«†pÕ?iûBÔ. "Å©Q‡¬ïS÷œq#â58Œ×²?¤{¼‹~äWO„8V•/Ä?5ë|/šu¾çžQå qøÞfLC\Xá½µ0’õŸï Ÿ*ßl½7ÂNêoœsçP ðÚ½™5Ú/ý›9µÁìž%»‹ö‡üËN‡ÍÅáôŒ*p9y'éËqn5ÐOxßlˆ¤ØñíÃÛç ÄËáƒp‚¬­mñ‰8kâkÉï}åETGüç_%%©^pMüs!bœ[*€/„ß›×y/]t ³20Òà†{‰5óÞ´×ÑÛLMI¿7íq˜¯•VxoÚ#Ži¼7m×·ðÞ´»6 ïMú½)1º&­Á'"6‰WùBĽiwÉ2Þ›ž>úE'ôÉ{Ó>Ö#»7íwŽNp­é×/i³¯uPú%|ñï;øñ³,Îü.[¯óÿ K¢…®º@C”sò-©J’ãäk`s ¶ Ç®5èö…7óµ_ „ÏAàtyjãì‰Öµí¡ Ä×ý"`åMÒgœÓwJê2õ¨¼‡®pYß\!] !\é;Yε ]à£ï±ÖÏ© ]ài=(ÓCÛ×òÏé›èú¢ûk*\hUf >¨¥P¬…©Ÿ4^†è®U¨(¿ôeŒáÌ[ßvjãÈwZÚŽ°Ê=r2úÆÚŽNp6s«_å5 j—ÛÉu‘î¯gé€Õ7£ïŽÐØJØË1òsKeôu§œúæt}ÑSáÖ‡aËýÏA8»-9ÅÕþ(ƒ c Zêß0ÐeXYÉYë·7»dÔÃ?Jv»[ã¡Ô~þGy_…Û¡U+lØS·¾‡a½Ñ}ë „»l Îè>NGpÎyÚøB y CÇöÖØG07ŒÐOW»k„㨠,ׂÊùcÁå’ å)ì?ƈ²ì®EîX6¡~FX¶d|ÂIŸ÷ücIä%m‘>á$))tõo„Kñ¨òÐÁçF4….<øØÜÆÆA/îÉá2ßÏê`S2ÃùÇÁçtHŸƒˆIó*Xb @”¦¾@6<øÖîñ1Õ¡â¶ò]ŽÐ…ø…hl.õ#Ä=!>f\ELˆ©[•&r…Ì×D¯—gÏ™ˆ×2 /„z„øL:èQˆ_ …x \ˆ¿içŽußBÜÁ†¼•/Dñ黓BܺÝ/¾´£Á®åâKÌ•|i__bØé(tD”·PØíâîí !>Ü…øN÷…Xíñ!_t_=òe!>¦qâcÞR¡¬÷-ăT.Ä/…ø…0Ù2ý†B¾8¶Úw!>v\ˆàst'ƒÎ í\‡¸¾ÒºÊgº!× ¿ˆ¸7ÂöÍÚŽ‰„øZ½ý8/Ôz ñáç~ ñ1ƒïš—fŠ˜Ë¹6})ÊÑ *™ÝÍä·®s,ŸLRäBÜi¸’;wæ ¥\Cê¾ýZ÷ôi:³øÝ.~ɘCÛù ᕨò…ð»] x·›ò>ÓÝn¶`¼ÛYXaçý6Ês€¶»Â&Ÿ»]tÈïvŽ8»WU¢ÝçÄ×Üîv³ÅÞæÝnú¥˜ûkúQ‹w»ýnˆ H ÍÚ"ˆzNo¿Û½gŠþùH úo$1~Š…é;‰{ú>r±0õ^FbaâÉQˆ…],\ˆÆær>baQ,L=8”X˜ûuw[)HN±°’ö¡Êå-± „ÖG,,W·Q,<`G,\ ÅB \,¼iGrêKˆGIJñV¾!V‰c‰ëv>bÁÕo±°äµ"±°˜&ÆÙþJqº•+Ôæüª\¹Ý],L™~B,Ì%^¤eë‚™báµf¨CM,Xí~­ž%Ÿ‹›ÿvÄÂt ÅÂJ÷Uïž ‚báBÀ#æh€„c(VýµqÒ•ãÐel=ÅÂòsËç9”™X˜;ÎæÝW¯›+L,ÌRÄÄÂ\Ç:PEêºn±0WhoL,¸Û—ÄÂÜ¡ƒ¤X˜;¸,#ýªØþJÚJ.óFy‘õ„ba{+wîªAJ ±ÐEè׺‡XØÎŸpsûóBðiÞ–yýFÔ¹fo'Ù–¦{¡è9CžtËIê2²2Ý`ro©éæ‚"÷«^þá<6ª|"ÎîeÜ„oDTY+Œ^ÿlTùÄZ/ÄtG/r2úà+&;ì¶K#åÂEHr¸hõ˜ }øës¦èWùÀ8Ë3Á<–ÞšDGÄÀ½Ê«ÜÍÆšðfýzˆÉ +§Êâê­+R£Y=—>Í q:§*_ˆÓ¬9Ÿlñw˜ƒBÖD^(ŸÉ¿L’*þØ'Lœ{Â0JpW8éY4Í=æ@â’aÐ¥†šå혋èÓU:é| ç J–p ¢9®5:ÒÃt2¡‚««+Úß.yøu7÷¬¢Ï¹ÁgVºt•4Ì-ˆl°e\å9äÒ¦KÙºïö†(®7ÉpIsAcæ Ý˜ƒà’¶Cxqnzú¸^­ LÄeh„cÏÍ;m¨)]å-VzM l™Õ)ë7NÄÖ‘Þs¯eæ>Z[7Ðéîr>8´5MÌAE!Äþùé‘oΓÆäpŽãTôz•—[¨}4y8±d›‚Û³i˜ƒ°Ü'À×Å5˜ îò TÒÜ…þÆy ™*ÝA„øý×üÕZ¿QöŸJÄКbE%ÿÇô î¤,ÏhÇÌå=OµÌWÕ–~Íâ¬û×q¼ªÐ{Ýø*ÌâŽ0Î?¼Qkã qUyu ÆoÛ¡¹Gal%¡'Ô•¿Ö5óþO?š€5GâG€4% 6Ÿ^¦û°ÈDŒgJ}¢ ´>´‚‹ÚßÎkQÞq„0ð¹f8XÚ[çÓU³ñc © L˜•Єšù43î¹–·b#âNZ¢ KP´LìX¥ÏÐV¢;ˆŽ¿Óꊼ ‘B ÇnÜ.Êy°%#EÆ"ÆPÑ^ÁMÐ]kW;’XŠíÀÉÁa:ÄŒæŒT¶¨2[7 Ë6c‚°jZ·9ÄTL„) ¶ùí,ôÝx¡@Õö{”ó®ú€ùaŽq¬õΜ1…‘³,õ&JËÈ&¿ÿ|,3ä1R' zkXyäYV¥L|P vKC¡@Ö~÷©0À¥Ï@‡xy·á.ÎŒM”@NÅ(W9ù’opÏ¥Þ'¿>,#Vá¡ßúָȱl>}]]ƒÁΪŒìfäæøa1.‘ó¢2þIÏR¯Hªk`y&ÎÀ¤ñAËßjŽZˆÿšýï%~÷€ôç”Ó‹Ä@Ët20Y“¨³¶2µ²™¸×2Lvƈ=à°ô•aÆŒz¸¶Ø` é+îW igò½‚6Ë)=âÁ@Ô7;Ç^9û–HØ(‹\oãYA=` Ra\ãá*Mïï-ñÐâÇYŒ˜ˆe˜çµBæ2t1ó0š7à»øÃèé`,¤r"Lµfàö‰ÈÎÆmÝSi ûŠvc`ˆ&ﱸß@Ìq±@ÞðÀ [LhºfƘ¥†òÎZD­ ÐN!53é*g-éF%ÏÁDz“Jü¸’”…”OÏÙô½õ@ 㕉LÒd¶¾5­‰AD©ÜÆmíÆ·Ø÷ÁRmRÍÞØ$¤ £;ÖV-vµ%“Ë õ±æHê®]oéL ߇Ø"‡\Î1š” Ý5pp?²6³ŸìÜœ*ÕmFûõbÏ•N^‡=+‘y”ó``'/70µ@e›ZoÜ1“µsç¹xÕ¯ïãÔë05ˆ=%Û‡ÂS9ñÅküg-ýÇJ6¯Jþ×aêÿ½EŽ/”¶ÿõj°Œþ¯nK²~w« ¼‹n•Ñ>[á?ÞݪTjÙ°ã4]©¸â©&Ç;›o\2ºÃ_ìúG‡êèUER¨Ïq!°Ûø¦¿ýBœ*ïŽáÎÙ ÿc w΃h•ßaŠß7‚{gØ5¯!ª“Ù-È«ÉÇñF5”iP”õØtO Ü3Àçï=ù‘åV’`±'=û®¯à †èSl¢ |³õno ô"Ý:3Ø:Hef:‚"çãyМN ]Ÿ·]½›D”gFÑY2Èbפ¶ýÐVbì:°²œ63¤j› \ã 4C£V³/Zw»QvðXcïó-xZÕßuì›7µŠ-ª¶Ð:$™ù¨ãÙ˜rÍ—%Nä°ùpWô‚ª9Æx¹y‚IØJ7'0Ól§lÃ×'&ªøÚÛvE}/3Ü9Ôä‰eb·uÊJ;V } ÖçÃ&rÌK@Q„S𥄩ÀÈ"]q™Íà/0ñL–/ØÌP»,[½ÏN,;§ <Ñòµ‘¶ƒ›±h]½ÃÅ'Û"rs|BØ]zaí-xÃl»kɦ³ñT ÀÁñeè ¡Ú„–>üïÐöy¸ÓÀåLfhµëX)böäÊîP ™ÌÉF}Z›À¡Æ je;ÂÂh4—ÎÅžWvï~$ì‰__$g5Õuóí¥!ì¾" ;2!tv×^³ÃqDg@¯ÝÌüZwÚÆ×«»}¢oTOœá(s=Ö;ʕæÛk+óÆ™9ªƒýëÆ)óé[€±ŒÁ±EmŽwV å´!v „|”·Ýd{£í0HMÛa,#Ú?–Ù/¬¼Ä¬Û‡\;d;ĥШ`å-޶Ã!å´l‡Ö]Ù¾Ì „áS"§¢µ«|º¢Äl‡XµRƒÁvbÑf¶Ã./ Ù±xåìZW¯Ápg1Þ}Øá¶CCt"Ìvh`!IÍvÖ¢ñáZlá3¡–3 ‘¤ˆöyéD9½td;4p¬Ÿc;ò‘íÐÀ"n+ûB˜íÐÀJÐl‡ÊÊBÛ¡!&õBf;´¾eê}Ìvhàä…Ÿ¶C›LÍdT†¸ì8FªÆåd¶C'M…´ޤµMÛ¡…;Ç(` R!Û¡5·gØñ±uÙ‡‚Évh}«‡ Ø`Úí@àƒrÔtÛ!(·/Û¡!RÛáH|“)Û¡y_¶CG„íÐ2ç‘ò‚,Û¡OTØ}fd;ŒÎÒ6h`/—í3S®räîtÛ¡Ò¸ÑvˆE<Âvh”“Êl‡è­b€kвbP4ÑvˆÏq^ HÉdv²¢ï,õMÚɳÜvˆ5OcáĪ­n›ÜX¤• Ôm‡†¨D˜õÏÀ"yOtÛa h;4°IS«ÚÚÞäæ˜é‰Ëµ_ýâ†wØ3{—3Tl‡  ´‚¹HËܸc:›Ë¬çâUÿî0åŽX¡jm}jšk0ÎÚ[kÔdçˆJñ[kÔ²ò¸.ðÿ?ðˆB>3"èweŽö4~dæ5ƒœiñÂ£å« RŒÏ®OB±'[V‚úoDTyuŒŽX;þƒþ¡­ðpÜЧYSà!uÂ4Ý%@¤Úž…ùÓ£yk÷ ²dâñ{c€2Á Y)O9rŸOèÈàv Ò¶d힪ßé?’Õ:œ˜ùi²v‘™Ä¶)¬‹!ÜZ®rsøð4¡33q˜u9['ž.­Ö„S ÜZ€Ç?'Ê;SWN$jE¹«'^˜ÐYh;íè*5DÙ9.°1áA ‘,jW-ªÂÖA™Éœ‚øz"bÓ³ éa'Í6]vCEÖ=/_šWDšhEÛgNæTiJ?c__œˆ©Îäüó±ÌèˆE3™¡]—†">¸v~Éuçàsæ Ž'ÔÓ˜ ®ngÈ©(ó*ç-9j+O0{/74 §WzÜ õ­ÿœ-Ðùúãc0tÄêZJ“ád÷ùß@Tu)™/í'è’y©4‘Lyâš"hiB ô¿WúRÌ|ØÜ‰ÖUN›>ÀLW&5–éÔ‚tªìÿÎÅuƒ-kJ­<áÇÛ¨’ÆFÚåŠTެ6×FG«LcžÑ4Ë9ïÆDä‹ Ô*•©ö]N{5@R¶xcü{¿‡¿ÀA0éïËÿžJ°¸ß@´rX`ÍZªÈŽ{&ªð©Í™<7:-\&ô$È™Yý*g$4Ç5ÛÏÇH*'%–Q n¾÷Voý [_áY¥T³òµv„–Afëä¶í_î~§RnÒ›ÒÞƒö[ëf\¤jÿ’oSϱæä„&l·5‹E 2ÜUÓ7bÓ¬ˆã¨6ÆNE–Å̈çzíW²_…×;ì¹ÊŠäåM…P~ {˜µ#’·>¸¦U;q?]¼êßj¦²˜G^<à¢ê<óÕš²§©ÿx–â¨Ôññh¦j—ék0îòd„e!¦NÛÊ8ÿ ;à7¢L†D´DÌý…¨t•7«ÅL7âüCûBøWþi|·L%%!U3Ý„@ÞÞÁ›²¥é|V‹Ì7º¡gúÕÈ¡ãôqÀÄÇ(x|µ ü¢Ðz²þc&#ç£o*ÏÌIŒ¾d"\W¼œJ²¨½˜Sø´¾˜H×¾>Q Z6sE <}wÓ›{íŠÑz-Êöì_wÊ©oN×ݽ¦¢™àúƒáìˆÈFm .!kp‘MŒJ>yýdòËȉ\‘Fú€>G˜{åþ‰ÚE™Õú¡­¾ÎÓoô­@Qy¦br79‹½\ÊkóáÙÕº¸´¯G¢oÏT8‚cóÚ¹·~(£¯;åÔ7§ë‹îÿݬeáÖqX‹ì¡ËýÛ¬—xËõ…ÉI‰Cþãàö‚Ëן¿L ‡#š?N¾ªMa†cü?à@E!çè%ü¼Y¬ðK3O¦xè1°ëïTb d Ê‹—/€xfWu£éav]åé¥@ËŠÒ̃j÷d­Á Äë°ŠhÉ7ˆ2˜>¢G:ÖOcþ>U¾xöF„Ðr¥gúû!|çës9zŽÓZI¿¤ÄÕ¤9È•ýÖ«œô p¨± 7Œ‘oÐ0Y5;ÛÁ©¿_³ ®]”’–èÿß<.5r»ÈŠ'—½4Ÿ^ìc‹ð‰ðD€+]Ù&WˆçÚhÊ–å[`·Γ"ܡ̈â?­|)µ–¹žœ2‘ŽÀíõ7 ýŒËPg'¹B?×Nèkë³/Á0Ùõ´©0×*SäØYåMYJátd„dï»çC§ ¢¬‰‘r’3Ψ´]ZoZ¹H5‰šZ›Y¾˜*æ…=–âP B•O­{s&¸Åúº)[áÌtÖU6†ú±Ì ¤ ¢Xf¸2•Î8Ûþ힣µ"¡³Ìmy ÆT8+ê }+éN ÐþîéÓTNMOÔö$ã轈Õôõ b.}ÝÌbE/zkâÙÿc0ØYv‚}Æp~Q…0ÉfGzgµOk V‹»U×Mh—o¾ÈøÑºlgì~•+â\Å5óâÆmˆ"Þk«Cz,¦ù¹²/DÙ(ÏMÖYpÆ6„Ä7óNu΄÷#½–“ãv¨ïž³‘T'#`%©Š–SZ=ÑÅä`ÚÉ´j½ï‘RÆöU€ËIåøáXmO(`+¿Êên5¾½pØ¡'dÓ‚‘mNr䎎'‚«Ókè4¢uÛ(ü»¾Nåsô͹‚ú~¸†çZP¹FN6”)r% Êdº2ÉûÇdòލÀ Οƒ¨x*d`G·£¥EÚÖêFô_Ô« åžg¡s*<7˜Xì~K+EÁSíº”É[·þ—óõX7ì[ ǧâB`9Ï8GÙ-Î[çÌX]Ī;Y¬ÀÓÔ÷ày>6•ûÈUÛ)­;åôõ‹Ð¸®¿èΩP.GòiNúaDíä ß»øÚtÝFäÉ`¹§þÉëçþFTþâkùÇ\|P–¶®Ä,P;@‘².b ‰§ Ö YŠòÇy;ý·)¹Ò’2À3vj&"Õó|Óÿî ?xΛvTDl<0¶"®}Ñìb„çÇ­ÔQ¬vvW›Ñ w_›q±T'Ý{»û€@’¶~•·H{ež?ÍO3ÊgdOQ٤øo,A* † ¬j±:6&CÔ)®Ò𤃃Š4Oî³8¿~Ó¾?3€0½79ÐÁâzä.ÏlP¡Æ(¥jç°Kk£/½3ЦoÁH<]5^£*ïœk¼F#‚”K0œýøðì¼^®¨J:˜Žs«Ÿl}Äž0M{L8Ì“óÿßûÂb½ß@”Lu+ÄJ¹ÿñW)åFÙ³ô¦hbÃ+åw¥øGÑ?øÂ¡). ÒmÚ ÆF‚<·JÛ/„ÿ£§»öF$øW²JÞ/DWÞaz¸ qþ¡Ž}!ü+t«Kj­¾+p*xTºs¸J3]Ó«"A#_ŠŒ`Ž“ù±§øw" ~@mEÛåj=Q­\õ(PÐÐ7æ™~¢ïõ¨ ]å#¹¡¶ržÖg¥ÝtêïŠpÖûFß}sj#ÎÖi2Ø™1.Ê©oN×ݽ¦ŒŠ/ú >¨(càR 2ø–Ø“ƯD-‡BB¶|1œÉZðþÃkƒE뇶3VWæëô-!¯ô™ŠE ?Ö;ÊkëÕS–ȸÁÖ=M›¾^,S}s0úîÍkkä5òˆ2žsD”kPmÞSÑDõß<ö´Õ².¶Q-©V¾¸„#?´Üˆ„œâÆ|µ7ÞÓ›Ûžþ“3ÿs*-!>ÿ;¹Ðš¥ .¼&(í\Þ„xøªyìf‚fe³7VI t¦S}ã»æ¶£¿›«û„ºƒÆµ¶O¹ù'Öøº=âm+Š2Õ›QÎ\A‹•—\ š}4ÀD÷€@¬áGÒç¬Öÿ ±+ž6¾Eî7n ìÊi¡7+˜Æqø«Ô§ Ø É%xV´K“‘«úõÔïò¾^à˜j9Gm:†×o?˜,u†³³‡×ÖÙ…»»%—ë"Ï8bm+…Wçx#ž#2»´E¤!Q¢g$Ä1˜éGýœmÒøŠÅRTÀ­iAшœ)ÀçïfÜwù.^ÞìX”UrTD”âa0ödoÐÆÀ6Õ7é"$ 7¸§¹Ãî‚yiX¼‰¬“Ù»5´‚ž½hI"°;ì@£à9¸ƒûÞý”§G^ª|ÛÛg+¿Ýq´4KÝ}9ö|%“Ðv»tp'&=„Q±ÚEÛÁî± ¸·èK,ÚlÜQl^fе…ç²ÄPg=kÏŽs˜W®l{:Þµ³§ScÛ0/œu…$ëË IÌqs5í1¤!øDYÅùq|6½.›†ÃǦpvδŒöuûp9œÑ|þn¬?Ÿò„§ø¬½±j‹Yn"ÖmMlZ8N˜Äj8ú÷`lgY ~§o±ñDa@VËy@Þ[“¥èÎýžn'Y¡v $΄Z΃~Fh9R¾lû/ò‰Xlnض¾+Â0PÍŸ­{~)6gïNÌZÙÂ^µ<Û Ž´ðé7°.QzcËBÎe¯Ï¬|“oÁ¦a)šVžÝ[>¤¿¼(¶¼»úÇsoBÎÕöõLª¿6ý­gÂëB žYœvîÞâXûIu#ZŸKëYù“Á’‰<³ŸWˆ‘±E%6ùr5‚T› ”åÆÓ·X([’ƒx!0𸗭?m VyÀ¯­5©(;ˆEm»U€WªX YCÓaá3.Êç¿d°˜9uvb™,Äòp3³.2©8{ž’çðc Õ„›è‚qlçæˆÂpƒlýB,4·Šà3$[`pÛ¥óïÍeUÃ2Ú[å;¢ .nÒ)žµ6ó½í—¯›JRiW Î@}'ÇÐT!ø¦ÂYD~ƒ|wî¨ØEä˜øû„ü®äæ63]½%ì×õLŸãfÏöèõŒ945gÏT¶sƒÊË ˜‹Ÿt ÖôÔ±¤bÅß¼ÊØ³ùÛ/¬æ;t°N?ìË´OõŸ~xŠ*ß@,­F“zØ,œV5Š p´2ç—ý}/§Ñü1Ïè}ˆ‚'ý¢Ñ´ 7O¹élW@s:-ëæEZVÐi$øœH˜(€ÁÕµ¹¶£uî«çïþõg°è¹BôݹFŒMå>ò=GPf Òƒr ± ‚®hüò=™˜_SÖÕΟâáìð¸—ø}”ùïúê†yÂúgõjå6æâ^nñkù[z9å ¡ ¢¶½J¬wëö¤Ÿ¯Çºaß.SãÛXÎ^ïO뜋_7räŸèyZôÝy^ŒMå>rÕvÊDëN9}Ý骾½énS±ÌD+F÷Þew­{¶ÎÝ Ã±%zðc!TïË<ô…çÌcY/œM>ÿ;àâÜ߈†ærWÿù±æ,yRÄ. öϲx“5ˆa]ub­Š·Q^Ïqþá~«ú2×|ÙCV‰¯g›,S³7±øô·þN)óû“vvðZöS‡ƒa7ê@øµï4û…˜ÈCˆg%Y·ûÙ]–ÃÄî[¦žZ±;—¹Ü¤Ø»–¦­ko#‘Í9"X𛏖{Õ•Yä-MIÉFeyA|u?+èñ¼ò ÜÇjo-¸çjiyC–ØXÓüæåg±dó¿³„ÜÆt¯½|Ïš\|Þˆ9,¼XÀ–²LEWB*‚v}ëÿìB#e=Œd„Y;ŒÄˆ¹Î±Ùtœ¯`±7?Cw.yëÏp—…~Tym¸zÓŒ¤¢2å¬)~í™Ö~I.7¶¢‹Q˜VŒzMˆç;–¾&ŸK•­‹qd:Æ>òâ&H‹þþÜ2ÌýwéÄÀkaÿüÂðlÕXè$ô{݃³L<ØuŒH°¹¯@<ã3Ó°K-;)jÁù‡‘¦ÌQ}õz3…µûf)¹öT~ÞÎߦu#ÌíL—›RØä{ˆ[ÒŒIûF¼‡p_©ÐÑš÷Š?á•rbà÷oÄöTa@ö§ä åKLRƒ4=Ê "™ÅÞõõfI„Rú—ßZq Øf;åÛ®.E›ÉKáR¶íõªîİ Cà³I˜¨ Du"ôÞ? bj¢/„4^æ=î7ÇÛ´>Z³ÏÚ|pFÛ[÷žÑŒÅ•PàØ’~­]åå_~p­`óó!É]þu©°Î„ã%ÑÇüÿƒîõ¿ü…ÐÇé'½~þùëÏó÷ÿë¯ÿéþýþçÿžþëû+ýÓßþïÿúÏøÿõùÿ÷­7"`Åú³ã5d}Âú›-ÿÿí¯ÿãéñùëÿ†ÕÖendstream endobj 35 0 obj << /Filter /FlateDecode /Length 2090 >> stream xÚX_Ü6ßOáœXk,ùÞÚM6IKpÀw‡Ë¡ðÚš±[åÊr¶ùöGŠÒŒgâ4@1¢)‰¢(òGrâàÄÁÛ»ŸžîöyT¬ÊE<‚´ˆY.ª ¯2–W(}’-}¶‹îÇ£;£\ë–§h^H=è ExÉ’’û5³©µ‰–‰mÚÝnåœÅY™áÞH¤K’,ˆÁ*A">Ž<+³Z,r–¦å–2ëE ˜Å¯±—o¥FÔ"ì ši.S[k˜¨GG¼ô¦£ùzˆ5JÙúuýˆf«M¿ã`å{/•ƦQ¡ £¥\àû3Q8?¬§i@ã'1jAD+'9¶«—Þ¬†Ïø)õ.³ïÌGä(M£Ú‰,|ÙåYxïºÑÉ­(£ëþØPùeÇ­[®œ¢Oq,ôlœˆQZ¡r6‘½Cì´'åµd=K¿¶T xW­›Žhëq0šNñÕÕpRK7«•"Ó]››­VW¥C´ŒI«_ec5­¬ƒ_«øÒÛ÷gÖÒ,ÚE â¢9||Æ»ÖC_Q§ç~„Gõq£.,ü%zé"ë –±õÁ˜­°”%^›”%¹q O’bòú4 rËiñ.Ëìö'«vÂÃFK¯|Y½`tEÎ:öéExÐêD|#á0ððÙíÕ4¶ä=ã ê–,¼ìÞy>/¥ã”Ùô ˆxÙD$áIjôÁD¤IîÅ‘?O²éñú8Óös³ÌsoãÆÎöç–ÄwòÛR{0rñ`˘ÔìN.}³ µveÓêÚg]Ä êØ7t8Äf9å̈÷ŽLaéc.Ã{šíGÔÞX%‚“+áºÒ ç/€©'šªFjšt«8Ä⼸½ÂÚ×.·`íÚ®kQžs”†ˆ0ü4õà9ö³“à¶œˆg¿`ßéD¸–T><€ªq·wŸ*4ŠÆgí¼¡‚›{æAÁ‹IV"CGþ¤µÞR1“‘R”•…]=ëYÊ‘XZNJ™ˆK‡ÂØõnǤ@Fܧ3wu¯ |èϺ ¦¥Zfpȯ=õ MÓ¡S'i‰Øˆƒ‹ÇCiHXdFbù÷Ä:ÊQjŠ'ü¤‡§¤k\I-Âç¯ÂSÆÐÎú9ä‹Ã—N Ž„Ä…ÂŽ‹¶ñψK¸Pñ‹úÈ=gµÊ¥€ŠR €ýHä'!’wè:÷î0‚Ù¡ýfRâÙ ¼ ÔmDaì¡VÓ6™„ø`ÓOqö›\´Þ €Yò†Â9ŒdV¢-¨ÁXÓ–¡ÖµvB?ÅY ëé@s'…| (W¾Ìž/7¬Z7fñÈ«3-ü­.ëÔ±{B¶°p(xÒôJÔb1Š0¥aî(‚fút1Ÿ[ø$0Áü2šFÈr+  ë„0Ü"IâcáøÒõ˜ZQè¼uÞåýŸ"ñku_¤Æ›AÙˆd£,Ï­däѵXf©ÿŽ5ÆL :ur35´—ò”T`‘Q“£h|Vƨӽ›í.È äd›­Òâb+ʯƒ«Öàƒ‚Ü%ïÁ§`¬²,ñìÞoP r¯®êM›žWØ•#$êHĬH]• nŸßî¹Âe³ šþí߯ßþòðñÃãû·¿¼ûø7{¨´ÜoãpÊŠ¬ð;1$y•’ux•á ÔH© ù?¢ "o¢ž–C™Z{Ø%ÁkûMµélDgÞil­åhl‚\B… ß¼%ʾ.ĶHe#WM‘QVÇ´ÛåFÌÜNŽ­P áŠS.~®_÷_˜P{Ì ÷x™ÂÇê­©³˜U|UÙ£i{à?6 \rV^j|ç®V<Ðâ͗À(Á⦆r€¸Î›œBÖÉV‹‹ð¤fãì =I!nªžÆÛ]ané³u§œ3·[Ðûù5¿ÖÚÍbêçÁyx¿®>k³’¨*VTënm…íþGÐp•¹_Ìþ4|0ª‡6â‚•Yö×#èLJwo¾@)4—I±jâÜ£Š|•cñÃ¥ µ -‘rL⃤*>°±óÕ‹•ÛÈûÁô ”²œö |^þ¾@%`=Y¶žáÙªfµ\ º<%„îˆÌu±mñmŒ¾žpì—NŽDÕâpš‡ïm3{OxŠ$Òú±¶¼‚ê¥ùù¥}ðiú\°ºñ›Ð²‡Œ4z”ò¦?Zl\‚wÅ×â­5’˜2½Mz> endobj 37 0 obj << /Filter /FlateDecode /Length 2754 >> stream xÚ­[[“›8~ï_Au̓]˺KdŸ2™Ü¦f3™¬vk2ÕEcb{׆^ “tÕþø=Bc7syèB`éãè;WI4ö6öÞÝü¼ºY¾•Üó‘/©ôV_=Â8RRxÒHúÄ[­½?g„ÎÿZýzƒÝ¨òúfuóßMì‘ã@%LxááæÏ¿°·†õ0b¾ö¾]ãiª ½÷þqóLjòHE‘Rª {ùÚÁµéGÇ@TRHŽ4î€PÈWÁ²©= ˜¶ljD#"0¬`ó§÷¿ÿýͲ`ô„ÁJòž¯m\H¤Ù ¬Áó œ\… 4 1(™¶!PÄ0©¬ =á#¬ã#JKöþùË»»×¿|ûáÝ]‘Ãi(‰äi9ŠÈf„kˆT )âÃ,(’œµ#p0/Þ!°…Ðbœ.ÄÜ[D…ÓE°ß¥Q›†ÓW)¬È§€F„kàstY„+8#€­GÑO1F>1³aˆê«éL^I?ƒIGÑߌp‘½Ëó! pxÂbÄMýÏgM‰@B¬™D Ó!þb ˜°>§0J öœI½‹×Ñ6… §»T…«cÖŒÐÃ_¨FŠ â¿r€ð9™Äa¨BŒ«ÒaÒ6ö‡sW²O@=Šýf„+د̟b¨ÃÆ™?@øŠLbþÄGL9úïwqýÃÉ+éÇP/Qô7#\C?„ ®¡V!iýA•±"†0G?)$ ÄñÑø[ÈN]E>A˜#¿¡O͉ÂŒLRsb¡HÕkÎW¯ß¿é,9‡³àx>h_áñB’Sø²«^ì*9…¯–dŠ’SÀR”Ku]Í3‚¾RZ ‚G) áú ¶ÜU0v¥P¡ÁŽýIR¨Ð qßñÿ&ÿŽÂ"r”Jšzx…¢]Ua§W@t"b¯P á4’EY¶KâV¯N`¥0'œ úxÅ(„Â)$D=SHÈ5úXÞ,Šõ ÖY›“XªAÀœŠ1jhF裆Q…„B…&!ÔîG-8gèÐÃpK=p¨¥‡f„>zà~WÁÙ™$‚òIÁ„I§› @jNb©†¤Ç©t•Šãº+ü Dû&Óµu¿`>’ê„D“eÉ„ô#BÚše‡SQ’Ia¹L!”¥{3•ÅQ¹3†Ø$u;#Há:•hóв1ùŠ>‚G_#Bú(øõ4üQ‰õôçá ”P¿Å!Q]EVçê Ú«÷«I„0«ä3Û q8‰Ð½k/«ýürDyk ˆV}ŽbñÉÁ°ð4Læc² „Ì}±3KèÛÝfNÄ ÍDªG†Óâ@¹6N L)€ºû({Êòè0_PgÉW{ ì¥þÓc¶‹7P× ‘!eá“m­³·‰/» ÆÓëbàëU3dA©£Þ‚A…êªÊ1#ýY¾Ýe¶™ ÿûè…}r†Q%h Ñ÷a_IQ_%j­“…»¸nå{òmdácšFqnoÜòÛ½ù»ëòc¯ëãž}MÌû¨˜}wLà%ÂWõ¢ÎÆœrÃ9x<¾PÌŸs¦%”-UwCU³MGiâÃmžØ«›”½ ö{Ûƒ<Ø'{s$ÁŒÛ¹ë<'³´hæþÍðìö ˧“¢Ngp¿*öl‚AÁ"jó4»YÇc¡ói‚¯IJšíøœõ¡ qVˆ«¬ÁÄŸÕïç2ùf'¢N=£ÔqfZaçÁ.Î̱¦coƒlk[Æåí÷SeàfÀ!ʃ5¨ÆìÞõÜ^-Å_°ÀM$SŒ„òO¯ž:Ÿ”~G–V¿s^Qsyx#q+v^ì³Ä¶ÖÑC¯Ý ÄÁìòNµapJ9JmÝS<÷Ãõ÷í.ÜÚf£ÖHnì^‡»Èõ3ü—š‡™f/Ü‚œìZNÊ ,Ãæ9;ÀÀIPVˆsUÎÖJåù(~FÎ1 ¾ÝÅàôOs)Š8!yZ™ ‘ë(µ&VžvJ£}d‘}Zä+xxœ<´µ­m¯Êae¦€!QéÆ VŸzÙí„Gc“ðÃ,Èþ3'`šk{kb¹n¢Ü6Ê~qâ<샰ìmLœaåô  ܚtfÚ6ÈçõžºÖ³rV¸qüqqÝǬ  œwl]Xs> \?9Ç CˆDΓқμo—gg¹ÉÞ¦Qö¸Ï3äÔ‚Œ‰C I­0«¹'5ºÂF÷EŠ(죰úkĘjZ¤'{oEM‹Ý>ûdý˜:£±e <ªËbž9žg`J¡ÍOÒ¥WIJKÃ&¹ÄB Œäü„¼*³ŽbÃù·]šÄ[ÁÐÆŽÇÊo»,·ÒÁ GÔ•Y[[¸N_“´%ä]¬žêÕ¡€Â–z óÅ v1ìüÝMÕ¡ù2¦ªVeÑ2?§õì¤l|÷é³»ßlÒBôÍòtîzŸÄ s6)ÎèþÒW¿ý|ñsG9Fy”h¨4y{™Ë Ý´X ÅٸٿaÏ?˜8)Ó |±Ò¿ââG—fÅ! ƒkXúAÆíÍF;óMtÃ’Fñ«—f¥î&@ºRÒ#c%ŠT¬Ý oÔÃÜT è±Ä(|eS8‰ÄøY¾:ŽVö &ç¤ï‹RãU™³NÞà x3¯­d 'k%®Ù©0E³)´Ü©¯–GK:©§ç˜#0ʦà´7RONÇK:©Ás„Ùb1s–°ãÖ°M¾|î&n¹ëŒÿ“u§»bãÁU„FBW5*TF—+Ç3Åömµzkjç¿9`¿6HÒ"#¸A‹…õîω©ë~^ÜÜGE‚6Í09<€¬ë¡>KLÕ/'±¯¾H}ík´¤ƒ‘úú¬Òˆú“pÚ©/§£%ŠÔâ³P×H=Àg?ù¶Ée9H¡®pYuâ²èöÅ`ŸR0q:þ{"õÖÿXI‡"5lýK,¥Í?§þÛå69DËC’åQ²DÅzwiwߪ/š.|V3_Ù1ÚR#Äd&&Qc_¤¾j-é`¤¾¡Ñx£ž„Ó¾H}9-éP¤–Ðëu¥z„Æ7?ò(ƒ½­Џö귟ߎÑ+ÍçjPÌöˆ•·«ô1ºmªhC\=«hVÅ^…i•W³§d®¯Œ[»ú¦Ø„ê¶\"N&1±¾H}Ml´¤ƒ‘úº-ÓˆóI8í‹Ô—ÓÑ’Eº¼~7WÍœÛFñºÓ©ªÅú5¹«uŸ‹0pׇBíû\¢ã[£®}®k :÷¹FÈqTiO6ηOϯå?b× ¯’¾0ÇmÄ/Ï=¡˜(dw2WÕní!ˆ³0Ý=¸=ÎÚ&õé~é!XGåÎií8óxhù¯£ôìÔ÷õëÅÏÿšBf‹¯)7tqy˜Fq½l0Fs²”, ã¶Uyþðr¹ Ó(Èwß"Xt’8CIºY:œlyÿ!^‘Yš+Åë%¼ly²c 6ú1¤wendstream endobj 38 0 obj << /Filter /FlateDecode /Length1 1381 /Length2 6029 /Length3 0 /Length 6979 >> stream xÚx4\íÚ¶ ZÔhчèu†èÑ{ôNDc0ŒÌèD¯Ñ{ !: ¢÷ ¢G¢'J‚ñMòæ=ç¼çÿ×ú¾5kíÙÏ}_w{žëÚ3ks°ê (Ø!m¡ªHZ$”(išƒ€ PD&âà0‚¡áпíD&Pw ‰ú„’;ŒÆØ”Áh P‰<ð€@"˜H\ ’‘îRe°'Ì -x€D@QDJHWw˜ƒ#Sçï[7„’”çÿPpºÃ `@Œv„º`*BÀp€!ƒ¢}þ‘‚û¾#í*%$äåå%vA "Ýdyø^0´#ÀŠ‚º{Bí¿Fè€] F$â9ÂP9 ‘öh/°;€1Àa(… ñ@ØAݘêC -€®+ñXë/?àÏæ@‚ ¥ûý+ ñ; ]\ÁÂ`ƒCºªZ‚ho4?Œ°ûÃQHL<Ø ƒƒm1€ß­ƒª ú0fÂ?ó¡ î0W4JƒÿšQèWÌ6« ì”..PEô«?e˜;‚Ùw¡?‡ëŒ@z!üþ^ÙÃvö¿Æ°óp2FÀÜ< Ê0Ñ¿mP4@()&& @ÝPoˆ£Ð¯F>®ÐßÎßfÌ ~®HW€=f hÌŠù"òC=¡´»4Àï?ÿ\@; °…:ÀDÿÎŽ1CíÿZcÎßæ °bè}þug‰a˜÷ù7ü÷ ©©*˜¨ñýù_NEE¤7ÀO@X )€@ 1€¸¸( àŸyôÀ°?}üG¬Â ü«]Ì>ýݲçpÿàŸ¹tæBÜÿ&ú# (‚¹€þÏtÿòÿcù¯,ÿ+Ñÿ»#U8ü·Ÿû/Àÿã»Àà>æz 1*ÐFb´€øo¨)ô/éjCí`.ÿíÕ@ƒ1jP@8`-º'¼÷—†R…yCíô`hˆã_¬ùËnüKopª‡DÁ~=a0Q@àù0"ƒ8cž"( 5»  ý³® ‚´û%6aQ1ØÝìC„9kÌJà¨Òêý›Ì!A `f Ø#݉~,H d‹Ù# Á1v¢ä†x¸»c„ö›˜Â¯« õ†Bˆægé0§Waíç5 ^›#x+«Ñ‰æ}Q¢hÎÙg~ŽZøÙj“nŠ6v/î gèÍ•GLÌø3ð~9õ~Ô¼œ®žÆRé[W<(ü~Üíe¶CÒ;Œ‰gD¯S$é3‘ÙXàZp¥˜Î\†‹÷ˆl¿Ü*ºêDm?”ܸJNÉYÓÐq y»ØOÌYÙWÑCæÈão»[dzi]a?ÅŸ)¶ÇÒ}÷Y·ˆÏZZz›Ûß—!rT¨Ù[-ö"‚’ŽÊ÷kÞpòuRîƒ&§¢è©RyZ"]±Kç2Žøò©Âþ¶¤¥à[ºß5zÔ!Egdòz–­7rŒ¾ ‘ÜiNŽvä¯É`W䨶Ã:Ê<¨ç÷âÒ0ðê:¯µ§¥egæZØ ±øCE¬¶ÆïœÛÄe'„-ÓdàŸ+ŠéÁ™]‡íM.ï§(é9(õ4ptXV=†ïò ~{Þ«4cIAœ|j~Û>ÔyˆdÿÂD=œhÖ‘½ûf'©ICôô=… ¯ŠºVsÙeÍ“—0hŸ‡«×Ö©&ýP^rnœ-ÁD„¬ÀˆbÖHk+S‡Ð\*\!hŠœ”ÒùK9ÓË…*±wÏdBšeÒ$‚€Ço(ëï%×®ßÒïù~Ó*ÑÖýPH˜ÀJ3¿ó¡£M©×ô½DXãnâå'EóÉàCñ™å|ÅŸÆÖ”eåÛÇýˆÿ¶}Òpo¦PõÚ5¸nýüSÇÃþxÆÌ×ã{½\iÛÞê §¸‡”¶CjRlaÅðÊÆÑV¥¥~êhc‹~°VûI3{Ï;ûÆ“ïÄ ‹3é{Á®VŸt\T¸)*n“qÍ…KЬ¿Ðâ”ôÃ%Ž2 T&ù&q›<Þ"<ƒÄr´o$Ú€Ëi.ÐîZ°?iŽ¡¨»Ps=<íe\¢l­ez0à 9Ã)Q•øá©'òᣙ®Ø[dWí—ǻۖ¦n Ê!Ú-xQæ÷VJ#š) ͦߚé©j] ¯[ ·ÜzÑRŽTOó#ÑzOÒQ îpuµ{Ðù·!IÎO/LuX˜ ²URJö³Z¦°O~p¦®gÂYT¯ijQ`8‚^2«æÙ~-y1À 'Q:·”/öp„1zÚO#CùìÇîäjïî³ÔœÁå!¼ËQl_^XTmYV¸Dl¿‡•†iVèNƳjÜŠ}5õêÇöo?­ÑS¦ÒY]ï¾fxÈsß­@ó¾+¥œºeü,×ÏýÛ7ý°È¦j'­óXÂ·Š¿h¬nªPÖóbMºŽuÁdyü'‰RëU¨ ².cѳ5o/Y®§.•E:5·Vføƒ,Xÿzieç#¶ÊïiÙ´û7= ”ÒæŠqsõ•‰èH§ä­ùóh†sÉ:œoÓÄÙÚ÷4Îõ¬°+ê²¼æ³)Kì4Õ}¹!g"¡Þ?™cƒ÷ ‡Œõ4êìý4GËGPôáÄ_FÌ«Û ö…ö<»Æ, Z~Ì17kqèÈïf©‡F¤Ü¾¿¬Çÿàùðb gÒ4?{=›£q©¶ÜIÝ®ÜjŠ+ïL˜¸'é,­Ì¢°®F–"_¤“,ju(’m´Y'aß ÷Ñ/‰ mÑå «'©ŠOmMr††©]$ø>§<>¶ÿì9nE¡ìøáäþF¡_VÖšbÚðÎLÀÅëþù<”°=—Ò±ÏòZõÀË©—ò–f‰”Z½¸W(ÝÖ Í¨Ë{κ2´û?+ågŒÉeàüKzH•'Ë´[ÎØï³xIÅ Üp,XñöÎ.šFç>M=B¶…XͲ7qÆnYRHÀÓ6šP-œaaÝB‰kkV<Ù¬F›o‚À$ÇØ«U_æÇëVi‚; Ù ¤>¥]zXaF)ˆe‰)ÊP,z"³ŒÖ ^d%ÔŽµ³…Oœ•SZ áøEMôÊçO¥ó=ă‘Þ¸*‡€G]ƒ‹ëõS§ý*HtÊC°9Pß+>æ°ZfWuŠhB66«L6FB»ÀåÙ–'Ÿä¦ù‰±÷lÑð”LGr±¤kÝ(ÏëR<ƒÏïê$ V8zû¬ú®g„݉ g-îbgíÝÒÅuÓ?uõoxÎ1K:ûPÄÓ4¨'û¸JÓ+ήRœèöA¹ãR‡a–UK9¶¾jJrl!þÐ¥b/ÖOµé#bqÃÅzŸØ·šZ¤®;Þó vÄ«ÜûTlÇUÕ»ÙÅ ÐÒHüVKˆ¡Àñ5> r¾‹!vî-±ËpxõÃKú7…Z¤c¯Oæã ÃÇ cHªy쪘-õâ÷­šNŽóx2¿á»åñÍ.BÌ}ÒúFÚŠósnQZk¿‹½²¯ÃÞ6Á»bà:É«?-G– ‘ÙÉ-ÕšQãRr‡š‡†¿9sÖ1m0½¯:wÿ“b@]úgçºÅ^üƒ}î…é1+á9r ¶ÂåÕžKXVì(Ùg¸¿K(rêí^ù=:ýÍVêa>O)ýSÿíî“é¯+1jeUpñM{S*ße÷|ë}™jl~\÷†#Ì´%Ü]wzÓj#è|…>Ô5ÎûNjõ> óo‰V¾ÁÜO€ìû*Peßµ1†þ¡áEó±ÂÀjdATÝÛUº¹f…Ô–î4¼³vTýªÀË(Ø5ª]È®Í[ÿ -O(±/éÄòr^ˆ¼Ã|®â'(K€±Å÷„°™æ~×WöšÈÁºnߎö=Þ–èïóï*–µ»vò1ÊŽ îm0qØÊX¥s+}ç 4D—tœt0÷º5û†¤ïͶM£(¥å@¡7èÇ­I}™7K‘L¼û’±ýîcÓO NÕÆûš§”ÞN­‚„üx#ç|¶ š™W_‰{5ràÊZúqD‚ÏõÈ“ö£®ûãæ+xP=Ð9il¾xp,¯ŠèÝ »È¯EÈøt?K¥ YöŸ8ª„¾¬ãQ¼Ï‘­XS7bÞ èüÞ)y<’HèÓôÒwXŠsÍåYQ’†ÎÄD=íÙ­%Ö2‰~|òöúòÜ…„ %±ä Úd+±Il+·~©ßc ¤ßp}}ÚÏ<„JÆõ4 MÀaœyÉóu‹±Ð¨`«äÔ¤™_è\Yù.Æi)°²€ô¥­P{É´ÊâÝ”° .7ÕÿÌá6uçÁ«–9³"ú´†ðMçsAÜ©»Ñ})w‹˜B•謁Ivu­Vå­,ûV»œéyà®;e7ŠGÜ*¢˜Ä±— å­fØ3“úÖ¹-;О-Å;²¬Åd=GÝ+™Ì Nv’æcò£nFòŒ/($;ôÖhòî›iö`/š4rùÎ?<~§À´ÀCˆør:v«nÚ¨=•¢7+qQkt…ôÁîÁÑg+eXÙ•EÉ¡êþÓÍÂ=¬_©–#/üs°Òïâ}5 ÛµŸ0ŽÙqÓ 8»œô—¹ŽÍÆüŸéÕõ×ëÅû„Ê–üZʰ±™ÂKÄÄçàªÄ_Ãß-ãïT),J¡4"žómš8ù ½º!cŽ‘' l4,ܺ6OŸG4ЇÄááe%Ls–ñZÅ3 $q]Bä±ÈÖî\r6 úß_í+Ê8ëdž ß¯¹}½3_Á— !}Ôx¿à±—Ëê~–ñç`IWVëNìRýö…o\%:9jõ«73eI±ûÊF^;YÖßF‹˜É>(ð•›WÞ’Ñ9¿Ña‹ aŠós£µ5ç–e›—àýô¤spĹÌGä¹sŽõt­¾ÞC’ ìµÖrnYDÜÁH½k÷ÌO%™z¨¸÷‰Wð<Ýj… ;µÉê¶#=:÷Ô×™ÝÙ™ÝòÞn55î!ľ¹à¢š¼M ×4]þhøø‡ÈÓÓ W¸~õ³ý­¬h\ÛÕ2j!×ã ÇÏRÜ:U'$p­N+P$w!v)õßã_ºhÆûqúJߟîÊà v9Z·€‰¿£©ßÍ}þ•‹—æÊÍ,Èèâ}Ÿa:ÖùHˆ@®\Ø…Ž'oxÌþ¤¥z?mu­ðÜç.÷zµ Ç‚_y)k»>s®µâÝrb¿­XÉW5íþä@eåÀ=±à «É§ÿœý‚ý• ýÇÙ\¹;y¹¥H}:éÎ4ã4¯v€:c/}Öçâ-Tz˪2m!=ýŠ‘x§ó§jšszŽuuê-šq5†¬w¢‚”h|—'í · ïO¥§Æ^ß°¹‡ùUVÍ<àj¿Z]b· 0 Ä# Á_|TD±¦#ìl_>Fz<yH¾S乺Óu¨¹hê—«=µ,"7›W®}dù]Ê”NšŠÂ“%1œ<ó¦ÙšôÍ0E–dÂèR3ÊA½U i¹|V£¢(€à­&ÍΩ±åÆËÐd™ ³˜Ÿ·®’Eë_ǹi£e}dª#x׃m•p:[‘t ûÜk à\ç}%i—Ç7œÍå2jcï†è¥pŠ£Ñdاj¾Òš÷Ž'☥›×I_|0LKïñì>¼ü¦ô¸N®ëAh›P²*›˜±` Pvû„þTŽmhªrBf7ø+êóò~¨7òåêlë;¯K1Ý%Á€'yAèÝá@QŠÃB“µáò:¾*Šâ¦ª¯/™ÄcêŒQ!Ù/gÊû}¶7‡Þ¤àåÇ*‰^ª¹;¬ã½!}Çž™Ëé_“ÐÐCð8mI­bcN"/c‡¤ OÛss…Û‰]º¾ ù:VˆøºŸc9jÙ§ýÎôN¸î\}” ©`ì󸇄´ã™HûNw·~r…l¿i½ œ#}-ÀBvþH;ð)d†[jšP+w±Nù0ë³f”C$nyß§¢žòm2JùØ\£ªTÀ4ø”£_ÓßF_3àcáÛõ#åˆÜ”hÒ€cΠ«7’‚W3¥mÛ¶ôžŠ¾@•.>9âAÑ’(N¸ä‰Y‹žì8Âá„PCu[J®:—ˆgh¬; é'uVr±(þX©+.ìlzá\\XÞ=lVÍúê S M.uÏ}ãÒW³:‹ZH;§EÔ,©y¤,qÖ]ú¯éh.³4;jI>ñÚC <‚,»X ¿>Ë£X—–§B‘t·ú¿’çµÍÆSÛÑ{Ò=1ÇŽÀ3O?ýÉâ…t¥<ùœÅš¥òF喝ªòÎØ'=2ɵ£l9Ý)Š1OcGûæõ¾ÄŸH+Zé'è–§ˆ|ïâU¼%RêhÃaoZÑè'ݹηÖŃþ´yOÄ’ÉþzÅ&$@@’Z_èMñ¦v4(On®{`pg²¦á3ùžãŽeL‰íaáÕç¶Jëáûç#éý|¸ä{hÆžŠ‹±ÜÚ(º?Ëuå‹8´“4B–?“ Kæ<ñB#¦Ñ·Ù®Oôi›¨RE¯Gùœ56…M%eíÓÊ›äãçoODБ•×­N%½þl¥õ['_gˆò-¨§´bó±ãÍoS×ñÌ!EÅ©W~¦ÜåÄWO~„Å_å=ꂪFyï«çÝWÕ¤X߈œ»9²ïXz«å¡Øøp,þå GCÓ‡·HqFÜájª9’)Ûøà¥³ù´ ¯Šf?×]ÑÛóêµVưj.‹D³YmN|wpû) ¬µWéç–ve“ù9d™ÌqVCíO+ ï¯Çê~ÿºks{ˆ Ô59Ó¯y¥LCŒV)]óJ GÈ«æ© ~å‡!Ã÷ì/õ0O(i'5Óxgz~ì,a Wm^ιÉIò˜-lC%Ev$¿QÚ—¬ØóÇ9ËBµ‘Å>dÏò Šæ–aLï·R‰æsˆöôž–ò°ÓO¢ñxècMõÊÈŽ-¥â¹-ßv·n„å¼Úû#—˜×Ѻ˜Ù+%ò.eMf]|ºîHûny/Kû“¬á‹ÀÇ»± Õ­ÈD<«Öts<'«…oxù^l5/_ ç—¨lïžæÜ°ÈñõKžfÇ…‚ª§E3ì öl¸ûÂåýenú˜ÊvFmÈ^$UoûÈoõ]·¯^ü~¥Ð«.=ñK?¼ï£h+^gåôNh=¼)_ùþ @À®w±ÃccçVÏö[fà—Ç—!jVÙE‘Àú8ÚÞöçVÓ/SïðLg ø5é&´ÔèÎ\“”õÔ“y¿ý´KÀ¥ßGpâ¥è0ž´Ö~exÕ–—Ã6[ϱ=<õ•n©ÍÔð™~¤2{³{x'ÚÕ½ÌY›¸IO¾Êùú™HZ&¼w(mx¶õ†ƒ)xŸç“«ÁÀùòüë ¶; D™*ÐdÑs¾7ó5¨Ò‡G\ôTµ-¥ß2?nÛFé¿¢?9¬1„ßÎwê;$ÒÑûâ{Òa‘/­=æ¤Ôô}¤CU¶}¹~F£²ƒÏ¿5ž¤Ñ¦ERòP ?€ ˜|,’š¤7žžh–E;Ma#ëÒ7m}ª{õm"鯮ïVAHó±$µÒœóråÃÜÜeÂÞŽÌ®øíTó;Yõ§çowøDC+ª1iB¹r—ïb²VI,Á(Áz¡kŠÜ4ñ¹$¸ÎE•îÿºªžsú¼Úc# A;!çc¦Î"/ýŒx‹[¹._k¦p¿ïm•Sô¤ð õ¥/Xîæ_ésùÎÒ¨Œùq܋ƿe­v9š+‹ú°õô¡–§lO;§ø©×¯>d|#ÅÑ$}œ#ƊYð¹‚#Ô!ZM>†˜¿v Zópk{ûˆŸZòeز`nlÚªY8üY4gÞ’£ÈÉšdzUëъ臯·so±2jìm'Ô¿z©ª¹÷-âÑ(¤i’É,3+àë(2·´dÙ3X-HV‰øAòÕµû&ÑŽg4Ü>’çQcL©”É«wúf…ÝÈÔì³@À½i–çTó1&Ç‘ |®ã>/gÍútC¶8ë× ËËÝD̺5µœ¡×ßÊKk#5û;bOŸ¯ØâwÅÊE5å§ ¤Ã&¶=wNUYÆT¦ÅêÉ#Ž,Ù5˜Æ¥ÃI˜üMê,(E|A$Õ6ˆQÅÏA,›iÚѪ…¢Æe†U-ÝÏ³Õæ©§¿Ëai§Õ« ÓŠUo¤ò>Ë û@\Ù€¾%hz|MøB×[Эi2—:÷:¯sPý•Ó…endstream endobj 39 0 obj << /Annots [ 225 0 R 226 0 R 227 0 R ] /Contents 40 0 R /MediaBox [ 0 0 612 792 ] /Parent 285 0 R /Resources 228 0 R /Type /Page >> endobj 40 0 obj << /Filter /FlateDecode /Length 2951 >> stream xÚ­Mwã¶ñî_¡#õžE?·'gÓ&íkòÚÄ—¾$Š„$d)R!À¸î¯ï f S6W›÷$p ó=‰Õ~%VßÜ|õps÷·<]Uq•'ùêa·J çIµÊ«,Î+¹zhW?ER­yøÇà]°%›mÙ(•Å%`Ù$Uœ–íIãt½‘Bˆèkc›ÉZ3ôˆÅŸ'e,²2ÃÝbµ‘e,Ë”¶Ý»õ&IªÈ4ÊÈ™£&а SÆÒÜãhœé÷·Œ·œã•²Š•¨¿Ç[wãÒéI§* ‹à„$‹vz´/ˆØÖÖ4k†ã±îÛ°b ­>½ucítØZ;<n—ʸH TœtPk`­Ù®M³IÒ‚.˜æÑ}[ 3Û±¶÷×ðN9ÛNt²ÀšÐk™Eÿm:áE~ÇOÝ=Ñ$cÍæ¡;o«t7jíé%‚¤²ðOÓ¶£Ë§Ñ¨Oƒ5n@šþ‚ ÕŽ¦: Ї»a¤¹9ý·æxòTÃX÷ô?И˜¨¢íyΙ‘è†/â’é-ÚÃñ‚L¢ò›ï×*‹î×RÊèa½Q2‰Nãð«n~Èèg!’NÛ˜¦¾FM£ºýYU÷n ÜuÓˆ4ã¾f˜:žØò–Aø‰ÒÕn81`G¿¤§8µ­7 $“JÕ»©oP êθ'yõQÕH)‚àðØñ|«­kÐwô]On8‚òµ´)Ø26må…=/ñ;Öäd¼&n¯{ ÚLºY ÒÍ¢ŠN]í@¾G‚žêæC½÷ò…9"À¬Øuk ûi†4´F=ð „»:;ÜÒ¬éAw[ÒMøì€<ÓèÞ.qV~˜éRaµ§`tK¯°hhž»–•¬¶š'iµŠ†“¿j@hŸ¬ÓGž V2f½&ÃK{i1¬3I&H¥á·óM«GÍp¯òðÛ™£q4|<˜æ Ïvƒ›ëþ[«Oºo®é4ô±§C¦q•¦—v1ó€%’¼Z*Ð@´[C<GÚ÷·ôAfð»À[Úº°àp%Á—Ÿr¸i¬Àò"ã¬îváDÏ5<`« T“M &¥Evq¯Ó`z4ÀT‘½¥ òØ¡ëð pð‹æá„¬ÅÑì^–¶êÓIóý̬ñ‰@üèÀ4íê¶võ‚b’§•E5‡º÷桊&2abßÒÜãLlv-bÑö¡mYNÕ­9Â^=BØÁÝ„¢…dL+Ö¥7:ÁÁV[»@-;š¬ Ž¢!f9›)˜\¾wuG+ÆÉŒµ7uÓÛ©!ÇÉõ¼5!–êžh€_ݰ§kþç½1núvÀ¥›%[ºàP*"džJϲUhÅèqTÓÏÎïy¤öû¼`ä=£fƒnéû¥ÜÄr÷(2Ü#ÅRì] éùCŠ`‘¥¹d—”£Ò4ØíX0š gŠP\Þös "ÞÁ”éÓœ< ¡>au U" ‹PMnÃÉL „æºa"|ž¿ÇÁ:p€pTèIÐH×ðŒ€Òœ2sQ^*ñr@trøëê ¼@Щ ¿È#22lMO‘?ˆã°— ü€1Ÿü~!™¼‹Å¯Gã¼›§MÛvz)–Œh¥g¾®AâHÎ*ËW*®2Nje¶È]H™aÃf¶Õkr>^HÖ»´ËHÕ{‚þu5es0DûÅ•÷;p†Ð~p<ð–¹ïÌÀ[Z <y»ü>šý¾cÉ@v.óêòÂÃpäà³ã˜tàðb¬tˆ8p“‡júÁ°Á9'®œëÀ“5â‹"á¯7¿ÝHŠ•\%e—ªX¥À* Ñô¨'¯“‚Ÿ›ü^3¶›S=úÞX}¬{lâ{à…¢â4ªi®ÐŒp´ÌÈ`²*˽ãoxýÁñüõåÆÂ5ß\ç‘îÑí2Bjì ÆÁZ³5ôÖß¿Í2j}.Ñ…íP¼–ïÈØÓº)ôyKæ>y1"h:íǺ¥ç˜x Îm ä>¤è¸Ýt"訽 Yšà~""ç5è?ýæ¤ø‘M©|ö`€`îÎYPMîw]‡ÍYk¹AÔ 5·¿TÐU\våq†Zñ¯žF:ÏÊúê¥@#÷ ÏäÙö`ì•~ùÙD)Õã0A µ\“y ‚¯sÆAAf¨BÓqá ®Óá,þE&òÓé«÷ 6 T·fOÃH^ñíÄ2èZYxO37³ü2˜òêÑì÷ô43_ÉHò3’"Â'&O|¼Àuò‘>ÜCãê#VבHmˆô¼ìƒGËvæ:|²—øl‰Bk(~ÍÞ“|Ü=Ö†c$zŠ0mÚ}O]wÇÙQ¨&ä3aDn·ÑVô}é¾3ã¹mÚ„ L|U>SgÓwÛMÃ{Öà^pd‡iltxýÂ7?}ùPÂÕø˜wVgðÇFÛ+=Ç JUÅErµC—忪W¥WWE‘SÖ–ÇQ&qY¯zÁÏaºŒ Y`'¸Uh+:ÝýœdyH+Fýs¢$ßJAäDœeb| ¯™7á?>ï¡Q¾É9Ì¿ùŠF?ÜǰüökN§Œ}јå é j„eÈBð¥ÿGYrê dKÌ_8%b ‡DœÉ6£9¹¤GÏ [ýGµâÜ~ÿ~óÕ¼WÝ|ÿ~ó=ß$Å…~¼;§RÏ—HD,@®› t…ƒs§www pÍ™ßÑøññ0îï½Û>mÖ›BF}ƒ¿IÔ·wpØÝKÕú?¯Õ¯endstream endobj 41 0 obj << /Filter /FlateDecode /Length1 1390 /Length2 5891 /Length3 0 /Length 6846 >> stream xÚtT”ïö.‚€ C "0”„twHˆ„0  13C HKJ*¢€t§t#©tç )¥Òñãœóÿ{׺wÍZß|{ïgïwïw?ÏÇÁ¢«Ï+g ·‚(Ãa(^> @AKKM ñ‚$P”#䯛„Â@Bá0‰ÿP@@@(ŒO„Âà´à0€º«#@@ ðPB@TâÿÂEÔ ÅP‡Ã H¸³'jk‡Âó¯W˜ ..úàw:@Î ‚€‚A0€eqœ9ôá`(åù\’v(”³?¿»»;È ÉGØJs?¸CQv€Ç$á±ü  r‚ü™Œ„``EþñëÃmPî €q8BÁ“á ³† ˜ÃújšgìXóààïÝøþ]îoö¯BPØïd wrÁ<¡0[€ ÔÐQÖäCy @0ë_@#ŽÉ¹ Ž + àwç €²œ„ðïxH0êŒBò!¡Ž¿FäÿUsËJ0k¸“†B’üêOŠ€€1×îÉÿg³0¸;Ìë¯a…YÛüÂÚÕ™ßuq…¨)þ…`\$ÿñÙBP ˜¨˜0â€x€íø•7ðt†ü ürc&ðñr†;l0C@| 6̉䠮¯ÿø§E" °†‚Q+ˆ-FòŸê7ÄæY>ê0b¸'þúýûÍC/k8ÌÑó?ðßûå×ÕSÓ4Påù3ñ¿còòp€¯ 8€WPŠŠD1/>ÿ,£ ‚þmøŸ\5˜ “ñ§]Ì=ý«e·¿ àú«nÀ?‹iÃ1´…¸þÃr3 ŒyüsýwÊÿ⿪ü¿Xþß )»::þsýŽÿaÔÑó/ÃZWFZpŒ`ÿ }ù£Z-ˆ5ÔÕé¿£j(F r0[ ›y„ù€ÂüP¤2Ôb­ Eíþpæßð—Ö¡0ˆ. ýõqÁdÿà ì€ù€ 1Äü!1jCý^ã/‚ÑÓ?ûP‚áÖ¿„'(òB @ž$˜Õc,€—F¡ÖßÔðóÁà(L 3³ÀŽ ùµf1¿3f7pë_~’Ô»"˜ÃSsð¿ìß ‡@< `’é 8øQ}EPãI™ƒ;ïÚ$þ^Ò‰± ïPö3"T—ÒˆÅrœ~zÚŒFòt§€ò3ûmy—“Œ…Éï^èJæ*Oá#^få [f«˜‰ë#ì±x¯cFÖ Š:¬¬' òL]Xºw#n¶ËXÛvésPx߫蘊wç¤ÎSUnÔnn-ËKÓ¤e7ÚYyŒª·ê5XùAw/sÅ):p5Ò,,Q;…UC²ù”$νôæRO_ïeçݶu·€µ}ö—(J¥G½ŒŠÂ„¥FsïÈ/2?¸m§PyY©Ü’ݶî*\äN8©Ð>´Cn›³Üwę́¥ë$ÚÉÑT‰{‘’Õ';[ö=Öl¢(¶@í!0Ô"ãåçQJ?`uú2§/X^HC  ÝÕ¢…#fý"½ú¿.oþ ÆywU\ •–Ô@¼¼4äeÚŸvAµSe|µ[)\ç°ý™„ÛÀäÈÊ'F3wbžqd¤N¨F}õÖ ‰5,ð‹(É#¥N­Ul¤û`vk,mÂÑŒúH¶0Z¼€Ý»Š_0+>«Ê¬üNŠ÷Ñù–@P¯ÖÙ'ooü­RWHÒͲhŠ˜EÈ'B³ yߘÐkÈÈ’œë¶²jçéýºr±©’§¯Ðñ‘ÆÕ³žù¡¥8Láo–äŠ6e7:ö¨Š=)îÖh“ÉÈrh™Ô§'§Ó0, ˜ó7’Í”øaõqúªÝ¶Q.å:¦›2*ÎíH°—º®%³Aï yÚoïEþVd+xÜÇEåG Ѝ¸žØI£veÞ ò„ŽlyEªšØiû±s蒥Ƴ¹8D'änLv>ø9¨»«QPFF}îåB×òÚIÐ =­ó°®`‡ÞbÑ[‚ÇÏ×UÔ|“ˆÔ(?LJ”²P=T¾êÆÜtM À)õÓ0£y ‘y7{­°Küjéën¶¾¢ÀyzC•‰På™ÃfEÓg NC ·)úøÖvFÏ•‡Q‹Í¾Ý…ï±[¥¹å è¨=M°—¦Ýë Ô›N­ýè9ÚvyÖ®"ÞV´Î`Ì–ý#Ä,Z&¹§¤8E‹±èà…á}Ó冷QOž› -çóV¢E\ۊǯê½È®X÷’{®•¾8ͪû7›ÞMƒ©¥S·gíõžtÍÇ¡d ›ä(å±5†Ôðûë&twmáxÍ ²°ÎXß'+ðJÉ£C ëdîÔßÜYç;±Æ¹m@Fò¸Í!7 w÷ÊyõÄ)Fy~£‰‚½ ïd!ø½$gdÜ–NZäÁXPéWÜØžB•ªºLÆ·œSãy»:¹ŽDvjøü‚ûq†Õcœ/I/}”D›÷`wÖ±c±ç’™$ôà;=¬X7ãŒâ·Ï\]›8“È%A±t|ã á—>;Ñ5m Qûçéã??-z’Òã+}äRê*¼^pzmxÖ̳œÓÒÆ!âìxEÄVÝmÊ2ÓŠR§ÒÖ5hÜòãZªØÏ`Éæ—]Óêï0×îæåC8àBïXK“¿œw§­„äSP=ÑÍ£’6ÊBÍR–çOƒLV’Y°EnkD ê¨ØëízÀù>ºã¹rLIsðT–KXêë±ù i|O¾XI•z€&lC¸òÚ·¡gêXìœOÊ‚ìÌgÆ'[CíêC¦s& w›Š?a¯µI“ܧ üÖï WßEMå:û§þ&‹›ð4½‘ª9R#;Æ~ÃWºI8aFéæï öüJ×*Öíסsån§–cijË?UKûC¾Jn®ë¸;Ç.§½âÊÑ­û ×Þñwã‰ga·Ë•Yº„w.¬$¨†{enj‰û+„–É£gnMÈ– ·7Æ6\*=*¸A˜Íkç•yâ_×cƒKÓŸG|öÂú#pú*GpiKÚ/pûIB6˾&õž‡±…­gÆ7q1Ÿœ ¾•‘Ì—Ç~¸z\Á”| ;âœ$.™Äµ2TÄÓX›¶él¦+Tkû6K ʉËÀظI…#üPŠ7m\âÛô<«x.|~I "Šyèù` Ûϼ8…ã éè¶+G9Þ,KN)ç1’‚…&DŒf }þÂ~p1†ýî.Ń缒1ˆöñÅBíÎ =e¾lÛ÷lm±»–oÏŽ®^N¼xnõÝž <:.‘àëˆz”/¡– ô§ÛòV Rž±âµôö)îŒY0•çüøåÓýº„Z‘*•»Ë¯”íªy%ý̈»ëÀÂïMüšý3ƒ§lW+*)F Þë…c=†V™f=¨[0ö¨µuo)c|qe,X5.¸ÏÏžL+ÏKAú˜WÏ–öxw¶Ãm—8 Ä5ôÁþ s7.Ñq,àZûÕ¸È 4¬@OUl»úã„!c²©ô'aIð±ìÇÛ‚â8POe’D*3%­A;Á¶Öù·g¾œiMÞºGI5''xÒŒxô#Ïý£àÄŽÈ}Ç-ó^ç?dQ#ëâ%x,x:îÄdJ,{¡4¤ ®ÆV#Jˆû9-uÍg$h7·ËÛ,l°Y«÷—±ˆ’<Ún$gñ@óøWd|¢æå–ùW-\³P–:; b:8Wú­~ñœycOßLÞm›‘­šAúƒ™Éߢ­=>*“Ë'![0@OSº@yê¢ñêŒL¿g“J^u˜B¿tŽç|P_=BõM6Æ¡è:FO{%sýQ†…1Ôäýé±Ý‹1ÙU‰3׃¯ÔC]†¢%øñyTãR~SàµË©‹|¸Ø¨jÒÓEwßœxÐAú"©™ÝFå¡ÁN˜ÖXÜJUÂÈ,)1•s¦9 ÷ñâö¬K( c™dBí‘ʺMo[»U÷ &6,?ÛPqákhpÙnãuÆWo¦6ø®’ï2¯m0‹z°‹¸0ˆE’t—(8ÚM‰fîÃK7ì¦5ós­ˆY㨠|{Ãᵑ¬„P+®ÃÚÚ´ýÃÆ‚N¥uø š&Õ—·vÑ U²¶ííi–2ãÓÇ7¯×ßqd{sˆ/¤^å”W—ã ä¾²OÜ,jgaLX~)œ2e$`yLì‹;oÅX/*ŦnZñT,°òöŠ£¡_˜"F[íªŽ|8W&4D¤IòžÕaê3€SÚz¯±¡.4Ínr2Çc‚x'òÌoÙ¿Ür<ô:qµÉë+ã.h$»à8*†ÄT7©Øœ|+ÑR<_ ²00¸o±Ä®Ï?*-ÎzÄvSmҽȃ¥1^àtS²tw"ßV?ôHíõÎÍ_Ï”à˜s _ &?£YðÒS¨µL¯ô Öë9Ú‡Í;µR™P)39Ÿ JH&Ž¥íÕùãÄl7_y_Ó=tµÈK -RÌ‘,•u~k¼ìp‹S×ó¡hÿêƒRWk5ÃáÉÜçê!)÷F»¬ÂmìÐç_p—Ê©ä†m’‰TýµHãX]˜—¼o¢Q(`áÅíl?éèIì~“ H/°ÇL©Y°Ôñ— á0ö¼Í“OÌöC«<ÃÕv•ªÐëx”R©ïðä"AF´RSÉé#Š€Zâò`íªýœ8ÔH”¹HíŸíÀ=~¡tQûÕï§bãëš!9““üÜBëå]­çþâÖäí ï EÌ5É'm`õêd|Ã[&Gè”×﬽òôn4lãÅÊ|¤Þ ¸ ¡DGŠšÒ•ï ”æS}¥å}öÎ kI¢Æ­W ß­ê¦ì~$È"!õðòNWÆ…1ë[5½¯Ûã Q^Sj¥›_kdóŸÑXò¯Ê¡5ÔÕ²_ôÊÀ}à¸dÉ Dý4ÚÉM/jÖ²vì”®”bÞìbl¿ðÇsy`/ËÁ©hWTüóà~W_~°0o"Ëè¥Kèã³®qxÀ‰ì3©C—h5¯_k_ÕðÓëü+¡îÉæÁèÅsjöWЂ×È|~^FkdÓžnBËÜx\Û|mö çä½gßoåWíLH®f(Qáô!XÛÞÝÍ2ørÖqjZØùAß§réŸMÕß~91"žžXZ)"»³'즶’(Ir.ò¡P9 òî „’©†.‰6M?%•àG"[!ÏVÉ•¡²Ò’“HNæow oR_@‘7|xÅj(AÙ”yZbEã ùÏ._:tϯc/œöëñr+/ªm÷òœä»í6’ﬕ)Ä[rSþhwXWKôÙr鞘Ù*’¡wÍrµa˜ÒÆ›ý(ÏÑ©„U‘S£YÊŸ‰Rág0«ƒÆPÁƒ¯e~ê¿€J¾GŸtb×7²êªóÄ ËžXÅž1áäy÷ô¦æ&pMOÔŒµ6¨txãÉ„×tô·Í¶\ýŽ¯È¥ý$’ÂóÚi48”N‰ ój»a7gUR‹§Õ‡Þ˜¢7ûqÇOÞÞïƒ<ËŽü×Ú,ÓíÄfÞÂ(Þ÷’rôc¸`ï”\£¡þ›6|iÂ8­6`šÛ>Õr%XœU0$r|ù º]JÕe¡Íq–;òMÉú6%ïŽëåÚ“ ¯äÊe¯´$ 5ïø'à“R~%ägùxiÇØÅTæ¨4ðbñÞ´?ÏaGùƒÓ\á‰Dâ€GÊpV’¸È‰@Ð÷ðݧ—ÖÞx°ÂÚÍ¥ç´ï^O"¨øH$—éžg@©K3²aO}DùãØLÆÄëï=„»|OAÌÇû/5ÑÃ*wv×?JT…o›Dç~2Y"¥–žòÕ N{Ps7˜ì>šÌ¹ÚÓñJPÖ·7Ó‰t-BÃ`3‡/NA­¥Èývâ§9Õ=Œ?{þùÀKPºe|sL…À¼3ÙÄrwz(Š”ú\ ïÀ>¿'äË–ïƒá®ü’O+JÜ Ò6 ÷„.û¥'vä°*ëԪ͓Koݸ=¢éürevy—ÛÕÒßðÉ>.$|N2ˆËr!"¾b×~J¶²ªG‚ŸÌñJútÈcD]0È@³zþ°´ <7¹+†SŸÿ¾OúXã¼-³Û´Ó©ùëÃbuzåé¡[ªŸM•å]ÆIá&$O.NÑGQem㸻b>ÍLé7JV¯%kò¯‹qÕÚËTÑ.¨p|óÈ×¹J4¹ótfIÖìý-‰i|®ùúЛô…Ì úJØ?Ó'ƒ€’`Uœì˜+Š5¸Ü¥2(ö¡ï#O’±q»e—Í¥¼9iê7ÑÈ‘äøœ…®&CÞNÓÀÃ}ŸQÈ;c•j.g"¶V»£Îjöô¼-eÿUN¹µoùk@ê] o<È›‘ÁæÀ¹Yã¼ì-x’ɾ‘zBh0[¤»¤XA€Ö7®ND_§½©£üBv5> ý|¹“‚{1ËH÷Ö$Ý)¦³”·QþøKœ– ßÍkõZ2Øâuõõëí6ƒ0ÜŠÒ½§¨#Â?SÌÆh-ëÎÂ`±KŸY¼‚öÂÖÑTQòæ@…݃–zþŒ>/·šÁTÉe¬´ù J6JùÇæu¹U¥êëR_Ò])Ò®b;ùC×»µ[ÜGšb†²Ëã…ÜŠ”Ó«3ý]nGo9 T<«xrzç.Ø=o0º?ŒëÖ‹ -q¦nߦ€.>Ÿ¤w4hÊUñ¢ÇAÅF¬ê¹ž;¹Ç†Ââòá KŸY§jòYóf5o¯±®"öAÈ÷ú¹™VΟ²%°–öÀ/FU%W$\7F¾s/W{œÝsܨ˜¿/ýi<¡BFk›øÝëú†ùÉÚ)q»bà£H¼øæº,Ÿt)ûGFÕc…P¢ûŽRˆË¨lN6J&ÐÓ¤;4@áë\ÈJìsŸ;ŽV¢(û&jµkIz“YÙÑ©*<\Qsx §ë«œ+¬þ$FãV~ ™²feDÜ=ì¸a½„ î§Œ<úÒ9ÍÅÐëÆŽÙDæÆÆV¶{«?îœѧ29ðuæñ÷¤ñµ€j©j½'̓]¹QuûéäjLõ(:=|îÍ(rjE£ øEéT){Qrøè~QTøCÝ·Vá ŠšÝ?î Ï91˜&Èîè¬ß9wŸ£v/Yliz¿WÄØ‡&‰«ªn½µÂCxå†î€º‰‰ˆz¥si5H´¸Â.ïè-|è£üü.&Z|ÀÌÌȺ?õ<µàêVõp>¯$p›ÌË–çÑ&N~ßøÐee«âð/»­Ö‡­5_Ϙ›(®Ñß6Št¼%Óœþôµï »WUzûÛM¿qê:w¬¥4q¾¯òFõfÝ_p"9—ƒÒ±ïRV‡h¿5–/霃–´žI¹‰9UMu1ë°}ÌêËJOTó^ˆ“#LO¹i KiPÓÐÜeÄÖxëñá‘ äÄŠ'ùÂ3:Óž§føõØj¡Ë­›^šL!Å'÷×kwˆØ½‚6ÛßdÞ-‘óe&ß­DjÛÁ´iäU¯³Ž¨Rù¼­ð$R}.®CÙÏâ¦*V™±&Î#»¾à´'á²Ï»<¹zÄÀðé4—-`­Q¯5™OÊ‘ú$ªm};“YíV„côöíCö©–*+rd]F%©5).Ü€jwØ{¡Ê3ÒÑ+ß´§ï°úPì®MëÒùdòÖÿ¬ììí4Ôq)xyóâÓ~o ïlÇûÏ}»{í‹)Ó”Û‘?-¦ñ>jîê?Nbû”õZ2 &(3Œ¬ç‚Ÿðz€+G²)Q•²Df󺈓Ù§PM?û=âépYñ£vËGW~ãÎòDblñoÉe«(QâgÐÁ"CVVÉ– ìK0]¤¬k+¶íMò”|*_i)Úf4þl¹á¢jP³F6ä–Zñ² Od9«bB]ŸÈb[õfxާü2ž3JëtI3&c†ükIq.‹é=Úo·ôÇÓÈÁ‘t3z\–7«~0ø‡-£¶s¬ü§Þ˜ŠiBí†üõÝfêñp.»¿ÉLM½À·Äaß+i}4<ô½HY¿u/LŽaŒùud`3U׎%ùpÿý!*Ÿ‚Ì­g5_ù[Œf»9äx„+rßÊ™®îp+èɦ*êN:Ý2…î÷OÝ¿014ÿ¹:Aìendstream endobj 42 0 obj << /Filter /FlateDecode /Length1 1495 /Length2 7651 /Length3 0 /Length 8663 >> stream xÚ·TZ6,-!)%5€t Ò)Ý%9ÀCÌÀÐ%ÒJJ—¤( -Ý ÝÝ õzß{ßûþÿZß·f­™sžg?g?û¬5 ´ÚRV0 °< êÊÁÍ Ȩj €@^N ‹Aâêþƒb1èá.Tä¿ì2p0ÈÉ‚\nª0(@ÉÍÀÍ àá<@ ðap€,ÈbPå(Á `,˜“bcëŠ8å?K³% €[XXýw8@Ê ‡X‚ U«-Øq¢%È  ³„€]½þ•‚YÔÖÕÕI„‹ËÃÃäè ƒÛˆ³°< ®¶-° î¶ü¢ P9‚ãÄbèØB\þÀÚ0kW @K0ÔàµÃˆ³ÚŠ*u'0ô³ÊvÀ_Wàæäþ;Ý_Ñ¿A ¿ƒA––0G'Ô µXCÀuyNWOWvjõËäàCăÜAÂáwá €¼”&„à÷;K8ÄÉÕ…Óâð‹!ׯ4ˆK–ƒZÉÀÁPW¬_õÉBà`KÄ­{qýn«=æõù³¶†@­¬Q°rsâÒ…BœÝÀвy ¬0°+€ óÀΰ§¥-ׯä:^NàßFî_0¢~?'˜ÀAì±#~°|\@î`€+Ü ìçó߆ï°¸¹VKW€ØÅú';[ÿÙ#:‡xŒ€áq€¿>¯LÚ²‚A¼þqÿÝ\.E5iM}m¶ß„ÿ6IKÃ<>¼Â~ €È+D,üþEù« à?±ŠPk@øO±ˆ[úOÁîuŸù¯Á`ü;— ¡X0€ùù–ˆ/îÿg™ÿùÿS÷¯,ÿÿo=òn¿­Ì¿Ìÿ+Èâàõ—¡W7W„öUaˆ €þ¯«>øÏ¸ª‚­ nŽÿkUt!f@ jãð÷%B\ä!ž`+ ˆ«¥í©üÁu ˜ Ö€¹@~=(n ðlˆ©²´G<.=þ6Cóï#å –0«_ÓÅÃ/Áá /,D‹;~€7b ­Àž¿ àâ„Â\!=?€5 Žõ«Ÿˆ ®?”ð„Àe Aˆøo€ÀÜàÿ‚.(¢º¿>aì¿öˆ³¹\Àîˆ7ão„Àåj ÿ—xÀþÉ!àòÃÿÿ¢hé‡#ü·üÿ³ÿýš€Áž`K¬™o0ËgÁv5ÁM—URCbã úoX8|fàÍn?q1’Y*3—à?¤’{Ûñç×ä˜Ï%gin}öj1Â>¿Öl¼ö½1KÐÝhÄš!ù:œ¿'õ¡‹ “’CGrÓ÷ÖÙW/À¥©E‰á³›®F.Ñ¥G§‚燮ҹÐoš›•ÊØ7¥c1ºÑÆE 9™“dtè®TY =ñ&ÎŒfßÓ(%°aùíÇðø¼X扽šô^x¯ÃãÒJþ”üÊ9áÀ(£ôvŠé”OqÁü×iÏÑšìGì©óøœÛ<é•­(h]GµûÀÌîõwÉ€`&НD믫Kê›ÁéÔ‰+Í¢ˆ\«yíÁTÛ_¬¥š~èµYÛ¥RÎ }¸L Ò¾®~”á1¸` ҊÛ“¯äq4˜ðFQ™ÄnåÚš\ÿ†ôVñÉ>§½»Lÿ€¾ÙuL‘Íœþ‹óTýê7/çMh•é<{:º§#FánûJÑòƒ³{WJ™¤ÎÄQòO¤MóF­q™Dy¾$X$¬'Rj—£{“d¢Šs5Ø/m‚šW{¿h”ÓÙ´$Γ¹.ûÎÒ§9m&l˜á™acœäIîbÌ<þAÛÛpí2B0Dãör~ •+\HL#ÃÃæ“ðÍ“ ï)kí¾oÁõ|¨=Kf]•ìÏýî^^™±È¤HÝ”f"JtYþ«ã×\ñÉ£‘‰ïóQÜ’´yîÏ܆öq^†oz¹þèW¶¢ëÛ°¦}‘9"Á¹û©»»àpà\Çñc®ô­Ãæó³ŒwýrºFÁ/äkJÌ5ϼXÌGIç/m¬ÀäòŠ©p]ޝJ/ï)¢<ÏmøB• ËÅù´Íø¿ÿpñ:-ùQð¦àÎÓ»Ú“7꒪ץyÆéýèÌ*#PWKbÓz3d£N>QVSºymÞY–?æ÷M_ >·ó™Ôà |µètºHAóƦù×n“jXyÚ‡’ßY!ãìwžŠs¬ê\t)­ØuX®ÜÏž:ö Ü3<êÄæ|»v¢Ï‘fËõ›š}Õx}IÌôµº¦PKÛô]ɸFÿÇ· 0ùó* æ//3kÈjàÒã6´–/<~?×\:-Í<ªHɈ!ÙN½¹6¸NãÁ±òFÄgÃKêÁÓzG‘KÔÀ¦>¿Âñ"";SãÝûÎÏâk.·[à”›®o4Zöù \InÇu”HŸÜü À ½Ð†Æ?¹<¥ŠµÚ¢ê™RÓä~/J™;f~ÔöÈÌ<ø­ã³Y>·x%ª'¼œ¶eᡊ4ŽLkS¼n™²ìn¬>,e´ÉòÊ[Ô^Ç¡%F‚ 3€†AÚ*ƒ’Š »OÕÄd½xÍUHÝÐ#yŸL5ôßÌ6žGnUZN‹ðöêV'™Û±˜ 9¹HÏ_´èùFE± Júñ•b|z…u½´Ó€³\åÕÔ@47Æ{ÅÈ2½Æ?M§®ë”æÛëø!G©Qþž¥f’Ìœ•¨°é0¦ÉGâÛùxŒEÒE¡I¿±ÃÝ{Ô²‹üfçüz7ÍÈì±è8—ÊðIS4‡TÕb¹„dðPšóÐyÕ¥^sóèü}™×²ÞQ¾ç,ºTŠ?…>Ù×öÇuj]Ÿû>;òFg{ž>à_`Da” …\ðHú¾cG1{û†"»& x5ÊÁ© qOPa˜Iø¾'ex@[ÕÏâñÅ$I¡Ú•jéùøè}óõ”òÖ*rÀêRᩦä ʧ{‰+Bw  ñó€Å&(ÉËœCàyöË>¦Í±…V…úVk¬d|·á²÷¶°²æ´'Ã|ã5Þ/¸Gf ׆Ž!ÀW5½UÝj1e¼œÈýmÏË»ØÙÕ6Íp÷B¸} Û#C\jª瀜:½‹Ý+‚bæ³ïqá)ö[𻼠HÿfúxêéÔ3”²sSÂAHÕ¹}ë#u¯hSÞ òlµ@S˜\]Þu‰&¾é¬§à9o`³„ O°ÔHSº†E_¾sų™¬[‡Ðï-îÝ4záa‘ëq·µÅ+ˆ_o ñÛ>G}÷Ôvï@{9@a 9à¢}ýò‰,QAW½RÝ|´j—g[ã e©•Î+ΜÛ̯±öùÞOp<:ØÞa %cá cx<áëÔ¸*ÝÀ¨Wr+Ú@-ƒ´ÏYXœK¶û¾)-Àÿ“^ÜõBa…£ÇX‘B¸M€DË0gç9£°MD0F®øÕ ÷„ºW¿2µCQâkjpׇžBŠÐöäcÃg^ã60’«™¢ÏÕ×Èv![õ&åúךí^f-äÊ︿šI?÷1÷ ØÂó<­Â2³©±1îR¬s8¤I¯Ž çwìdÈS^øZ)Q¹üyu Þû¨AëhÎ~})jç›WEwËî²(¥À Ęb dÑFq‡„Š£÷`Ñ&“7þ¥Ñà Ô·ÌŽ¬âF— ÂÛµU‡m–œ‚rh3!È~å_Êkg–ËŸTz9"ë«eâ‰inõÿÈz^•ü³N`*&ÍR“ý8W˜6Q;hw¢pènɆ#!|UQdë³%c/,M€¥Â]q±WîcÖ$SHx |;UeÂ[N¿‹Ì®®T(äûrå.úhø°a²»C½fÃÜÙè¹½*³dsÔˆÎç§A ÆÆc„94‘û.˜ZÕ1øŠÿÒkTƒítOGŸ9|]À}h—%öÌó(ú®³ü,½¯oƒ}†VáÔµ¦qÚZÉ„<„ùáyÏ< Î#Ä•b•aØÕcÈ-e#ª{5•4`»£{çw¶¯ÿ„bÊ¡jÏ9´ðÀbíƒÓK‡¹~NÜ–ja¾NóÃ8Éo,ùeÔ„ïh¿à›Y1 cNÖ’û ÞÓ‹‰ÈE …Ñ–Wß‹w;7<rs©˜ògâ}ÖÞ}ŸØŸ¥µ©æÊ Ç£+ÅÅéÃz¢ŽwÿÙœP*5 FàiÑ{$÷èl,-]Y)v¡þ¬ÆµC!9¸ÛdiÁ9ÝCò¨Õþd’Æ,A_׌¶G?øþøòàà\(‘ì¤-;;}Ƥ”ú•÷½SûbsßÉ$£-_GÓT„ a¿æ“p_¢ÝßLg’ÑÆ© u¢6f>…+èU+¢ö}´å *ªÄãN6 š!Ë¹Ä ›l>ëÑŒp±poÄr¥íhê|*îu(¶Ç±ê»ù^¶…fþ¹tÙÝçêº~.®öõ…@4›QÇoW¨Ú¤òWêørmPÁñ®Å}Ý¥ØHÝ×»Ö3 ¹SMr¸x#ž·åŽ_Bg'ÌÞ†¢Éækö(§.— ämC¬“b—ÈÈ«•îKÉK<·‰ûÝÛËç…S®»Tƒ[`ŒÍ¨‡MK¾qnv±þ¡7¬u>¯SO\=ëzð,ˆ¿µ9 ¿fÔûV íÒ,܉>ñ®9%§eyëi”‘·¸ÀϸÖzGeL/‰ *²‰G¹yJÈ?ôÔ#høÙ7ÇWºž%,¾o»6´ ¬1Y åû“Ÿµºà>á¢a ÜúÒ%Æžô”Í{o×>ØÂþ˜Ò]"\IGθd`f£M·¨³Ð"÷eâõ õõMíÃTlJm’Csá üÔÙù.ÈQœî/-E»úЧ%dG&ÎL*¯~¤m`n´¤ÝKw+HÔÑÕÒù»Ž Ë]j“±ôŽuI¯{ŠÀ@+»!ÖÛ+£dSÍ(Dï˜ žß§«¥¨0}f7ã¾nÑAY©Fñr’¬ÿÞ)¾Œl¼Ä$ã‰òRE­‘e¬ëHo-n1éüõ:pîº*'í,bœ\ `œÜUrŒçßÓé‘v7¸ãuî­FÇû:(!‡ dx¤HG‡iQ¢ûŃO¡}*,…yhe%ëÃt%Ù9²•¨~3*¤ÖÉ-”ÿlë|ëIÊÑàó~ rtv|&ŽŸ ½'*-¦¥g Ç}¬õ˜Íj»•Ý#ù]÷ª^‘ã»Ú¸—M§R£w,—¾Šë^þui’¤X¹ñ÷R 1i@¨øaØ'ÑX^Y ¼R\Š(1*åã‰Ò~,Ò z¯ KT%Æ=û·o».þw6Óúh OäŒh´¨H=PŸM°ä“þÔ‘7\  jº±c“ª„cè¤.öÇîÇ^PuÐ:8¡ 3_Æk)1òEŒm …yË2_õÏãw’åêÕ)è ÌÏÕ„vó  Åð8÷ªÆeÑ…+‘8]P,} l‚ ĵ«Ly ïq3cÛûxšjH><Ÿ:š3X°Ñf¥Ý¡ºçc¬”©³RgDj•Õä6s ³ïúðUT:ì+ã²Ìl‚ª9Ñ]Gpc£2ŽÜæ™ùeŒãGlð@¼ïš¸40N—2òÄ8&ßBÖÁhQ¿¿1ÃnG\iÃí„9Nk¾xy$µ+¬Cõú0ãY®|ÕÈÁÒÇ’éFK×NæÓÖ~êÖ蚎;~,޶˜Dµ;DŸ›!Ÿ¸áË HÐDd– ͬ#ÿ‚éÚ–ÖC_ö<¸’|vOón–«‰ÃyŸ óÅÚ¬œ¹°WlnDe¶½m›;°ÒtÁÙl²§Ú1Óf òŠBJ¬* 9÷™¦8¦‘-x¬Ì‹ÒÅAéMÄ$Ξ`AKY‚ûÜÚPEjôå­sÐÖ7RàÁ§uZ,ôÜÆUa³À_ 省ÿá»ìX ä_Äè߃)9u>>‘©­ƒ¹ù`Pæßipû‘|Ä1ê<²oË¥=¶nèƒB"W¯N…B@ŽÎþ¸Ói ´Qx<˵Çw ”]E†é„iD.~©Ur1$*²• ÃÚ¬,’jBü,2_çØÓÉ<Î/?Ž¥ñ‰5OЩz»Æf™ÌI)±˜¨¼Î@‡ûG³*BS*³eL·4i› ‹HI4õ3ªŽßFnD¿¨¹!´Œä™Œ×ÅÍŸ|6ôP::µWÞâD~²29AèÌŸjý1U‘*UJ`}žÀÚ˜ ãÜI1þ©}¸òãÉÆ jœ¡¢Û¾™K¹6õwUkËéHœH¾Z…Uå–3Rñ™ÚS%›R´ŸP—uigÃ>;òäÖw†Ò³ð½ØÈƒàóï/dý§ü5NÚÑèem2jÞ9‹`¢ {‚-ÑM´Æ}¼eªQÂ>Kx©Öþƹɶ¬Co~£ÄZÈZ\¡œÁææ¨iRáÓÉX4að¼éR—g¬QiÄ9=îÖa1|À Ô»WÆ¢~PPÝø"q4g æZ2<|ዺHfÍ:¼Ú4vSDµPØ¥ç.${ÔY2˜U6ñ§á3|ÿqÑŠâ2'`£ÃØÉ‘"†@ªÂžWôÊ‚Q4™»?·{´ì2ìy¤ÒÅ7)ƒLk¶Éµ¼GŬ "vRX.mì¤^3y†YHkX‰V®˜ŽÅ²Óâuä¸On8Nc+Ñ&T³ŠVTsi× ÷´#‹©ûPÍiñ®ü”âaS ²Ú£[u /€)wžhtĉ—34þBM-P–‚j­}‹Æ–Œ8:Ï—†ðXyKœ,Š“ŸYyå'ñ¸8Fh_£×¤d1ñ"Zfìˆôä¡‘!M}SÒ9æ{*ó‚è䈤„“ÁÚ‚"ß’s-=U¸¦ÕS»˜‹2 ð“ìÏå1Ì œæœ?¾?rm}eNvÒãžµý£6ʽa Àƒzε2—_ÑC¯×/ªW!ßÍ„’y´{¨»±ªu_âÚ?ð´ŒÌ|{¯—7Ñ&üþy»³POoþ0ïIîÐ÷ïSþ“ég¹AœÚièl=¤’ŒxÍ‘ Æ£&­™úK9´¹j‹N3Ä ŽC`¢u\“CÜ´qKN6§Ö c[.rRuJE°1±¯‰*–·þ aûñê@¦þG !êGÝéºguš®wk™F‘/–J 쾦Õú¢hòÑôlʈ¿O’ÂÖ7~ʆ8“úÞÍ•iÉzovoüìºM2ßï™!£ÜˆÇ%ß®j¢À‡ölÛ¯Žƒ®â¿SW6§nQô’š÷ѶÛfD=Ø^a¡5ç?‰4•ÿ,kve°Þ‡‰#Æó#,ÈIíãï>%‰Ü{¨»U'_Ù£¼Y¦­Â¢Î=dàÍóÕš ™Ò¹íÜ×^Xj¬ Æ•÷âÁö>ÑRîX _6Ñq• 4B›|W+.²˜Š¨ìm ÎQ¿Œ?÷{2?Þn;FEyÃ:ïdN¯)×MÕ ‘ã+óÍéÅèØñúìs»¯þJŒÀ`dUžáér§“BŸ]mŒî÷¶ð;2„~»„CÐþÉKKÔ¯·8€ªÕô‘Úô晽vV]¸ÏœÄBXÿ©¾Bm×áäÚVB‰sä!º£N‹mq]D4C‡ê ÷ÉÇ,wÿêxª­¡'‘H¶,:ÙU_›¢ÔB˜U•ä ¾ŠÝòØìÔ1Å¡P-PUnÆ®gijb†ÁL²JÇ£M¦XÁn‹‘âÆ…8#Ö§Ç:.£cø«.†ßˆ=} N÷ÛWA” Î#릪Žß8—T‰ÚÞ]’˜pŠè¯!G=èJÉàüzNï­5Œ! “Ê7"øÚÔ#Oá{Uc®9ú­bxD˜m ƒ¤õÞýlÛrš…‹ÊÙŒñ!Qi?"è©m…¢ñ‡ödñŽÇ9îÓHöÕg!à‚q"ιñ¥ØÖåg z|·LÔ±;UÜ´ÏH_G1>[Jª;°j¯Ê;õÖÊ \äõ6^at Çݨndøª# çg—Çq6чI2ÝŸ'¯ÙJUÈ’±J;ØG]åÑ}£ßK•”zÐQ-[0³× °E‹î¥Àrvƒ²ó#ÆÞv¯Bòdò¿ Ä£_É'­ =y®Ä§©š/2ªäSRô½Cc9ö¶w—cI×E'¯î޲ÆEëòvÁ-ã‰8a/­[9¥„ägN0øCÑÁÑãZ ‚î7ðò£˜f®¦4QñG‰éĵAúAÐãr(VÆ9㙬Á$lLÈŽJPý‡¯¾2ÙIº¾nÀyÉbZ¬‹ŽÝbl×>EÓ»•Zÿ¢Û~Ìr‹2FOäíK2õ£˜©’1’Ï2ö5¾v:yÒs*Ô™ÝkgÃQÙp|'»S–&‚úâ2 &{/‘a;«Ñô\£¨ aêÃakÓ‰²ª‡iSv±Ý´’8¹B5Ø”gºU…p_¶¼|n¯ÆšªÉ±ÖQâ¥úÐtâð¯Ò$×̲´Âѹå-o¸cüXö;±Õ ¬ý¹tôË"¹žd¼ÒË,™Õ5KòMbîòÝw~º€²ÚKbôm¡Wª†gF¾šW>×6;0`Uñä»Ùâ$)¶òÌVþ|ü3+\Ô‹l –“_9Ã5aþr`ð¨Ru»›–ÊÞ¤ƒt÷òçÕ“®wtªG:|ÇD˜œF!×z¨"Òð®&ÔŸ ðš^‹%Yô¤1ìôŠ…`¼5 þ~íZC×F›ha¹$4±• ó5¾¹¹%èlú8ÜKGw.ªÓNƒ%bÒË6ðÏE,ÝgLRŠØlÜCY->w½€³õn[v&ú;¾‰žHNL÷ööîûÉòñT^RÁ31¶Ç‘æºÆ˜î„÷༠ñj$–I•q¸[îÚ„/~\% ÿÃ_¶Ñ»¶½©¾Éµ(¡'˲´ï`Ó ;f Ÿ±Ô IW¾c®Þ¤n+k–Ê«<ÛVrXÂÓÖ,Ž*ñåðPÉšªw )$4욃~/-¬³Ø3ü.jY…“Ÿ¥‰g$¥% ™¤…Õ¤5#¹—â¦ÈdB–„¿ž=†:ú’ªa©Ðø‘·oÇ⃀áu/XZUkB†!£\CU¥¹³Z/“jð³v5á€ôÔÛ<⽬øËê¶grµ*´B–•»”Ä”b.Ø¡><·;Ô ¯æl؇¼j×1œš+Á#°]ì,UQGb’íù—uŠ$E»’4÷¸EÖZ ü¶ìFœcãQ›úNÂ1cÈÁwˆ??ÌÏónwë3ÆÒÚP¿²ö#Ý»“ŒÑóª¹wëF‘oˆ‡ˆ~®ÓÜ+X/¡.âóðô€b>-~ôÎùÅ$Gö1e-y´m§TV“B©«…óéQâèsÙ–A7*s¥¿Æ8Ÿ¯ãâðmxLj¬ôèÅòyxJ5øÖ€O¬'ËÕ“˜nÅ~ Ó•ýÑ7øErµaÉG·¹†G9;ñõ·kÄ¡•¨bvǹrva„º=ÏMï Jß(ûÙÁ¶MÙBÿ”úi» ¹^FÞä5’˜Äí³m®Eû¤~׎ò×=ù‰è÷|oÊ{·! ¶H|o: oí¸z°'å+º’È“+y[šv28¬GqÂQÇC­ë”¶UHürª•ñt«½HÃ'’;ȽX”a›Ydz“ü}‰#æK\;DØxý\mý»#. ;ä<¨¹ÈÝó2޳Ž¥MJKNêYœ¬ ¹êÌ A[zõç¹îÙ†d(ØûæØ2Õ8¼|¨«GdúÖ˜.Þ”År«>MS<ÞBš€°F ž;·½{÷å˜l ÿ6ÓØê{¥TçÕÉÓ¾ƒ9Ýu&¡þ8Ãa|qâïeëBl1(²X®¢BsÈ?P rBË}Ô͉tf¿Öa½íAR8+ ªšæ:¾ôJÿÖÍ4`]/­2û w¼:\®Þ3ø;ËGTæ±J[bI¸ÓãÅm‚k£äR° œ÷Å:¿;nE’üð…‡Éd™²¤ У HÇyÑ!~FƒÅÆ)ôöÙ·¿endstream endobj 43 0 obj << /Annots [ 233 0 R 240 0 R 234 0 R 241 0 R 235 0 R 242 0 R 236 0 R ] /Contents 44 0 R /MediaBox [ 0 0 612 792 ] /Parent 285 0 R /Resources 286 0 R /Type /Page >> endobj 44 0 obj << /Filter /FlateDecode /Length 3081 >> stream xÚ•ÙvÚJò=_ÁÓDœc5Ú‘ü†1±Ið2†Ü;‹çœiDz,$ŽZŠ/÷a¾}ªºZ‘dlUUïµWáôÖ=§wóájñað) z K"/ê-^z®°aö¢$dQâö«Þ?-7èÿkñùƒcVÁ’°çº, C×8=ÛKX'4{ôš}×±Þ2±Z‹­È+…ËõA°Ê ã°Y{­Zl¤êÛnëpqQ¾¶á†¼"'HÕ»]QVbeöôÝ•ÅD ‡Á¾¡õÔž³8ˆbý¸ÄaNÀÑúȇ¾yÖ•þÿÐuEÏa¾6ÓÇ;Yâ%Í„[½Óþ»ÖLÃ3 O4|¯ÿßJÇi¡Ïü0j6{vBçúqê9nd£hÙ¸x6tA0AÏv}æ iî“=šLŸ&ד'ûëVº}Ûw}‹çÀ"ßOŽÎ;b¼Î†Íys}½ÅÑ…Ÿ:Y±$‰/9þz —ÚŽƒ3:y±¯«MQ*¢Vž¿6 ™PŠ>Hk]›ç¹ÁnžUÔ%x‰¾1¥=yðó$èæI‘‘rTd!dùh^  Ä–çh‡Æ$Ú ¹šT˜ ;‘ÊgÇñÒÖnC­Ð£ùtn¼¾Þ±Ux@æÓ›ö„˜‰ vW‡\nn:h>gHä,ÉM’ð-)ìdË5p¼*9èÊÆ!0k´&ÙìÙ¢¡ŽYH½—<Ì/ ‘H»ºÙžà—:OÏ‚S2™×ÐÄ‘ª”äÎp k61¼Â9s¹Þeh©ú¨d!Î;ÒÀG$ ã€# È9û'þ‡ŒâDšH%ò%O‰x|®Kˆ©Á~ë»^b5cs¾ÊÚ8ƒ­mÜA€Xë8ƒ˜ ÿ¾%ú^h}CæYMÊ…ãèÆñËî' ‚ »ƒ°¡#¢: …ëí³ ;8}?‚Aä¢1<®„ï'tŽE¹mæÝ È\VŠí-xØ 3ÿa‰Ù¦}aE”ëcI7Äy¸ÃPÑhÜ8Ô‘#‰Mè˜ï0¾ˆòDžþ/jü°Sž·|+³ ¾ÈÚ\3<âÓùNP×µ´›Ìs軇4ì¥j®Fqp!+ÈÌýÇe¡ÔÃ+÷CQ² ’áI@~ÿ(çT=ãÎçÜñJ¡ù¾J¥SH°=À/Y‘â±ðŒéÔÐ>ám˜ŽH×*ÒËZUD¤±æký×;òf0Öz3 À=òf@õÑ•‘Œ.hØ ¥êgUÓ0!øEKM:Yq¯è­*špÊÚdÜj]椓YfÈ·ì÷~âYͬyZTU›TŸLH\ -JˆW»"_‘å`Z¨s-Âk¶ùvYJ(eÃO˜t‰,b#À]2{X¡â€úö!Û÷£Ð2Js×èð]u“GÖ~Â…²u /eet¸0*ü&uº‹v¿F3ñƺÊúcik#?,£/iÒ<å™Ñï´È2¡Ã™j‚;x\-ªÃ#[QͦÓTÙ3!—¹üØÿ>ßöà4[Ç92§iþ‚žâžv”0bB£ñÀPçé&+”"â5_«ªÞdͱv—gýäŸe½5ºòì£.푯'>ö§b5–èv×j=,ˆVÛbèšt ÛB›!SüÀi(%VDÒ*‰D`Û–Hÿ.t´ARÅÝù¨ÇœÄ}Ÿ©ãZZÅ $n2R'd‰ó.Mç%0>7x¼ˆRT¼ 奸ÑhO¢ªâ¥zãPÂÿ0Wí²Šîú手-ð JYIÿãr~Ó¡ 3%Ä®E]*ª|&EPÎ+¥%ÑÔ¼@ÿ¬­·;$¼ñ‘í9YÖ­FŠ êþÚŽ¦ˆB·È=ϵ*C½Ú¦Ý%|É÷x2QÉ騜ÆÐ$Á ¥v ŒæQµ £sÍz"Ž‹• ꨩ¼5Êl CÂ%wuÖdì©ø|<ºkBLÂØsb6F½§“ÉÄ„k* µÅœÐ@j hâ úÊ£ä qîžÔÈž«SÏ ápÔ‚a—uO+ÀêOÌ$ÖJrbí;j¥4j–\„bBlÝÊ*Ýl¤ÑÁ}Tt¹©¥æ:ì[DzÜCš˜›-®„Î%\ò”Òxš(ƒÊÂMVì°;ÊΪÑÃGxL–™tž“_4²HÙÏû ]~«»Jæù’:WkSŽéŠÛ$W¢®}§:7<àMSŸÝX8 ìj®+@fŒ†Fé<¯°D- 6km—„¿nß-˜ÎÓɸKûâ(ôænFn“£öÌ!—E,öýäUþÏÅÝxòî2±‘eý eŠ.¥Ú€±ìó׺a_t7dvq§(Ö½ªKšB} æT0T„­“Ià4Ýži–2‚ÇàÅkªMpŠNí¬RÙôZ0s’‡®:qšq1ŠÐT†ÁIºþ˶Ÿ± ,1‹\û['4=ƒÌ„!B%éâ÷S œñ?ù:ç²fôPòðˆîèΠ:kE2”­ßñô•è[좠ÓDAG÷Rg£ûó‰‚Ù Z%Ú6MnjäwIG;áä÷cô¾c«Nê#– }ýã¡ï±aàöl?„¯QÈg/t±¡c”›~Ð5­¡Z¥¥ÜU=´ ·ùé­¸2ÛdƨÅ2ãËÌë|õ]ãi<¶¯þ®Ý‹}?¶ï¯M@g¦m•A–+qÙN‡Gxøkpܳ‡@9éå§íWò›À`†?ÿaGßì£Ë=Ô>CˆÖ)~=+_ à°ÓvýdñálVêÂendstream endobj 45 0 obj << /Type /ObjStm /Length 1702 /Filter /FlateDecode /N 97 /First 813 >> stream xœí™oo7Æßó)ü®AUf=þo„ ×jiQB%(ê‹ËÝærå²{ºÛòíûÌÞr!N“JE-x½ûÛñØžyl/ž•VÞ(”·ÊXVÞ)ÇVy¯œOÊ4žEñ72`ŸëhñD1sTQ£ðFÝ¢œb›³ ^±—zP=«§ˆzRœå}ØËx)je´Î*2J8İf…¦ ;¸àPfp^cÁ” \„çp=&”¨Ä¬Œ3V%Øs0ž`/à½{ Æ“UV»¤’SÖ˜¨`Â:mT Êz¼œ¢²}M %:—²”^e-%Æ€Q¹l¤Ä}+eVö"É^Ê r÷Å ,öpCb“ÆàáÇfƒQ@'mF÷^86Om•³Ḟƒ“¬1#­2æÃy–·".du²À˜3FÅEÃüà}e†å“ë’“©ƒå”†ål†åŽÊk#0B@G³òòŒ‹~¦+-³AD„ cȽ•~áMoÀY`ijÃ2šÇ,ƒÆ,{L%£âŒ±Daà€O>²D,G 7 ËI ËÉ Ë) ËÙ Ë9 ŒÐÓxÎèmИv>i™¢eÀÂØÈ8ãÍ`$BG³Àˆ}ëFˆ:íî=|¨ªz«Ð­TõúÍoâIl˜hI¦YÍfêwõèQO?VòûPU¿¨ªÉ´;YѨ=­‡{í¢®&Ý»áxx¦Tõ¤]ŒëšÖøË°_íõ^Wž© æêQ‡»èE !†ˆ2ºg%Ów#“F¨ƒ?\u½/?M›wŸüjš¶» Ç‡–·ðÚ`<%‘t$‰>L+eÌa‘×29ùóÜ éIòØûL"Ûæf v–uß1br÷û>?m_µ_é÷Õ/;`’¦Ìžœ(PJä“P²· ;|:žNV‹.™[¸d5ú¯E\=%H¸åH"ñÐhŠÈ€»‹ÂhQ»éû‘pÚ6Kj“j6ÕͲ^VGg»Íh·WŽtuóà0Ú'†2YQHM Z”Ñ\ÐûmÓõ=Ù‡`¿‰’}ÉÜ Ï+X?ðt]‘EO¥"î¾\´£ÃZœ©^öÑDý±“–_ÿrô‡8)¦ŸŸŠpŸ¿²=&!e½^Dí :v1$¿drA¤ß3q*…&¸» CÓ>ÓA“ÇRì³%¬WdƳã¶í0ˆD}›ÔL½žG²$˜È„¨Œ˜>,+7KŒÙ²›M—Ý´™ 9,Ù[¥GB:˜OnYHl þ†cÿ½ôH2ù†é!Ëõ–ô¸˜×åÇEx½øÚ”Éaçp ÌpØ@ØóÅ4Xn©}1-‹^*¦± '.¦ ¢ûBš±DÆr ¬‹im±„—Ò‹U×Ó_S»Ç«î¤]¨ˆÃ^Ÿwm3vµÚ<0š“6=Ð(¿×üÖßsòÎÙçí¢SL·¬Ï> —½­íø:3ȃñj„ÄÝA‚Óñ¢®Oê9MÃùÉt´œ¶4Ó¤ÈÓÍ-3Ø´„í3Ez5ífõú ؼ#ᆳe}Þ¿Ãn1ýøIØv¡ãøÕ§úËa×Õ‹¦Oq«'Ã1´²Ï¿½vÖ.çÃ’P¿‡ø<}"·û¾í7é»r1H¼ÝÐïíépÚl”õýU³·¼‘ˆM›öD Öê²ñãŸõØ`c¸+§0¨Ý®ÿV–ÓSﱜœþõ.ózˆó72¼àüÍŒoŸuq“urä½#—¹g½+)z7µ´UÇ9 …Å)CZ]ö¸Y–[”)áŒmFÖ_õ÷|@~Æíê`ØLê sþsAà·«CÔØû^ø;='9/9ä{2غ€’å»Πúÿ`éF9÷òu»Â+§üš­ßx³]>`ðå æJÚ%˜.§±¹ÈÅ´5$³ i6øÒ÷¢+iÈ‚bZ6\Nk2®”öÙ‰Åtr„cV)Y[L‡D6”Óšì¥o@WÒÞ|t-¤±…†”Ò6»¤hWÒ&‘çrÇzWL³!‹ií(èRÚå@aëgˆ­tJB9­¡×¥ á"DÑÓëŽ/¦¡>që—™­4ÔGô¸”†z»bê“b1 õÉÅë >ò ¶†údÈx)]F.¥m¶¤M1°øb:Æþûx!2Éœ”ÒLò …´·Ä±˜–]‹.¦­|v¥´É$K})}Xþ+ý'T&Â=endstream endobj 46 0 obj << /Type /ObjStm /Length 2206 /Filter /FlateDecode /N 95 /First 840 >> stream xœíZ[sÛÆ~ï¯Ø·(Óáb÷ì=“ÉŒ-EާMã‘Ý™¤™>@$$¡¥EÖK{¾³$eK‚LPt/I¥aüpöì¹,´B m“°^h§D"\´Ð&âŠq´¸A(g†9aÉáê… Œ "<㢈!àš„V ôxHüóø•4ñ I<ók(€=0XA{ülõ¼³ãùç„ß=‰‰1IR ¢¤,žƒ‚iƒ'¸Õàv‰@08 ƒ=6B 0y°OV3”-3AÙ)€#(;Ee—QòÖd¡ å` Ê!2”#1”c`0(' påÄ»»Fi€!l£ =½­Æn kC'' %{a, ¯ ¿1°üTÂB$Â$••fÍ€)à°0¢6‹Í GžÁN8¯X~P_2üTžXZ* ïxO* 4 Ra±ØõI³ŒI„-X X´Pp0Ä”Fà)Xü…`s "8¬L¤0€…ô"ëJoYi ìYZÊ „(ÖrâE!â¨X£Ë«c“ÑÄ•©F‹ÛÌ\´¼/C":¬LÆ`±lª v"¦l^$6A"É$ÆD‘¬&aÀÆ$9ƒÉˆ„a@"ô‡¯¿Å‘øYÀ:”8Å?ý ÖleÀb°eiágÍÕ|.þ.¾ùæ“hëIè{Ú‘“ ÚxˆÓІÀ Ük$'ÑHØÎXN¢’FÝG¿«g¾;kÛ¾iûJjý¥(ÞŠâUû®L/ÛnVu «8áÙ⧘|'Š×¢8©¦=îR XÍ o´L0t„™ 5otðàß^ö7‹J®›Šâ]¿h°ö¦æË~^/ûº9—ZI{0f½‘ Ždƒ’ І(# ÙF0 +Ùƒ1+÷’´è8nB÷Ù¥S’&fó–ÕvclZCƒå²^ŽâHežîs„/9ÞZ­e@ÈA Ç•#—–Üvà,üõäõ-`Ú×m³ºupÑ÷‹¯ŠbÚUe_ÿRMÛË˶Yʶ;/æõ´j–Õ²8½™4ÓI3+¬TÅ—[6¢ŠV‘ 0¾dDT°ZɈÐÇ&Šø1jÇmÓçè‘eV~uÌ!Ê«Í$rÚYOrÆYÁ˜Ý7];}[13Å›£c,Q½ïïú*݉&ûjPNª¡0@AÃ/9KC³L¬Ýж@s–´ðÜð¥‡8Q’ì#!æ¬>¿ê*öä}ÜÅż[äCÉ ¼“žcôR¥]ÌGQoŸàb,!Ês• ‰å’Ôœ} …ҳÌsL£ÞÁ{îšá﹆e[TÞÁn‹G¢-4ìÇ£U¶É‘hC°ÂÑhBvCEË Z#FÄÑh%W„cÑJÒ`ù4„FÑ+Q‰EG‹¢e4‘ИÑh%ÁcÑ(ŸÒh´C”¥­qsƒF´µn4Ú H|eEÊ=­P¦÷ðhðíÆ¢qMÛ=í6O=ÂN¶å©ÁRBëò#4¨\öp{`ЦmËjv‚Æ™Âr#*²`Ø&—ÏFÆjÀÿ·ò‰4QüøÃé?˜/¦öú-üí#¨|{jìAqßš^\õm'`‡YàmsTö•88úŠ”Ž ö­E¥ÿ¨ôJ}±Áñ37ß¾_´]/´t¸ý§êæ*XfZß·³md ÙÕ;€fåYWUÕBžwå⢞.ëV.fgò'êÕú­W‚r²¼x¡wu?¯V#ÀÕ b/çËj³¿ï˾«ßßô„_ÆàVò›²ï«®ÉÊ%½(g蔲ÛyÛ½]”S¨ý¨úfwòê%ßÎ;üYLÐ %´ú0àwUž51AE•|n=ŽÚ˲nÖˆùñU³2r&ÿ²½j2kþÃÕã/ =øm3mgÕíô¦ÚÌì›óe¶ï˜ àþ”ÍyuÛSéõ*lžëý¯ÅÁwVf¿Ó¿Y¢Ü½¡ïE'ŽØÇý/O#ŒÖ? twäœàþÏÝK R)$‰ y$?/¬"Œ‘8’y–æÓü]k11h>!Aöwžj­å³@Ÿ"Pçr1°ÉH(dž3Ò~þî"Š]öwÈ$ð±Ežr oåò,Ð-.O\¶B è-ò“Ë3x¶ƒ8Ý'EøDñ}±ªÌ_RèÙ8¨­´ïó9 êüsÐ\ã#¡ÐGþPô©ío$ýÜ~”Ç•¿ÿ¨3„« …M¨¥ü£G*÷ öyÁHh¨x’|¼Æ}¡áSÃ`Ñ`ì¬~w "¿b´é ÿ#¯?²‚íÍâð‡— >Þ™ð½~Cü:Æ ¾`Bk’|x:­¬ti,šƒ‰§¡cƒAtŒÒ»ñh„ð8`Az4ÚCîƒÇƒht›!ŒF[ä1u=t¶°Ï‡F°aW·|‚ÊIø-kþ|@j¿Ói˜êËÓ9¿¬ÚïŒ2åoLÖůtÃS8ú#þT"®_ó9Ñî™FÆŸ] ‡¾0xü°ðÚ'‰°c]T|<ú¬p”ž—Pô¢j0ÍYuZ—MVó¿æ§]Õôe±º7)gådÑBù7ò¢¿œï®oc8ˆ¨ÒèÕÑ¿‹Q8ر¡Ï|Lw}}-Áp=Í[aÖ»jÙ^uS˜mß¶óåd^ŸveWcþ„x„c„Ó«SÐÛ­æô9]UÓ.àn™w 7,Ê®¯§óªÐ± bÚÖ *œ êµË '+$.gýuÙUOØ®‡1°YËqe½9~ñ²Û'$¿ùðòðc‹ÏwxäWþfm$¥¥zð Òÿ’c/2¹•±'Íä±[kø5ôD;}ÊóßöãÛ­ ã üÙ ¬u(åÙß¶o6gˆ_˜¢‚QhƒX_0bþ sëæ~ÜWªÈendstream endobj 47 0 obj << /Filter /FlateDecode /Length1 1606 /Length2 8510 /Length3 0 /Length 9330 >> stream xÚ­veTœ[“5îà»»»%¸k &44 4»&Á]Ü‚‚{p‡ ÁÜ]ÀGî™wÖýæ×Ìû£×zJή]µëœÕLtÚz\r¶ÎÖ eg(œ‹›W  v²vwÓp†ªsÉ;ClON!,&&;Cp8Àd PÙøù|bbbXLgoøµ=Àj kÄÆÁÁù/ÏŸ€µ÷FžNº_CÌO ˆ³‹ ‚ø_Ôp{À ´´MÔ4U¬*šBÚîÖ° @l‚ºØvÎ0äo`ã µÿiÍû KÎ ¸¹€lÀOÇ@^6 —?!N€ ævs{ú€Ý¯a@(üipgjq·ýCàÉoçü!˜óS†ÓSì LÛÙ îf»ÀOUµ•ÿæ ·ÂÿÔv?…ÎvO™¶Î6îZú+öó…ÁP7äÿS˰»¹@€ÞOµŸÀ\`à¿h¸»¡¯ÿÅ€½Âl! 7·'˜'ì?ÓùWŸ€ÿÖ=ÐÅâý×i翲þ‹î‚Øqcññ?Õ´?Õ~ †bñüY5¨3€÷o¿­»ËÆ<@°¿ÄúggØžHm¡o€-È‹GÓþTÀú¿S™ûß'ò¿Aâ‹ÀÿyÿoâþS£ÿv‰ÿ¯÷ùŸÐÊîˆ&Ðéiþ~`O/Œ3@ðçùÿrN`ˆ÷ÿýÏD#Ðß ÿ'58ði rÐ×ORðróþí»)ƒ½@¶Ú`¸=ÀyšÑ_~¨-CAOZþ5F/ï?búö`G蟡 ýAmÿÉüIž¿xóhêªjšrüó5ý+KûIu¸¾·Ë±ÿèCÃÙö¿Œ?òòÎ^_.A¿ˆ(@X” *Âçÿ?Tû †ï_¶{ÌžZæåû«ñÿøý˲øŒÔÆÙöÏ–èÁPÛ§Åú/ÇŸ°; ö¤ç_wý©áÿ´ÿZqÈ dƒµ0ël#æþ!þ™,§TѬ»“¹?Üåc­~a~P¥sG`úÛU±r«ûªpâÍÞßö]~o¾`ßì$…°t¤‚Žó¨üغò ¿3·Špl…ð¼úˆ›q`í{2£¾‚b*Ìk¸µ6ª£ûªøúk« ãä'[ƒG~ ãµ ^€MZMܳ6‚:¢ÏûÌI»?¯Yz‡úû:ÎP»6)9²ã0™$€d)ûtÉpo+Øe­Íê/w¼ ö/oýˆí¾BbqÔpï÷šœ0%m­ˆ Œ//0ŽËin5âíÊdývÝÕóZMÏ¥jѓק…£µòÔGG~T!rVIÎY¾HæE$vu ¾ÐÃ]6:å?|¬‡žcïùx kâ³×_ ¿ íb °&¬lÕ_H-ð¤@Vª>ƒê Hz8îÝ‹Föcx_úâÂ0ß[9ͧÓrM^$ï::¤†ÜoŽð ¸ÚÄ3h‘] ·ƒ([7MvÃÛ)ÈžÃsè#€²Ù‹ÍÑsº|œ6(J9`Ïé$´ þjo­­ü€è8 9UD…DÖü<+gí¯ë5šx.ï•B¥É1§ w;4øë.‡pѳûkN¨EÂ5l"<ýöpÈp:î—”+Þex¼¾ ŠV«ße¹¸^À:„¹”‰ZiÂùʽ¨¹phwrÿëué껼‘Ô¢rïbæTœ\òKýâ ¬2•²¥žh(- 7qùhâŠ}PºvU•zù*”¯]ãß9hÖ $¦_‘òpõOž3&šâÔ7…Ÿü a4Dm¥AÑ¿¸„é¢.Ð[þâÿÐ>#Æ3:Sá€µŽšàéÀÓc"—÷FòDPÿ&¯.Ñg¹ëxÜe®m£žü‘‘Väawâ,ÚG 3ä±_wz…•FÌ&à÷ jͶÇ6_¼BRÈäV2 Hé–5ûD 1 G£¥X¨‰ qè²æ0IÂìt¸]†Ác#¶ª‘›ñ}Í2ßN)((à£ÅàËÄh#ëâû`@âúCì:fêëëþ¡D)>Ö·»  ifÒá÷ýFŒ«›æSbà“lQßÚ/Ö:]/÷Û$Ywè º9sºS…»›”Ûô_·6¨îœM4øT·½É±ð+ñ2ºÌM˜ð0sal.õV˜~%uækÀÒÑ*F? Ó°c§f*?,D„³´ˆS}}_,"¢ê‘x½`ƳJ )Es¹7b"vwäRsÍþ§·y„t·¢’Ìï¿m_Ûòoû޾ɫè~#’2ªò>)@uH;ˆs Fs/QÅwq7LËC¨KyvF÷ƒžÉ_ç¸ðš.4õʈÔ8(õ>&©aJHw‚[ª;uÛòÞ+èçñ+„Bªƒë,å³ßvd€ö×mdL´{œÐj]ŠLNFˆcë€÷ÍK§»Õm7+ ºò&ì4I€bí©á3¨O¿> û¸|FprΔU‰¡¸qÅl BzÿAõ'Nܤ %þ5Æ>—vIIy¦]ÍÐîf›~»–‹ÛÖ’²>“à9Óìˆýé³®Ådî¤ê>ÀÏ©Húm¤òB–-šš%ÁÈI¦ ¥ öX±õÙ§ž'ôÓn EÉìjûOñÎÁGÌwt”OiÏý.Õ:É’é=‹°»¢’ŽÕ#ðÑÑ•[?ëà”ÐÆ¨$õ4üå‰_Ók¸û^V,ªEíV_án”l¿ëZÚSûyïMìøzýv¤Ã¯us´bÙ3Çþ<ÿ¹XqÔ®ƒ—Ä·Õ$³÷«ÝøL¥"ÙbŒE¿Cå8з‰{½£8j–²Hß þbÒ„Õ~ÕÛBéï¨à8¶9ëµõ&´à‹)TÑvhëéW;¦‹V—wÚ4&”ëÑW,Z£ò þnË$ü Å»œÃ_4P’Á³€ì*aÓMWºÖôd~´Dx9çø6YÿH1Zjéÿ°2;€ð£)KgÃæ%ÀŠ˜n¹œdÏíðú×)®K4Z7µŽÖˆVsál{uJùÞEå®pRIþÈð™»ËÓ× Æ·±¶é_;-Á1x®{?ž‘€Vçâbûøï*- Ywƒ²PçÜ×F ·t®ÒÞãˆ>¡C²Ìæäƒ4W¢~11'‰“>úqãâ _Q`¼VGÔ±SíÔ:Îê¼>§  ß¸Ô„Î<y«î9wuÄÝoú†8Þr¶Ý3ǃ·Åã§iÑ+Œ²‹j:H¡¯40†é•ÅÜ _†-)Íäfa<¬ð¥y;04³ÐèæoÑ‘’ëŸÅI\vS?Zœ©à5 [ Ðc^´BܸÉIXîm>»WúT –·âŒ,ðö‘µø!©ï$ìíÓÆÕÒAŽ—¨»ué4“µÞnÄ3¬w*—D.<˜ií.#Î_Ó>È|ìáÐ/b‰m˜ò!SÒµJ“YÓ}¼|ÔØå0È“{Fq_>}§µÝÒ6d4>A£â‹ÃØü=5Oèc úA*þ£(´<ˆ¦Ó¾4•åÓ¼@[ï= Uî™\3úI4cy‚QkÞ¢=äŠ;gÑ/û~Ùé‡ ã»éɳž·c"ƒá²èqù¡Å÷¦:;WÈá½yÊþ¦„åa­Á%Ã~é̯¾ÇŒ—2â®8F^÷HžÓ˜D¹µëq].TµÉ&xUZ‡í™Àw *Êô… 5·N¼Ü7 ’Ž 8¸„·–‘?adÒï-Ùk®9åÌ–ñµXß”ª-oŸÇ½öå`O‹~qý’™I¼£˜3pMH¡MÔçt¦c¶1³PÁ÷™ÏjRÐ3ÃSЬNˆÖ(0@Ã- kG–•Çæú@ðÕÔlÎjº„Â0¼•nãvÖœe†äßœ+È{ø’“ü¶ýËwÛÓõ0‹(iÞqôæî‚BôVÈ"p7#5ÿ˜:ŠL'‘Ëý——EoaxÖ-‹ÞS7C‡l,i×þW‘\®Ùþbbǹ èëT>ÁYqKh1_¥*á|…:ÔŒÔcYFü?KÞU½—´‘%š·šÄ»?ÞÒ—ž)5° †P±°Ôa^– T²µ™£qœ194&6¦“óËg¥²oQÅãÇÞ#ƒoé‡mõÛõ÷¹’q£óTº“Ö'û?)j˜‰é~-µÉÆ/¥>çvвËÏRFÈl2Ð%¶LÚ7Ðk«ñPX-¸+©¸ðƒ}þ%ÕNVÖÑ<Ÿ5t¿æ¾J™1NR#ML“n0j ”­wT¥q6Tñ1NM¤Øå#ÆÓŒØ%P¡ö)ÎY ßûtœg ´&!òÐ#uQ#3ÐqT°ãOîî—G$P`ßoG£Ô4åkb¨+ãP3Y+€±¾ÀxÇ|Hd(Œi4‘¿s%m\ÌtŒ¬$LxÐǼå<    Ö•ÐNe±˜iåŸÉž©Jl±°,N[#hcÄ™GË ›èêÐ¥–ÓH!Ë«¨W”¬HYë⺸%aD‹>¶’öåó¸¯ibŽÖ•êð ”UÎ _ZØ’=“‡¡¨­?ë‹'^%ð™–ÈX'è‹?“fœ4Ù »úr¬®ç"b£m…¶ºl(T½ö°‚—n³#H·ØKå—ˆID:ˆðLK‘t¶Æl^ÈŽˆWôPQ+û¿»’LÝ‹]®EnŽGOídÕ4:ªD.£ÖÒñçÎ`*D'Öûvlþ­&Ʀ°<1⛹bНÎ;G|¥;®LW‰°âê,%¨ü²Ž±¿½$@«ê<ª"õwøÜÕØw »»¸¶eï›î¡%>ª`lX)iâó9¼øîëÅÉ)%–Übcê‘– 2 ½4ÿqýg2¯…hxÈ­OÖ¼p Z™=Ry—ÑXÿÅÙÐ9£«¯ú`+üØ!X·€0ÍK¡,—‹CljY®_£ù^›çµ¸u`­ß—ýybøJ÷Æ ë‚OI¦ƒÎõ™üBZîyK–µ¯¡EpÝ3j€¤nï’Q¡£©v/ 9§U‘aËä•ó/Ù(È(ƒôbnO\ÄyÁ ASˆ#~ñféžüE#’ÝQþóþ)+‡—þsã]ëõfëQióIœÑ‘pÌž‚PøžuN3ú:‹}4mJü>Ñ÷ó }ްs5åû,ˉ¾uYiÁ˜¡/y›_†kïn_,l“ÔTl$ãCÊ­$\ÝL]œî Š‘ʱiìqrhsø©-£Y‚|ª9MïïN¦ø‰t$¿Yg÷s!·µzÒbUö½jÉW'õÅnÜ©t4-°8ô™u1eé-© l0XaX`¹BZ {’ˆõ@µ©é&R/eQ‘:wLÅâº#¥òÝNŽÇÜc‘˜è½VÜeògÈËì­Ùð»S&‘~tA›|éÃCÕQÒ= a9à€“ ÅŸvú¾þ»ƒäߎ x£dÌèkRVŸ]mwf$„H /ƒ®Ü~tOÌÆöJ~”ÀFªšŒhh«3s;Œ4Ö †ZÇ7L¸X¼j<ˆQ0Åþ”ò1?{ˆæ—¦Vbþ×o©ޱ™] ÊdÚ×hßþð7žuÜd…¸_¢kÁ‡ó—ÌKÈý [«ÃIúNÞ€IE8“¹B 1UrÓ.ƒÃr»ÃYtSÚU¸Å}Q"¡Ùu_®s캣ìË9ÝB¼Ñ–5dCJêÑ¿»l„´:11‹nª¯•"‘ëêSHy4_¼™#çUº:à¯p‹ÅNâ¶|?Ì]«Ó`¬k¡:³CEŠŒ1©Q¯›mu%§²gòP Gª1Qs˜º ÜšËL’Ÿ)+<ÑW•#Îa¤†œÆë5ºðXhO"g(½Ä(Z 5Ý;O¸NÊþd¹˜ˆOòŒ++ #*Æ*³"äòõ-µF¦)ÙÜ×á ÊoÉÜ÷0|ká]ÕÆ­Òå+¸UgܺCíö:ìTq³Çí§£EÚa©‡§!mj gfyb¤r‚S8JˆÑòöY]›Êi•¦J,²̦¬’_˜ˆ±yÒ®Jf³ ¼“ö³øÓ¦ƒBdÃõ"ñ“Åêw[n×O1Ï`MÚÆGÁWh¾ÏŒ6Õ…=©)Ók"YO‚PÃR8ÀáL@@[T85:öàEN%…ÙÕXº|ÌNô˜yßÐ>拘Ք! Ýúy´ÝÜ$çš‹õ]k5g‹6S|…ZßO¸µ(‘´gJT×§ùÂ@®òݤç1yúkßÐÊЈGDÏ^>`DSP×zr}݈‘U‰úôÆN7X±ƒ¡òëdNlbãúˆft;%Í©ÁRcbvªÝ•zºRÅërªþ„_=,;y/'3.ÚkÔ¿ª}üuC+ÝxÆíæIñ (Š.ßÐŽ³>¶·¤*ímÑÏåxÕx¤vY}’C÷ð^‡È7íÃ[Â`[Îêk™Ò‹ ¤tðzÙèàH#²¹´Æ„ª î-ŠY¨y™œÇ;Ý5C G¤'£n–ö~È6ÈÇ(6¢à˹xâĆ…&þÏCúų™mÍos¿J\ˆ²1 öut…{~b‘ÞK0¡µdKV(¥çÒ4G!ÃNHÓ?šbo³o=æ{¢ŠFcA ÂV‡a‡²£z5£’¬‚ȧ‹Õù jGs)´šŠ^Ù…v­`‰Â€¯\}2eK9£?x„è^Ä,Vf’ÐNýÇÛxëéÆ sUÍp®• b:5¦Ü)‹+8PÙfiÁ†Çò ¨ì™–fYÈ&>=ÕQ¨îw´W›¸ñüoñÅ+Ð 3åØA´ïN:[w>ó*^íœÒ|9"JØÈqÓ ÿCŠ…ûâf|`3ç¥Cª²‹Ýû2›7ëi8°ïU7æúŽû™ªE#ƒmš464\/ïJù£í}ñb‡ü:ÚÌR®0ÒÙ`žœ–FPù¦“QKÖ7Ë= ÍNî,ªÖT¿šTªÊºÝ2äŸwÀwÎg†eÁ…4V¢Šó„6gfxš½ÅðÇžUÑ<á&GÿÑÜ9mqtm$ùJV³jü2°gÙ ºvyv¯ )B:†jw¨*W)|¥oÞâß´—oòîG÷qÝÚzµÖF½"wÈcN¶ü»Â8S_5ö:±­ x´ïœyät/«¸Š£ú¸qò3²=B’— ¯´\}ëx_×`i®ÜñÏ´Tá‹cŸû½‹kÕKöˆÓxôAо,¿":ðåkb¼üòì6›§Cñ1Ð…¤/]Ïr—LJC´2S©•ªp¾®±®eïø4åÝÃ'9iáE|˜,b¶J ¦ —ìHv|¯¸MË´ÒÉ©þàÞÏeÍ8äé¿Y"1…¸tÒ…+…_†H(醇OEħH³ÚG×$ >VÍßò☵“"îËZõö\K@Vñy탡4^ëµâ¡Õ¦”å ÁôÜçô~mT £|Ô‡îû ö î ß1õ)®Ìö¸OÁ×›xv%ÌN±ÄÚø‹DωöÚÀÒädše³×ÂlÍlµ¤§”šBý§ŸeŒ–~‰ÃadSû¾0EÍ ïÐÏ~ŸÐd›5e>7»…OÅéÌAAÙ²™ñŒ?ƒ?ªár;äÇŒ\´ì}: :( ¯a½Š7)»Ë7ò‚‡ðL @{e:BŠÖÎæx·åuY=Hã0b©ÎâJR–¸x}·Ý—ç}â»Çnãêz‘ð°áuýuŽìEF–lœ¯¨Žø¡„ŒËó0qjí{¹šâ¶¸zÓû¿ºÜÓï§wÄ¢®¾6õ˜ÔÇ…»›´†¨(œ¹x‘™•éW‘Bñ+,bw=š™CKÓîxÞÛY W ›,gñÓ=è¸`"->§(Ý—›5Ä’?"BÖp?‰læ>¶H”šGê#ì|ÐB\í]ýAkiä²sC—²¶6–è†<=O0“ð2ò¶ÀWáU“™ôùÚ÷2&‚PŸ¶r “ 6Ÿ«ß/æ¿ú.´NÒ&µº¤D¿«š´(ñÆê¹·øöiî¹ÑäÀi*3áAˉ8„;E®‘—£¸ï±ÍéS£gÑÁN¨œ¿÷FçÌóyº­OaÕA¶_âü–é§JGí›[¹éCˆÒ'ÚZ÷a‡ŸçÒñ-·rÁô ŸÆ&FÞ§òäÉ¢^1:¤™\ Pž½´M¶Àý.¯ƒWûÝ®à†jRÄÚ?R¶œÕêØ¿ü©Yä¦î“h±j;ü“³ôÔ3î‹.ã„ÇÆ°R£¦ª(‹p†‰²©L".S‡ÝÜë "rîlCJ?oƒê¤°±e=qˆbân¢æ·zùØÐ}gY€SÜʰ^lÔø­6~”zäEò]Ï®×õÁ`­÷¶ÿa+4-J¹è6á:öÿõ¶PƒÎõwóÞ²T„d ¬¬Ud]rË$7¸frækó&þ¯þvžPä«È9«ÅvˆP¥9!úœ›š¹ŠB[1â¢kcÙ˜â‚ü½þüŒI¼šHßNb¶AUê™3ãòn@„ÓM†É7*Û¼í´úÕ®BwÅê™×ßÀlE:MA8>¯H€ªï>GÇc Y$pæL3*=]wV™áÒŠ(7I¤ v’T²«ö¢^œy -y¹Ã!ö‰¸é­ «ö9Úf?_% ¬2bàëMTðzËî¸ÛÕ,öBoJìô!ÕÁ~ KŒJGíã×ÊlŠ4; ~GŒJ‘}î€àókk&NtÌ{Î(úèCþ¾~ù¼‚wÊXœDïêöôÎÌ~HT…{™ÅªV^móÇçÖ¾U«¤“´@tu}C½º’¶Ûo¿ Ää•›YšØ|UÞ÷ÚiÅ0©ýŸ-a“9é!øÒ}£œ½>j}ÑÂÎñ2®~ïE\ã]–h1ö‡ñ:9Px¼wìƒ~#.øžÔ{Ðí€rÇ_. ?Dø‚“×[Xvóø¯ìxÒÚ»e¼½o¾©ÒžÖ]<ÐR'Ë#$Sž[GLƒëKK4!y¯Ž7Øx`%ƒ$B"_R8lŒù¶Šd8ÒÆÁè²á:6û~z˜"ÎÕ9dI)+vÊ|Ã7¶H›}Ý$Ö¤¾) úS³+·b³#ŒÚÝ %ܼ‚5Ú!Þ"˜.ûÛk®3ÍQûaŸm­B(…óH¤Ê|”µä»2ŒJc£Þ‘¿ÐG½G[ y#(Ûk‹Ê«Å5àÕÓ0€ ¾Ëd$ÒÕ3 ƒ·P0P‡·÷÷’Oõ˜-¼ /‚ö$6—q¹ýø2yÏÞî]•2ºPE  ø K-yP§R¦èj¼KlLi¾»¨‡ ð·¨­Š¾™gQ”é”*±(¼?®˜L:h\è|Y†œJprBt^X»¡¦>Ø‘¤Ýºô#ê§zˆrLSYPÍ!GBXÌÉp¤[²f9Ÿ´¹Ô…Ó)F×jD¯ù86©Œ¤îÏñýw¾C»OS{»[ˆœ±:|äÖuƒÅ Eó–^ÉÉ1õÇ¡ïEl’½ˆb»H”¢f³k¤8…D'ÉÉÇôyUGQÏOÙš›”Z\h Ë0Yê›Á7‹Ô¦ÁQÆ];ì>ƒn1s1¹Ñ„Ÿz ôŸ +×!DÛ|?mÇJþ”r›Ñy´ê—ÆÑ•LØ+€àâ7Ó.#,ˆÕñü0†ž×&áÚuÙ÷cúóþ–{gu¯ÀŠ^®¼¡[­j¬„Ö=;%ŽÙé³FDÅÁM‡5Ñ{È~•ç€ …Ì‚”ö•ÙÚwÂlb½yŒQ™_9Æ?«¢ÓÑaZ©ò»0"7nüíÙnåиäÌÔ¯\ND¢Ó¤–¼ýü¦ _%r[Ù2_pÏωÇÞst@½G#ÌÞ„ç:^~îÞ“ÞP²ÔÑ&¥ÜI;!'Œ•Ù«t³»©ƒæôS›R¤z£^ÿXÙ磙<çµ¼‘Ç9þy<‡Z‰Ãâ#ж9AùuUmÊÊ£V„I·Mg¶ymÉÈϾ¢ïܰQšoCû9Y/•ø²CË÷,…ªù7×z‰§^x>kµz]±p.»kYñb®Þ³­Ñî Oµc¯ÂÐë jZüµÇÑg½nM@Ë>:Zâà ]z·tž;fŒSÿÉ0&:ÚÙ™cM ‡õ¡Ü©Á^RíD]E9ñƒ?]>h5AÉOd¶"”¼ÙóA§®gÞ;%e?8±j¡&º¿7õ‰tDÔ‘’µŠßÙ£ÎZÓTBzùëvš×Vö»Žå‘FUœßg`mcÆÖ÷EÕjá7´as4i{c/çÝ¡g̢ ҡ ™q5§µæe^åx5@¬³5ohn‰¥¾ˆÝ5Œ˜x‹PakðλžEDîöCŒÂ/`"éW6Ìzý®ó–“ɦòY(œ¦çéIñ²Cä6%íÂH«—£ËBB,JÁPÓðd[AØÊÛ~srêÛZ|l-¸5¦SÇìüîäkåkkiA“ ñÝøÓq̶Ùq»-8šæ^ŠxWرEXVóä¾H1I™¯AIõZ÷ly"ËìDޝ6ÞÊ<ÖÍ3Â9]ìzÍç·CobxÒ&6ö”&š#jıømô¨‡~Ñ¥¥ü¢²F_Þex¸nLAH/`ÁÏôˆ øvZTÑŽŒ0¾²zÆQ ¬9ÃRq˜ÈbÂù=䓜@ûQÞÜOŽ%g¶ $÷­Ü‘ýÅ«öÍñ¾Û ¾_̃,ëI±6ñ¥º«û®T%‡} wÛ^¿•ÂPUÅKÂCfœŠÌžs?WT×bÿðyšÑ•*¤ÝÛbVÇ›M–@SÖI¹¢s¦Ë„VõŠY‚E\-ׇjªÇ²Ö@æ Ûº •ÂÕœ9ó¯'ÉÆŽZ>"{Øõt ¶èpõ.fœS•@ѽӕG1ñܹÆ:†)6ænô_Ÿ{QUfÎMrDmá˜øÖ¼Š^Æ<2lö£H÷¸¾/×<ÎV4tágDJçùHLùrÌ~Ö—M·­Þ_Mî¼Ô‚Øh¶aÉ<éØstø{…¦“óƒãºüÚ*Uÿ­®,KÇK÷Ñ–RÚ·þœ±géiÓ0$2Ü5_ÞÏ«,é É:“Ì ÔŽÅLòá¾Ï'ªvòÏðÆ£'‚l™HQÙœÄNjH½ñq"‚UR5‹)ˆvwX;u®ÞÇ=(2eb}å®r‘sÕ¥¯ìÕw°j¦çï¹°¾´,Wƒî‰Q&Dm.ÄNW¾¹¾­b:öË~뼉!Ÿ•⾩òyµ(8k§z»þÙ/êùTâ’‚/õC;J…ÍWIÊä^´ñ)¶@¿P†ïŸ»L¼sIÇ *«{®óÏ›8oôª µËrÂcy#æhL§cÄ Îæœ–$~¿2]Äâ éªmSMI%Îj…ò^Ü6 Ëkl#+YöZ†ÄÎ\Ó ¢r,Õ°{ë©0¸ªüè|/8KW¡Óêø‘àÝb~<».Ê䮚àù/QœM\òÓƒU$>ÌÎcæV#SÞg¯ç‡{+àš¾œï6¤—›¼e(ïò¦ð‰¾K§ eb3ˆ/ndAKoæ®Ø&¢]S;QÓüt¶0ƒ YmÒ˜ ^+Æà$U”eý´ê¶ M5Lÿ|ß”rÖ£ÚÀᩃ໰‘cÊ(ú5GXTj]²±j&ÑYP’/ÃàÏ|Ù›¼€31°3îj›ÐѨ}ßá[qIU?)£`}8šXwöÁá’Úÿ|©Ñendstream endobj 48 0 obj << /Filter /FlateDecode /Length1 1630 /Length2 10778 /Length3 0 /Length 11621 >> stream xÚ­weTœë’5î‚{Cp îîîîÚ¸Ó8w‡Á=¸[pww—àÜåãœ;wî¬ûͯ™ùѽާöS»d×[½šœDQ…^ÈÔÞ(no¢gúÊÈ ·´5vq–³·“¥Wš»(ÛX>6rr' ÈÒÞNÔähM¢@33€‰‹‹  bïàádinP©)kPÓÒÒýËò×€±Ç?‘OgKs;Åǃ+ÐÆÞÁhú ø;ª`fiˆ((jIÉK¨$äÕ@; “‘ @Ñ壀¬¥ ÐÎH 0³wØüã0±·3µü«4ç¯\BÎ#€³ÐÄòà èntø ¢8l-?ž–Îs'#;ÐG@öK;Ó¿ø°›Ùÿƒ“ýÇ ÛìƒLÑÞälâdé|DUÿGž #Ð_±-?`€½ÙÇMS{—¿Júû ù@AF–vÎÐôW,c ÀÔÒÙÁÆÈã#ö™ƒ“åßi¸8[Ú™ÿ+:€ÐÜÈÉÔèìüAóÁýWwþU'à¿Toäà`ãñ··ýß·þ3K3ÐÆì+óGLÐGlsK;†¿†EÊÎÌÀÄø»©‹Ã?1W Óß ¢úkf¨?’02µ·³ñ˜ÍäíA!Tÿ3•¿þ߉ü ñÿ‰Àÿ'òþïÄýwþËKü¿}ŸÿZÜÅÆFÞÈöcþ±d[Æ økÏØ9þÚ5Ž.ÀÿÏÍÈÖÒÆã¿qü÷‹À$û|ÿKŒ>š"dgþ! =óWƘ-Å-Ý¦Š–  €™‘ÍGÏþ¶«Ù™l,í€ÚþÝÖ'FÆÃT-,M¬íþíÐÎôßÓÿëï䤥d´4hÿ» û÷MÅI©z8ÿFCÎÞô?ñ Û»¼èÙ™ôÌ,V'“Ïño¦åŒ@N–îƯŒŒL€ï~þuÒû71;{Ó¿&Gddgú1lÿiø 6qqrúÐøï÷ÿ£èžÿ{ Ðh‚°¼`oÂdõ#=T=0&ªÓÓÅ9ìPT§ZçWißéû#l‹«Ìð¥*øký÷[³Çü±Ãë®4ÍÞP– eg2ð<—Àç uwÚ:E+í^ƒ~rê‰F”ן9ÙM(mvFõ½ßcJÊú?_`'ZYœàþÜSû}qÍóà »s@ùf’R‹Ùö©ìsuþñ Eâáýeßðà@ç%t÷.>mV,<9ö·¤c’ï C§›:“7è'W·ßýîêØ[lšQSà´ž!˜kö½ÐÞ :‡jꊨƒX/æ¾³š­Mª‰$VM‚¢êÔop´Šõjýnë¦ÔÂ%¦ PmL!}Qî"0]û7¸Ù}*>Å{rþY…c8 üa®NÌÆaŠ–ñž‹­*Üôˆ¡ué|ó@‰«†¨´ŽëW÷yúRv8²ÏdcÀÍ»Ýh<¡È†<ñõ(}a²Ò½G‹ì& 7>1‹Þ‘G"R9M`( "Ù3çC¢ù4€ÜZ^þ67ØEo[&3AœbœMS ã-bu2 Êz=î%OËøäÄAí¸d'µ‰¯ÄȪLÈ¡ ª9ëSLñj›ÃD‡¥ò:qXæÇY)rRU5J[Kȯ˜œ¹Ù•§\Ϭr‰ÒSXgAŒdS1è&`F°›ŸEw(yûìô*ÂåNY|ƒ!‰îuU%؆gìq>Öba°y;ûòÜu_~oâÝ‘Šedè¢Í€Ÿ—ªø2®’4m4ï3ºqIðØšP Þ¾š *¦»„ÎÎ<üG¥Çª9»¢WºvðùDñ„dпFˆÝï`ψRÉ×:^ ½4§²6Z¦¥ûÝWv>Ò¨Õ& Á´Zs6Kæêh h{^©Vºtü’º¶5ˆ›ýÚ‹TÏdW°w™×ÁÈÿœ¶OLðAÕo)ñ5õîl¢€ß›uøbÖÆ)¢÷?ݨl”²|#3É@`¾—ZȦHû& å,+X6Eh©Vý°^ù;«•}Y^9û'l ñrCZúmºtÝ%lÜÛÛèòOa²±­°mÒ›ŒäOÞ+÷Ë\¨úMÌÂÖêSeˆóÎ=»»×›œøuŸ¹Žl²fçbŽõ>#a½ö xéLÊŸÊeÝ š¥ÌÈ8=Ö´³+$_žÍfGõµÀÆ27ZºËdï…äeæþ@;†™p¤~—ù<>¯Ý ¹Å ¢×ðq¶$Ëj–£WȪüñ?oZ툌³F-UªXLdBüž1à3ÜYQꟉŸégˆï†+>}ԦƓßk6©óQD:l4M¶I‹ØÍT0iÂXÄÔK™F!:GÍèš¹`gcÎkÉOâþüËÚo6nŸ·ºYEA|RØœ1De°Wü£NáPy5æ$s2¡äT>ßs‹òÝfQ‚~s©Ló©W‰Có³Zªº†@]§CÔóûdõ5Û£Úû*(Öì.ž <ÁY¶Îú]6Ž‘œ÷Á|³žfïk«n}©å^Ö^¢A9¼ãƹú×\Ý9€‚{2!£Iì€аLhŠ¯Ñ“!þŒœÓ,—®e¨Ôþbä,£Öˆ„mO)BÛe™àO2Û×È$Æ€Iþ>ˆÛS”®‚'ÝT2h{–Ó {jvm 1pº(%j‘¸íaÙ1Ñü(ºír}Ò2¾°.¹K:–ý×aó5ÈyÕ§¸·Ðw+•?+<.h¨u7Ê­Du@¥µ£>‹Ég±ý] ÈÏ…è–œô›è‰°•8‚›Œº¡õ{ÍÕæt'RÅa=ÞOC"£—Kz¢ž# ¹á B®hž‰6‡/Ò£¬Ê³¥ œ|æCÿûe÷ªd>…*:„)S[8íFÅÜIr®ôÇOzzF[nÄžýÊüèKÑ{¥…¦Àö¥ ÕvIwQt+ë6³ö”z–ÈèRƱž-¢Ñ-¸·yD³h¯‰4AÏ@û¶·Ãe ˆm†òœí¶%Ó%=é;NêamoNR¾wI¤Ê¨Ñ$sEZ…no‰ÿ[5íÛ¯®,'S‘d¦Àdðøé‘|Æ)Ú’P1<úV}«G–ÀŽ÷Ê–-u=cÕq¬æ¬”Ÿ©®rà šöí ШºAe˜AH|m&𢻋ýÀVC¹+ám5öèy±kø ‘ƒb“qæ—’”yb‘‰Þ.›um"ÛrÈ™à@5qÖ>òCÐéþŽù").Ø#Ì'‚SA­uT)ý/dˈ¾Ü!ÕÔ 5!UÐ‰à„¢1ÓÆ5ÒÍǘ¡F,4 Z:g )xüü]½\:)Ž–o<Éöù:çö÷ ]a­ôFNá^ÈÁÏÕЭñ¼¯ËÞÔš¶D$jÙæ]¯¸¢qÝüÞü±[ ý›µ/kâü=Ao¼‰ìÐü´STž¼LüÄ">|ë‚=åVÌÙœjƒ”«@Wƒ ·˜f©vyʵ‚Íäâf£,çžðŠÙ/o-ÖÒ@bOM7i¢®Áê‹™Ÿ¡â]Q¾ åügáÛ3óq|Á׺®-‰–züAb 'Édö•¡ÎûvsíøÍ^¢‚ל™ó)S¾ÞÊÈûðF¯8qilzô)ÛoÇŸè/QÉ[ô¤¡<às•¾®¶'»ÿ* 2² ÔÎj¬ŽIÊð E<™JÿÜ™Lûž2‚Âx”©‰‰1!û’˜F’5X´:,гlhýÞãeÇ GÇ»4Á3,¿6Š.Ô 2_Ì£³2M>Á)‘õO+ø~9·7ÊO–j‡¡®óR¬}%HúMhÀ!KÒu}]sŠ«˜ÐJ˜œHª¨|Z?¯«^·@˜ ëW‡•¨eaùtkkÌÅ÷ ÈŸ¥WĵmÐgdéSÆMþ¦¸ˆÆ6þÜ'Ôµ˜ Å.£{:šSÀîFÃçìÌ2°Lð†ld•DÉ;|Zaô»éÜâÏæBÌ áÚÀ¶YáéËø ý¤û9k¼Áµ°åûY­SËùvLdÏ+×hmΦݱ¨„¡ˆ>¢ÑV„5ó÷ƒiÃ|ÑiëãA°Ñ1Vñö}š¸ªxƒáAlÄ‚~ö†‚|¹¤¡G—ªòýðGÇ Ðúc›n•ϸC䨀Åv¼ßG6çn- mÊ{Èä;9öÞïWüEQ§@ ¾ À¯˜Lܾ޻*Ü)ij÷i¬“ܯÀ1z/Ó.¼¯¨c’•uÀœw÷ÎÍJ©Ù7/‰‹úþvêo™…«†G|ß6;« ¬ù:€ßqÐvð\Ñ©”{eýW’•ʹÏ%±I£ÉÙÇÂ…Ú$WÊÚQâOô7+lÌóA䨄í†Pºyö¸#bÖX%$KǬÜ÷Ñ8x^͘¶û²[~•~ÃrÉy&qb2å΢iH«Ã·ø1¯¾B¾^I:¢>§UdW~*“XÕg`,Þ9YwÖûúÆžK¬9öФ¯ÚD¨:l«!t]J%"Õ|¸ÓJ3q{ˆvu3QÎ[Òuˆ 5KÙ°a\Zὺµ³ʪéaÕÝ01—ñ]¦ÆxTí=¾£·ºr!OŠvà1oAÝ–ZB0çi«UC0BÁá\qÍ)„[*'âSž‚O’hoº›¥v$nx¨Úe•ƒ»`I˜ñJMW"šU$‘8# mvÂÐö­”ñ€ž÷@nú"F6-{{íò\Øÿ¶èý½¬â’iöÂ~®ÚJ>\xàÚ&8âELoG2ã4LSdÉ3öK¸1<×~·"¤ÕŠ›ñéj›ÃmLz¥;¤¯ck)±ã˜ý…Î(®§Ï­s3‘ª¿2Ý7U©3¨ŒM ö Ô‹ÖoãÄ'x«®ÉCÏ%ÅÝ«~ÞBæÚ¿-ÈÖƒ¥ôêg³Mˆ‰rmšÖÕ®‡)Ê;t q2rÈEŠ›Së· Í>„·W¬ò5]ŠÓô¸EÈÀ‡~Qù¢)’Aúèd´ć5Õî||ì%P|ܦìöEZM•g~TétC 0ÑÚjÝ©uuyÕJa}š¢ BÂÜé@ltgaå Ç;-.:R}Tì1°Ë”·v]ƒ½Œ?7fýàaòîlg”<—%ÆÚT$¸L_²€”›2NYP]¯Å&ÚϺÃW[6ˆ‡"ò"KÐß‚¶“—šDŒi=¼}Yü…nZl”‚G–×ÐÀ°-öyßêøÆÜ4ínÜP4œ|ŠÛªy¶y$>>7ÛLÌ€¿2¿¥:QyzN B8Üpk}/“¨ÛϘb¢êªYR<uYb™P¥¶¶ñBp4žŸkH« ÜJúA}è>¤á’œ›Sicˆúµ¬žA‚§Ì™ê$\+ f*¬Ú om-Ñ­GT$ì»lÂ)-*{ÐØW–cý‡™=ß~Ès»m¶ŒÃús×ÐÁá‹Ò®rt2"†4ËÞë@ɧÂf8iq4Ÿ½‰DF ‹‡íæ±Ã§Ä"4ª_N*,˜â­« ¿¾°”ØšO IÕWU†ŒÈÒ\Ëw¨¿é»0M¨ÈQ'•ËÚïÕ(êbõHéñ^ŦxÛ²§QŽÑÿ|›êf¯“Y#R8¸qNx€_ |¹v«Áôµ_Œ? ÷cC)?°vì¡YÐö½ó¤ u}!ÎiQ¶Ûßœ L­Æ3Æèµ{?§-Ûa¢fŽÀ  ä¥úpDvd •"ßñ‰ì·Þ½æQ%ñ—ýb*ÒØ¸⥆„¿MRU(,X$? IjÞ‘@•øê£Ù*Ù—å(ˆ3¸ã »2ûí[£iS²t'9~kÎ-‹¿üé[«ý“Jf)óýee@]ªi|$—{ "=U…Ïbp-¶h|áWFÈ“ó–Õo´Ï„ŒMnÑI£¦Êfœ¿>ãò…ê§p›Ã6Ђ¸‹ϬÐÅôNÙm©å×ñÁÏõ¥Èî-¨z§—!›–‰Q³è—S­›ÚV´Y;èŸo=O6ü¨%Dz7Nªª­kÌv~—tä2š5šûú¾6Õп$AÆÿó\Ì…KÒ¿–yÙ,¾b+%?éõà•^ð•n©«ñŒÉK¡û®S‘øÍm~ô÷k2稔ø@Y'õ`zXæ’—7ù¶{{þüay\ Õ|¦ê×ÌAÅɾ{ä~ÈÅ`óÁké‰ym}D:† ö£ªÒׯæ,c£Îí0Öù¥ln§ßlóÒ–’2x^X¢ ñw!­6ḿ4•Þ·)+«ü 1¬nÃ`éJ*|͘H†…]&ÑXÐÑs3¢6ÿÅ$k¾íë²­ŠÌ¿KñŽjí¬fÑI»~ß(ü“³Ê‚Ð06ƒŠ;ykéÎx¿`üa¬iÚÕ¯5Âz³©ÝjxwYX˜V$?žììåêiZÝäžmÒ¨ÎQЭ}¼˜—úUw.Üþ(*¬qó yVÏ×®f‚†Ö ÷ äU57$݃÷#Ë­æ®™wù¸Öª…ÞÄ,ãï’ž{ù¹ÔÁ×x¸˜séSzF˜)ªÕaÎ÷œï!àþk‹Câ ïo¬EÈ*dÁî½gˆH{?ë£S2ÑÊ×uÀñJœ&Hu¢TF®BS,¹º¡UIŽxoqeà“ŠwWBOZ20`¼² ;8êè'FƒŸ­ò£ü˜ñ6úD¼lf{€Žš‘…§°Â+„ÙfzFÝ8ò¦žåYØ\R*F:]¨úãæÎƧ‡€Tk­Í"êU»Æœ¬É sJ£ƒuCB[ˆ>úE"Öî*ƒõâ°dùËrJeÏX!vgn½ëÐÓpB:ÿÀgE½¢š«"ÉSÃnâïýe€¬ë-bž™zÀû…$iÐÛuS•BÞdÉS‚ðÝ„uCŽØá=lzP¸øé±NÏÚô«—zAÀ¥gÀÃúóàÜ}û± “õdïð7ݬþºdf‚n.ðÂÕ¤ °ÔÙeH1ËÒ#%SåBùáêÏÖ¬¤^á¸|#›ñ[;ÒIâ†Ï—=‘&픢¶d_ ]8 Ó'MŠ'°Ü3Ù+H“u†@»~Œ9œÝâ´S›Ñþ£.ºÆ+5Mg°W^¹ì7¨_Wð C°/êq‘l‰íÏ£Ýé~üû»Jæso>|?"‰²ØJ¼ ˆäÐ Ñ PÞ£V=´y^ÇÌÝã#%qC[@”µ}j>2P÷ŽŸ”H‹.^Ã!0Ã#¸ ,Öö%<\‘0°‘›wV4gñÉÁÛb•ÎU»í-ÑçüòKv¢'M/àŒP…*µ²l=kŠðKð‡X}Yq „¬­Îõ{N:ÁPa[ ž[îΆâ6lÍFש•D1Ý1´­×íõzÅ ÉTÈ@²·¥,iЧ6f[¥žD¸K}çþr0¥‹ºÛ.m_"x €*¬°,ؤýa9AT¸ Š{iâ,Çß{“Wݲò+VÑl†qÏ–¾&OçÁ÷\÷\øêEú?Ríáîag¼Âï{à>Ì/Ü÷õÚÚR·çY==Æ ‰t×ǯ=Y€|9¢|V­ïÊý<ÍWh(œª<&1·’ÿ肘Õ8_ÆZÜDuxê_­˜Æ kñž±;5;Øtuh® Œ=ÿ-ñòè©ýšnwz2jèsP6äì¢g©=\§Ž@‡ ±Ïy|Ÿteša]^˜Y¿ZάÀâÖTö©ˆŒœê¡ß/㥭½…xŠGڑ̤lU¾—ÿ™º| €˜`YÂT5<ìC&YCØôúÎßaÑR¹µÄžVç(ÎðÛÅ#+F}±ŸÇ^ød{×·:¢yç‚MvM˼ċ­ÂþS‹©Å)Ù³¿XÂVü”‡÷ö4PW‡ê$@¼ýê{‘b´í\ùè1ì·™ÒÕÚÜGAÏP]¡xB+¿Š7ÉÞ†c,o1OèRvì7ó:BI@£¡­‘¡@.þPÅ,Â9˦]“¯˜< ­÷<=(.©vë'ïúª2Û²{vk:ºªYKk÷Ë›™ëȵ!ÓnÒr”SŽÃ¥¦7ÇÂ=õo½/ÒØ›æ3?3È9K‰#¨Ó-WeÜfÂ"\ô­Z‹ûg´qxùOA&¨"X>õƒ¿u< âc4¯3ƒj5GÙ¡Á†%<=‚¬Ieù@²K/Qñ¦ ïƒÙ.ºÙ—Р©Šš¹-ÿê;»™¾ä)k]æzØFõ¢b‚æTS»õKÕfÜîBonÛ1çWêF`º`'ß²\:Â…‰JBŠEƒ'– —Vc;¨ÍáúÝÓ:g:—Jï”{9/aUܱv©ü¼uíd5ˆT%YÊ$Ÿ¡—8q7Ýsãð©V¼>x’ò {ì òFÁü"ÎX¥¦¼Òs?\ÀÙS÷HÔVyê±t¬¾4TÝ‹KqÕ[ÞŸ[<Þ®eÎ|Ãó߭Ѩdd‰]‚i2 0‚/¶yƒ luº%-$Ó‡2Ù7ÏÇ…umóºúúLÖ+¾ò9ìØ‹ìÎŽÇ—mžîP¦îéHH„‡^—¬ý-°ås^}w"{º)º÷ŠÔý(«š“ŸÃjjµSïy2¦Àí~K–¦zêӬͼµ ?>¸§ (ÿü²Ži).€‡o"Ò h—;œ²]âJ ‰Y<M‡ÑÖ#?T€ZíÍ™0®XC5îDŸ±_í_CÈà„†ùŃƒücÊ v®y¥ ß+è!T@"–íLe>·e•&ìν$Ö|è6É`ÕÁ¥øec³éO*eÿÌÌØ˜‘q#.ç`ƒíœ]3kuÒ÷ÚÙÞÖ2ô„c<'þ]b^ý€FÇÆ•Qœrˆ]-§K4iBý—É6V‹Wz ›œ+óà¹{ú_›Tâ_nÞêÊ6²‰ÎÎSÂIRf|ÏôÀ~÷ùJêˇ"ö‰´Ž%ŒÔê"eN×¾x¡Ç1ÎØã"Ê­š}¯r””,–zA2à,Ü'ø:‹'¨º”Ð|Ï×þ'—›2÷ÓNP*ZÑP£ Uþü×3a€'ßBß©o½úèý– ]äîæ¶¯f·ŠtïÇ_z‚ùk ›¦Yá 9/Ð|‘$Î6æøߖǹaÖ(ò÷,°¬|%D᯼Ÿ±öËòEŽåĬ˜êù)èµ2gÝ”ÜÏ¡‹û,¿<±.iíÁŽJ:ÂCóu¿_o_„÷§Í¸B4Y¸Rú&4¹ÔÀèx@?¿ëÈÒ»ÙäGuöˆ!þ4ÉμxšBR¢”¿Í-œ•Ò×o^ºŸÄà‰ËÿÂŒQ¤:û5ë°–…’ÃdåžDo %Vʲ_ žk©ŒªÑì~ «É…u—à¶k˜<9 ‡2’9Ó@TQyEàض®Ï€ õÞSWàŽ—}MÂE9KÂm©Õʉ¤?óT¼"[§TNLݽ;ðRLü‚ðÏK—91ÒŸø”u<=wý“(/Šaш]æç¯–¾ûìê÷ó;8.¼"µŽhŽ)|3µ·"Ô?·_^›Xa{C…Ø ?Љy“CãZUÍaÊ—S¡aUo¬>ø+sÊCà*¬Où[®þ ·×iÉXàP7J»MÍ<™ `ðcf‘3ÏN´¶IÊk²¸~Ir bÕë™°¨~´v˓سPdï“BŽb®ÐŸ<2Ö¦š:g;ãÖïÁ” vëtÈ,âïªçµ´ì*;vtn ‡kÖF[=`k‹„B·%5o~«zq\°äOˆúC@ëkñ£è¦ávvRÍ®Rô^€©ØP°Þ¶C†v5¿ôŒE-ù‚AÒ¾´´@ ây EÙ$¤)^’H.¨5‘ÖR¿-îaýáû»ø]Ì:D¸qQñ“‡lÜCÇj&Ú¹ä³ú›Ê>¡€Y+¬‚ :Í">9ÞÉ Á‰ñKVü@ËO¶Þº·ö½Ý/6˼¥ö®…c³ýg”&•Y–[‰+ºÜº53¶pÅWîOpü¢Dü%)‡l”õrª^Ãx~&ˆ\^¤Ȉ8þßjK©þð†Ü´¼FÖ¡FÕ¿ÑïZ-ÒDn®õ2žzwå…YÁ–;#s¬ö“»†n¶.¡Æøå;´”h¯WŒ¬>€†±ûÔ$r/ë¾é‡H*^06nYœ®_CÈœipÑKÝTS8Qf†?Kutú~"å u¶ÆÊáu2†Fâ{ô˜ïžÜÆŽ¨Â=S'Úþ˜®Ë@F°^Õ¾ Ò„¶¹m‚ž½ˆ›–ÑÁE3³ŠIôòn”K¸ÿØe*UÞ_J”¤=ìPXÐWœ]ê/®ÆÛÞÇ (gáÒ[òáê¥æƒ6˜9Ø ¤0-7Sþ`OEáä:ÖC ±àE%|ãêðéošLËÛWk  Á$ÄØl›™îHFÍfÂŒ²ðÔβ^Tx1ÖЗ—ûªÚ­]E*t²$$-ÛÑž†¨†H Òe{XL#›ê‡ vqú#â^p(=¾7<áH¡mu=)1âë~Hó©Ü¹„ú{9×”?F¢í{†­Æúõª¬”¸3Ñ­ÈäkŽ|Rì[í‹Ùa[Lž: ­QmÂçM|Å?²24c†¬–g΋ƭ)ͦÐ×ñÐIÚøh,ð«WL0H5™e’ÊÎ*À«tŸ—ɇáñÇ 1Αç]ô‰ jhýòÄ:ʼ Ž^¸  ÃTxóC9ïzleb¬MêÀž:a‰G1Y ×Á81k¬„(ΓàÀžJ>cA<²uÀ˲h˜œá¤+FÒÁ"›v¹ö)„™Ã÷t¬Ä,º}vß I–*‰v¸Š;¥û%qúÊ'g,“ŠæG:—`© ^¢ô>„LT]…´÷ÃEÓ,ÄáÞ' ¶}ßÔ†sÔ§¦á¥¸ “Ö./ІÚÉÅ}ÒSR´­NX$5IŸ§«&†g!I9¡ç$9t{¿/{˜"d±¸$+g© -À> endobj 50 0 obj << /Type /XRef /Length 183 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Size 243 /ID [<11675611c716c6ccbfd7e7cbe7e29b2f><63a39e37a24dfa0e56966c294d97dc0c>] >> stream xœcb&FÆ¢o L@ˆäž "7ÙÉ`ö"ɵÌ>"y:A$ÃZ”"9MÁ²€$£T/X½Xä<Øä 6ãtq 5XÄ[ÀöÙKÀn»„aX<ÌîÙ¾ù-ˆÍQ VÙVÉ "e6ƒÕL«¿"¥õ@¤²;X| ˆä ‘ì|`±HÕG R÷:Ø%åÀ°úË}¬žq”%É' ¼FÉ¡Fš$u endstream endobj startxref 216 %%EOF alire-1.2.1/doc/AEPs/000077500000000000000000000000001430264165500141525ustar00rootroot00000000000000alire-1.2.1/doc/AEPs/aep-0001.md000066400000000000000000000012171430264165500156200ustar00rootroot00000000000000 AEP: 1 Title: Sample Alire Enhancement Proposal Markdown Template Author: Alejandro R. Mosteo Status: Draft Created: 02-jul-2020 Abstract ======== A simplified template based on Python plaintext PEP template [1]. Intended to be used for proposals where change history may be unsuitable for regular GitHub issues/PRs. Rationale ========= This section and any optional ones up to [References](#references) shall describe the proposed changes to alire/alr. References ========== 1. Python PEP 9: https://www.python.org/dev/peps/pep-0009/ Copyright ========= This document has been placed in the public domain. alire-1.2.1/doc/AEPs/aep-0002.md000066400000000000000000000202661430264165500156260ustar00rootroot00000000000000 AEP: 2 Title: A complete develop/publish workflow for Alire crates Author: Alejandro R. Mosteo Status: Implemented Created: 06-jul-2020 Abstract ======== Until date, we do not offer guidelines for a complete closed loop on how to use Alire to develop/publish/update a crate. Likewise, we do not have official guidelines on how to distribute, outside of the community index, a project that uses Alire to obtain its dependencies. This document discusses a possible solution for both the closed-loop lifecycle of a crate, and the open-loop distribution of projects/releases that are themselves not (yet) indexed in Alire. Nomenclature ============ - Index manifest: The manifest for a release stored in an index repository. - Local/User/Bundled manifest: The manifest stored with the sources of a release. Rationale ========= The root of the problem ----------------------- The file `${crate}/alire/crate.toml` (henceforth, the manifest file) is currently regenerated from index information during `alr get`, and rewritten when dependencies are modified via `alr with`. This is a lossy process (although this could be fixed) in which the manifest becomes platform-dependent. Hence, we advice against including this file in version control, and we ask for it to be excluded from sources submitted to the community index. Even if this file regeneration were not lossy, machine-generated output mangles the original formatting. Even with a good pretty-printer for TOML, any comments in the original file would be lost. This goes against maintainers, that have to track this manual file somehow, yet exclude it from submissions. On the other hand, developers publishing code outside of Alire, with dependencies from Alire, could distribute the manifest file in place and ask the users to run `alr update` to obtain all dependencies. This is currently frowned upon, again because this can only work today for manifests that are platform-independent. Proposal -------- The key change is to fully embrace manual edition of the manifest, and put it under version control, in a similar vein to other package managers like `cargo`. The only caveat concerns (at the moment) `alr with`, which is leveraged to comfortably make dependencies available in one step (and behind the scenes updating the manifest and the project file(s). Thus, there is a need to keep `alr with` functionality without regenerating the manifest file, to respect user's manual editions. To meet both ends, the proposal is to allow `alr with` to modify the manifest in a non-destructive incremental way, only for the purpose of editing dependencies. Advantages for packagers are: 1. They can format/comment the manifest without their editions being lost. 1. The whole publish process can be automated (see the [examples](#workflow-examples) section). Advantages for regular users: 1. They can use `alr with` as currently, without manually editing the manifest (for now, for platform-independent crates). 1. They can instruct their users to simply use `alr update`, `alr build`, or `alr run` to obtain dependencies, build, or run their projects, respectively. This is analogous to `cargo` usage. Why not `requirements.txt` -------------------------- Another possibility would be to go pip's way and have something similar to its [requirements.txt](#references) file. This file contains a sequence of commands to pass to `pip install` to recreate the build environment for a project. The analogy for Alire would be to have a similar file with commands for `alr`. This has a few drawbacks with no clear advantage over `cargo`'s solution: 1. It does not help packagers, unless we have complete manipulation of the manifest file via `alr` commands. 1. This would be a huge undertaking, just to generate a file that is easily maintained by hand. 1. We would have in practice a duplication of metadata; one copy in the manifest file and another copy in the requirements file, in two different formats. 1. Same problems with manifest formatting/comments being lost. Implementation ============== The proposal relies on the following changes: - The manifest is moved up to top-level and is always named `alire.toml`. - The manifest is under version control and manually edited. - The manifest contains a now a single release, hence all its atomic properties and tables are now found at top-level in the file, which simplifies manual and automatic edition. - `alr with` editions to the manifest are localized and do not regenerate the manifest file from scratch. This is achieved by storing dependencies as an array of tables. Arrays can be safely appended at the end of a TOML document. Migration plan -------------- The existing manifests in the community index can be for the most part machine-migrated. The local manifest bundled with sources is not used for dependencies (the index-provided one is used instead). When retrieving a crate with `alr get`, there will be two manifests at play: the one stored with the index and the one provided with the sources. Both are, after retrieval, located at the same physical location. It is clear that, to avoid misleading effects, the one in the index must be used. To resolve this conflict, a bundled manifest is renamed and stored for reference, but not used. The bundled manifest is only used for crates obtained directly from upstream providers (not through Alire), if these sources are pinned as a directory dependency. This enables the use of sources simultaneously for an Alire-retrieved dependency (the bundled manifest is not used), and when using a work-in-progress version from the same repository (the bundled manifest is used for the external dependency fulfilled via pin). Workflow examples ================= Several use cases are described, with the changes happening to every file described in this proposal. Final user downloading an Alire-aware project --------------------------------------------- 1. The user clones a repository or unpacks a source file. 1. The sources include the manifest file. 1. The user runs `alr run` to test the application, or 1. The user runs `alr update` + `alr setenv` to edit, or 1. The user runs `alr edit` directly. In all cases, the manifest is already at the expected location and directly usable by `alr`, transparently to the user. The user can contribute changes to upstream directly (even if they involve changes in dependencies, that will be stored in the manifest). Final user developing with Alire dependencies --------------------------------------------- 1. The user initializes a project with `alr init`. 1. The user adds dependencies with `alr with`. The dependencies are stored in the manifest private part, but this is transparent to the user. Final user distributing an Alire-aware project ---------------------------------------------- 1. The user initializes a project with `alr init`. 1. The user adds dependencies with `alr with`. 1. The manifest is put under version control. 1. The sources are distributed including the Alire manifest. The user needs to know the relevance of this manifest and that it is intended for distribution. Maintainer publishing to the Alire community index -------------------------------------------------- 1. The maintainer has an Alire-initialized repository. 1. The manifest file is ready after `init` or manual edition. 1. Regular work on a new release happens. 1. Some dependency changes end stored in the manifest. 1. It does not matter if these dependencies are stored manually (e.g. for platform-dependent dynamic expressions) or using `alr with`; the dependencies are loaded from the same array of tables. 1. The maintainer runs `alr publish`: 1. All necessary information is collected from the manifest/configuration, or generated (e.g. the origin), or requested from the user (for a first release with missing mandatory fields in the manifest). 1. The collected information is used for the manifest copy to be submitted via PR. References ========== 1. Rust Cargo `Crate.toml` file. - https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 1. Python `pip` `requirements.txt` file. - https://pip.pypa.io/en/stable/user_guide/#requirements-files Copyright ========= This document has been placed in the public domain. alire-1.2.1/doc/alr-logo-black-white.svg000066400000000000000000000175731430264165500200240ustar00rootroot00000000000000 image/svg+xml alire-1.2.1/doc/alr-logo-sq.png000066400000000000000000000262711430264165500162350ustar00rootroot00000000000000‰PNG  IHDR+ƒbKGDÿÿÿ ½§“ pHYs-xþ,tIMEâ ¾ØF IDATxÚìÝô¦u]çñç0Ã Š€†¡øÑ$MEÖ67- üqMQKÍÊrµãºyvÏnÙVg;Ú·ÍR7P›‚& ‚™™V "Zé ÁA ‘30Ìþqß´3ÌÌw¾?îëºs>g¶v÷®÷}_×÷z½îÏ}ݬ¹uF°p®S=ªzpuHuïjŸj¿êºjsueuIõÅêÓÕ'çÿ3ÀryÀüzttõ ùÿ|pµ©Ú×x`Õl›ÿ{Ó|]W}»újuÙüžà«·ù÷ÖÿýV£C°x¾¯z~u|õð=¸>_XQýIõYc–à¨ê¤ê¸êpã€ÁÚ\]0_ÿx›ÿI1kãG«¿¬niÖî/ç:¯z^µÞ˜X?¿^œ·×"˲k][}¸úåꇳ›VÜUŸZ¥?ô_¬N4r`Nœ_'#˚溩:·z}õÄjo—EXUï\£?ð©ós‡Í¯ eY·]ßšß«<§º«K%,Í4{(ÏZþQ¿¾z…—&ïͶ ;–eÝÑÚÒ쫊/­pé€]óŠfÜY”?èTmô²Àäl¨Þ(ÔX–µ„ucuj³„np9€ï¶¾úß ú‡ü¯šý¬ 0 ûÍÏ{AƲ¬=]—U¿Úì§Š€fÑyÏ‚ÿÿ¸&aßêcB‹eY˼¶6ûùáǸÌ0õðÿÞüñþ«<ñÆ~=òÉ¿eY+½>Z=µZç² €ð¿Øë­^6­?L,ËZÅu~uRµ—Ë/Âÿâ®—xù`t~Z±,k ‹€\†‹íËþO©ž1ÐÿþëªGVz)a¯>Óìûÿkåoª×TçÅÚ³-@ø¿Õ¾Õ[RÃXüð,€W]½¯:Ô8ÖÖz#þoãþÕͶíÃõìêÕÆ,#ª—6ûúÜf¿ À*ó)€ðÿo}iþGúf// ÒúfEÞaF,¨‹«—U6ŠÕå+Âÿ¿õÀê'¼¼0XÏþwhõÕ©ÕAƱzìþ·çsÕQ^f¤¿«n À@üsõâê £XyvÿÛó0éÎ]``¾·:½:9.Uÿkæù^nœ“Œð}ǧ²Q ü¯‰ã½ä08?nÀ€Ùì~1_W_† üߑÚ=©X|‡V0§V?U]oËÇáÿŽ<ÆËƒñX#FäÄêœê£Pÿ«ãQÞ0G02kö•€cB ü¯<¿%Ãñ #Fè ê¯ª—…@ø_Y‡x+€ó`m¨þWõ?ó;€ð¿bîa00r¿T½QŽ]:í €ðG6Wû æ|Ýh À¼«zAu“Q(„ÿåµ¾ºÅ`¡íUm5`BΪžUÝ`»÷ÇáÿŽ(‹Áy °hžR}¨Ú×(Â?À¸[½¯Úd á`ÜþCuj³_ @ üŒØñÕÛä[€ð0~'U¿g á`ü^V½ÖvÌcáŸÙŸƒE·¾ºÙÚV=§ÙsP¿ð¯ÀˆÝP=¡:Ï(nÏWá€1¹SõgÕ=BÿŒÛ}«÷V›ŒBÿŒÛc«7ƒþ¿UÏ5†„vÆCañy ÀŽ]S=¼ºdꃰþ³ªwÍïÂ?#öèê¿N}¾ÿ쌯Àâ󀻥zbõ1€ðãvqõýÕS3ã<¸Z§„¦ì#8Æ}ª»)á€)ûÄDŽó` ü0eg7ç(á€I»ºÙ³ @ø`ä>?c¼§þ˜º/Là÷WÂ?SwùŽq üOÏÕWŒà_]¥PÂÿØ|°:¡Úbÿêk8Æ;+áZáÿÕf£¸ë&pŒv¿ð0y7(€ð/üŒß¾¹QÿÂ?ÀÔí3c¼QÿÂ?ÀÔÝI „á`üöS(á_ø¿ƒ'pŒƒ}С„„€þ…vÙ}'pŒ¾ÿÂ?Àä9cü¦þ…€©{ðŽñJ ü ÿSvHu @ÿÂ?À¸=n"Ç©„á@0W)á_ø˜²'O௭¾£„á`ªR:ã¼bÈÿñ þ…öÔñ9Î €ð/üLÙs'rœç+á_ø˜ªGUȱ^ „á`ª^<¡cU¿ð0IV'MäX·å€ð/üLÔÏWûNäX/kÀ?¨á_ø`©ö¯þㄎ÷3C?ÿÂ?Kñêf_˜Š+á_ø˜š{V¯œØ1Ÿ£„á`j~»ºË„Ž÷†êï€ð/üLÉ“ªŸ˜Ø1Ÿ[mQ¿ð0TošàqŸ=†ƒP€ð/ü°«ÞX2Áãþ[ ü ÿSñ“Õs'xÜ×US¿ð0löéÿýEu£þ…€±»ouFu§‰ÿÆr þ…väîÕŸWOôøo©ÎT¿ð0fûÏnœð έ¾¦„á`¬¬þ²:zâs8cL³Áû„á€Û¸w³ß9ñ9ÜR½sLdÿÂ?·zxu¶ð_Õ_W—*á_ø›çÏÃÿýŒ¢ªw°;áÿ´j›µäuVµiÁ_ç‹'ð:¬w:ÃÂ[?kÑÅ^fX1ûUowïy»umu—±½Ðž+þ}ò¿g|ò°òžPýQõ@£¸?«¾3¶ƒòþ…€é¹{õÖê£Âÿvrû¿ ü ÿÓqçêåÕkª»Çv]Øì€ @øþg¿ê§«WU÷2Ž;ôúf?¨„á`0¯^\½´:À8vêkÕŸŒõà ü ÿãrïêøê¤êqƱ[~¿ºQÿÂ?À":`ô©ž\=²Zg,»íúêÆ|€ þ…`-Üe~?ÅÎg´±º©:°ºGupuÿêÈê¡Õ÷åÞ–Ã;ªo(á_ø––7~°ztutuXuHõ½FÂÙR½n '$ ü ÿÀrY_ýhõ¼ù¿w3àMÕ% @øþ€Û¯úùùºq0 ß©~} ªá_øöôé•Õkªï1èwšýüŸþ…`Ž­Þ\a Ô7ª×Oå`=)„áØ]šm™þ¨ðÏÀýFõí)¸€ð/ü»j¿ê]ÕSŒ‚»°zã”X¿ðìªûTΧþ ß¶êç¦vŸªá_øv5ü´:Ô(wÌßÏ“â ü ÿÀÎÜ­Ù'ÿÂ?cpuõê)¸„áØÙýÑ»³íŸñxu³§ÿ+@øþ…à6^[=щUoŸêÁ+@øþ€yBõKÆÀH\SýT³*@øGøæ6V(30"/«.òœÌÿ¿ðlÏ+ó½ÆãäêO§>¿ð/üÿÖþÕkŒ‘ø§ê寠@øþ…à»ýB³Ÿþƒ¡»©ú‰êÛF¡@øGønoCõóÆÀH¼¦ú”1(þþ€ïöcÕ½Œøãê·A€ððlßs€8§úicP ü#üÛ·¡úQc`à¾Zà¾U€ððìØcª»v}u\u…Q(þþ€;.`¨¶VϯþÎ(ÿÿÀ;Ú¨mÕK«÷…ááعÌ€úÏÕ[A€ððìšûô+ÕëA€ððìšõÕÆÀÀü^õZcP ü#ü»îÎFÀÀü~õ cP ü#ü»g£0 ¿VýB³‡ÿ±‹6Â?Â?PÝ` À¶füóÂ?Â?°ÀÖfÏ€E´µzIõv£X_@øþ… fŸ¬^i ,¨«„Â?Â?°<.3ÐW«'T§…ááXŸ7̹ÕÑÕ§ŒB€ðð,!‹EòÎêßç«) „„`Ù}ÂX[«ÿT=7¿N¡@øGøVÄÕÅÆÀúrõÃÕo…ááXYgkä”ê¨êoŒB€ð𬼷«ìÚêgªçTÿb „„`u|®úŒ1°JΩ^½Ù(ÿ¿ð¬¾×+ìšê•Õ±Õ—ŒC€ð/ü ÿÀÚxw³ÂJ8¥zpõ†fOüG€ðð¬‘[ª_4–Ù%ÕSš}×ÿJãP ü ÿÂ?°>T}ÀX×Tÿ­zÈü~¿ð/ü æg««%ÚÒìá~‡W¿VÝ`$ þ…`1]Q½´Úf솭Õ۪Úý¼ß׌D¿ð,¾÷V¿a ì‚-Õ;ªï¯^T}ÙH€Û†ÿÓš5ÊÖÒÖYÕ&o¥5uñÞgë½Ì°ðÖOàZt±—yM­«ÞéÞËÚÁú—ê7«{;UÛ#` ÿOþ÷ŒOþ€Õ²­zaµouœq0we³ïøÿî¼Ønø÷É¿OþÇÂ`ØÀjÙXî^lÒksõgó"ÈÊ€ð/ü+€@ °F¶þ¾zEuw§ÀpilXíðoÛÿž±íXk[ªgÍïëžf£v~uFuJõÆ¡á_ø¦YœX½'Ï“›«ÏCÿû«/‰„áàÖJ€áÚZýcõ·óàÿáê›Æ¢á_øP Û·ªÏÍÿÙÕ'ªo‹„á@ 0Lߨ¾Øì;üçWŸŸÿûU£Q€ð/ü(Ã×ç9mCµ×|mn¶]ÿÚê;Õ•ÕתËçÿç+ª«nó¯ûG`UÿŸúóSSágEàgY«÷¹—Û£u¦û@VÊ^FÀ „ŸüïŸüCu민ß(–ì)Õ{•(þ…%€ÿÂ?€@ „á@  @¿ð P á_øP(P ü#ü(”(þþ%€@ €á_øP @€ð/ü(P @øþ”JP ü ÿJ%(þ…%€¿ð/ü(”(þþ”Jÿ¿ð P @øþP(P ü ÿJ”(þ…%JÿÂ?€@  @€ð/ü(”(þþ”JÿÿJ% „áVÛ6Lj% „á€ñ»eŽÆì/3J% „á꺑ßõ^b”JÿÂ?Ô×G~|_ó³à}F¡@€ð/ü05—9>&X<[  @€ð/ü05_ùñ]ä%F  @€ð/ü@}zäÇwž—%€Øqø?­ÙOæXK[g¹² .žÀ¹°ÞË ƒpøˆ¯C7Vûx‰Ù‰î÷xéþ„áÀ0\4Òëн´(”ì9_gø·íÏØöÀP5Òã:ÓKË.òu€=çë0 ð¯ñôÉ?«Ë`‘üà¯A›«ƒ¼´ì&;ìáßþQ(`ôþad× ÷xIQ(á_øG ¾Û‹Gv :ÖKŠ@ ÿÂ? °ý{ƒKFrýù¨—%€þ… `Ç^0‚kÏ-Õã¼”(”€ð/ü£P;¶®úë_{ÞæeD  „á€ع‡V7 ôºsežü@ ÿÂ? °Ë^Þ0·þ?ÕK‡@ ¿‹•ð@ìºuÕŸìšóZ/J%ÿ.RÂ? °ûö©ÎÈõæóÒ”Jþ-á€X‚ªsý­%€„á ¿»Uç,èuæ=ó J%ÿ–ð@,ƒMÕ/Ø5æ Õ^^”Jþ]H„ `y­«^ÑÚÿDàÕÕ³¼(”àâãâ#ü£P+ëû«O®ÑuåŒê¾^܇+ÀEÇEGøG VÇ^Õ‹ª¯¬ÒõäüêÇ÷ãJÀÅFøG ÖîägªÏ¯Ðuä“Ͷûû®?îË•€‹Œð@,ˆÇWØžï ¸°z]³¯€ûs% `,ÌÅå”êéF±d¬žQm6 Ö xàÈqCµÕK “¼O|hõ˜êQÕƒªCª{TûÜæÿÝuÕ•Õ¥ÕÕyÍ~nðb#Ä}:Í>¤{¦ûtøÿÍ¢Oþv`0Eûî×­ìá€Ü·[JpþQ(Àý»\<,á€ÜÇ+ÀEÃþQ(Àý¼\,„P(À}½\$„P(Àý½\„P(À}¾\„Pî÷Ý‹ ¸ï·Ü÷ã"`¹ P€ûËý?N~ËÉ@r€ à¤wÒƒ@ò€<Nv';( Èà$w’ƒ@ò|Nn'7( 'È à¤vRƒäœÌNf'3  7È 8‰-'1  ?È8y¼ P€aÉ8i´ P€^Ýd4 P(„áãvMõçÕÉÕ‡²“”J€ð/üƒ`ô¾RýNõ¦êzã%€`mì%ü#ü+ì¾ÕoW—T?›‡‹ÂrØR=»zŸQ,Ù5{°âd 8…@øþ€ÅpPõÕ§ª£Œ”JÀr‡ÿw ÿÂ?°PQ[ýbÓýU*P(ËþO©Ž÷~^²³ª…`ljöµ€wUw2P(Kµw³mÿˆ±t§7áßÇV͉Õ_Tû,K pºQìQ pÊù†î˜ê.Æ+ÂN€ÝódÀê;¸ºŸ÷ÞNùäƒ Õ#VŒ»î~Õ½«ëhï»òÉ?0& XYvLàz4ÔàPï¹;ä“`lüâ ¬<;F~=jpï¹òÉ?0F0XvìÜ! €Õåçÿ¶Ï'ÿÀXh°jìéõh¨À¾ÞsÛ ÿÏÌ'ÿÀ8¹ÿƒÕuS³•#º µØà=w;¶ýÃÚÙj«bo#€5)|`D×£¡7xÏý+ÛþÁõ` ®7X¾0¢ëÑP €k½ç*ŸüƒëÀt|Ç`ÍØ 0’ëÑP €+¼ç|ò®G“r¹Àš²`×£¡—Nü ç“p=˜šËŒÖœ¿ µ8Âo6ŸüƒëÀý£ÀB°`À×£uýïÞT]3ÿwjáßOýÁb9¼ú‚1¬Êõö‹Æ cïêÔêé;î-ÕþCÍdCݰ¹úôÄÞh¶ýÃbúbõucXQ_¯.2X(Sý:ÀyCÎd{ xðgNèMfÛ?,®m»¬…̯·Àb™â×>0äÿø!ïŸÈÌ'ÿ0Œó€•s†ÀšÚN€AçºÿÜêÑ#~sùÎ? ÃÆê+ÕAF°ì¾QÝÇý,¼)<àÜê1C>€½þ¼eÄo.ŸüÃpl©Þa +âmî‡`¦°àÿ ý†¾`Sõ¥êÞ#{cùä†çàùõèNF°l6W¬®0 Œ±î¸r~=ºaÈ1ô›«×ìå“î…·À²ú#ág¬;~sèῆ¿ fß½ý\³ß†:ŸüðT]XÝÕ(öØ·«#š¬ÀðŒi'ÀÅÕCÇÓöÁ‹±¥zåŽÃ'ÿ0|_¯~Ù–ÅþaÐÆ´àårÚâyK³ß‡â:³Ùó €áÛ«úÈ€¯G–eY‹°þºZïO ŒÂÞÕi¾½yL/ƺ˾է›m’Ó«šídÆá>Õ?TÀn»ºúêr£€ÑØX½»:~`ÿÝ_¨Ž®®Ë ±×ˆÞT×UOmö[±CqVu¢ð£sy¾Ò°7Íï„—-Õ³ª÷ è¿ù›ÕÓÆþÇê Õõ-þV’÷7k€ñzAµ5[y-˲vem_7ñÚ8ÏA‹~=º~ž+ˆYðà4á&ã%J˲¬] ÿ/ñ'&S,ò3®ŸçI懚}‡lÑÞPo©6xy`RžWÝèß²,k»ëÆùu˜Ž -æCܯžçHêAÕ òfº©z•—&ë˜ê*7ú–eY·[WͯÀ4½jž“áztÁ?õ*noSuTõêê>;²o³ßƒÜRýsuIuqõ™fO¯Xnw©Ñl+Ü!Õ½ª;ϯI~JX7W×ÎÚì¡Ç_¨þ®úŽñ+àžÕ#«C«4{ÀòÆù=ÒuókÒåóëÑùÕg«ÍÆðÿÚƒCAÿ_û¯ž+-Çèã=‘IEND®B`‚alire-1.2.1/doc/alr-logo-white.svg000066400000000000000000000111031430264165500167310ustar00rootroot00000000000000 image/svg+xml alire-1.2.1/doc/alr-logo.svg000066400000000000000000000110271430264165500156200ustar00rootroot00000000000000 image/svg+xml alire-1.2.1/doc/alr-logo.svg.png000066400000000000000000000234651430264165500164140ustar00rootroot00000000000000‰PNG  IHDR¥]ûËsBIT|dˆ pHYs-xþ,tEXtSoftwarewww.inkscape.org›î< IDATxœíÝy°¥i]àùoeVel* – ²"B#‹(2ô´£( .!¸¡v»`» ŽÓÆLô¸ŒÓm·ã4n#*Ý#‚ ›­¶»²ª­„ìe² h³Ô–EUÍo%$i.÷Þ÷œó¼çœÏ'â‰Ì¼™yïïÞ|óÍóÍç=ï¹(€ÝvYõðê¡Õ§T—Ww«nSÝ¡º¦º¡ººzcõúêO«—Þúc€U¹GÓùè!Õ}nýñeÕ¥ÕíÎûæ–[¿½ñÖuMõÞêíÕ››¼ý´oO½ý¦Oº'.=À|rõµÕãªuôsÝëªTÿ©úËÕŒì™VO¬[]1xàèn¨^sëú«Ó¾ýo‰UNóùÕ©nnú_ÐU®WT_Sߨgl«ãMç‹W´ús‘eYËZï«~»ú¾êŸåª€½õO«—·™|^_=a#Ÿ°žÐtžý@Ù²¬1ëÆêeÕVŸS];í.Õ3óÎïT÷^ÿ§l‰{7F? ¶,kYëš«|eõ‘°S>·éÆ#ÿ¡¹¶zòº?Q`ñ¾®é¾Ñ~-ËZö:Ùô4£'Uw €­ö䦛 ŒþÇåÔú¹êÄZ?c`‰.®žÖøseYÛ·®¯žÝt´‹`k¯þŸÆÿCr¶õ»M/1ì‡;4ý½}î±,kû×›«lzÙ:ì’êWÿÇùÖ'LaÜ®úýÆŸs,ËÚ­uSÓKÑ=<ç’ê×ÿÅAÖïæN{°Ë.É©eYë_¿W}aG­uVh›‚ôÔzúZ¾ÀüTãÏ1–eíÏzUõÄêX ±Azj}Ó¾ÀXßÜøs‹eYû¹^U=¾e;XªKªgU_:z#º¦zpõºÑƒ+qEõgMÏ'å«ï­^2zU² ,ѶiM\6ÿù»â'¤ÀxÿCõâê¹Õ½ϲ2ÇGp†]ÒS>©zMÓ%7ÀöúŠê{FpšûVOjÚd|YÓ{·–ÿÁ–d—‚ô”¿nú‡ã£ŽäxÓ.Ý{ô çpUõmÕoä¨\¾ ,Å.iÕ=«¯=pd_“ –í^ÕoUÏ®î2x–#±S ,Á®é)¯¬8zàHþ¼zÐè!èo«o¬^0zðS Œ¶ëAZõ€<¨…môéù» l—­ž_=£-º9›(FÚ‡ =åkGÚGpD_[½¼-¹RK”£ìSV=nôÀ¡}Ñèf¸_Óy¿«…?msÑÃ;kß‚ô”{7Ý!X¾{Uo=ÀŠ<»úÕµ£9;¥À¦íkV=|ôÀ}æèVè ÕKªËÏqV¢ؤ}Òª‡Ž8°‡Œ`ÅÐt9ï#Gr&Q lʾiy­CØ&÷=ÀÜ¥úÝê;Gr:Q l‚ \>zàÀ.=Àš\\ýßÕÿÕBî1$Ju¤r×Ñv—ѬٿªžÖšpe ì,Aúán¨n3zà@n¨NŒ`~¹úºêÆQˆR`]éÙ¯n=p^Ǫ›F°AWV_^]7âƒߪv’ =7ÿËçï)°oSýfu»\”«&H¶Ï#«çV—nú‹R`•)ÀöúŸªg7Ý¡wcD)°*‚`û=®úù6ØŠ¢XA °;žXýĦ>˜(椻çÛªØÄrw9`Azxç¥&`éŽW=ÀÜR}eÓóL×F”G%HF”Âò‰R€¹®zTõŠu}—ïG!HöÃm«_«>n]@”‡%HöË'T¿Þš^ÃT”‡!HöÓgVO[Ç;¥ÀA R€ýö ÕW¯úºÑp‚tuÜè–ÏŽÎí=Õƒª7®êÚ).Dpʪ_nzŒ¸¢8A À™Výï«zg.ßÎE®‡Ëwaù\¾ pa7WŸSýþÜw$J³¤ë#JaùD)ÀÁ\U}Zuýœwâò]àL‚€ƒ¸Wõ¿Í}'vJÓ Òõ³S Ëg§ààNVÿ¤zÍQßRàA Àa¨~ºž¢(A ÀÑ=²úçGýÍ.ßéf¹|–Ï廇÷îêŠ[¿=;¥°ß)«pçŽxÓ#;¥°¿évJaùì”ÍõM»¥s˜ßd§ö“ `ÕnS}ÿa“RØ?‚t,;¥°|vJŽî¦êÕ«úì”Â~¤¬ÓñêGóì”Âþ¤Ë`§–ovJo¬Þ2zX“cM¯yiÓ㟋›þ^;íço¹õmzh}>³zéA~¡?Ø—TÏ®¾dô ˆRØû¥]Ýkô0ØEÕ]o]÷¨>¥úÔêÓ«û¦•æzNõeù…¾Ð°û鲈RX>Q |LõˆêÑÕc«»g+ÝÜ÷o=0Ö%MÿKu‹µ˜uü¼bÀoü¹bÝ몕}µ`÷]T=¤ú÷Õ»ÿ÷w›ÖÓŽðõvˆ ]楰|¢8—Õã«—4þïñ6¬kšvÏËÝwa7¹d`õNV¿ÒtŸGV¿=vœÅûˆê[GlžÒe/;¥°|vJÃøœêÿ{½Ôõަ;!Ÿ“RØ-vH6ëwª‡U__½{ð,Kt×ê‹Ï÷ D)ìA 0Æ-Õ3ªûWÏ<Ë}ýù~R”Ân¤ã½£iWðë›nòÃäóªËÎõ“¢¶Ÿ X–g4½Îé›ϱWO<×OŠRØn‚`™þ²é¹¦8z…8ç%¼¢¶— X¶¿­>·úÕу,À§V9ÛOˆRØN‚`;œ¬¾²ú…Ás,ÁÎöFQ ÛGl—›ªo¨ž>zÁw¶7ŠRØ.‚`;ÝR}Kõ¼Ñƒ tEuŸ3ß(Ja{R€íö¦Ky_>z{æD)lA °®ozL÷¶Ñƒ "Ja R€ÝruõM;§ûæÕGŸþQ Ë&HvÓŸTÿçè!¸¸éer>H”Âr R€ÝöÃÕ‹G1ÀgŸþQ Ë$HvßMÕ“š^ËtŸ<âôˆRXA °?^UýÛÑClت;žú(…e¤ûç‡Ú¯»ñ¯vꢖCì§k«=Ć}ð^Q Ë HöÛÓ«7Œbƒ>ëÔwD)Œ'Hø@õÔÑClÐO}G”ÂX‚€SžQ½côr×êÎ%Ja$A Àén¨~fôô)%JaA ÀÙü|uËè!6ä~%JaA À¹¼©ú£ÑClˆR@p!¿4z€ ±S &H8ˆßh?.á½w‰RØA ÀA½­ú³ÑClÀeÕE¢ÖOpX¿3z€ ¸MõQ¢ÖKp2z€ ¹L”ÂúRŽêÅíÇóJE)¬‰ `Žw7=·t׉RXA À*¼zôðq¢VK°*¯=ÀÜQ”ÂêRV魣؀ۈRX A:ß ª·Œ`AÞ1z€ ¥°‚t¾U¯NŽ`AÞ9z€ øQ óÒù^T}iuÃèAæšÑl€R˜AÎ'HÎíºÑl€(…#¤ó R€óÛ‡§6¥px‚t>A pa·=À\/Jápé|‚à`n;z€ ¥p‚t>A ppw=ÀˆR8 A:Ÿ 8œËF°׉R¸0A:Ÿ 8kô"Já4‚t>A °û¥ï¥0¤ó R€Õyôè6à}ÕûE)ÒU¤«ó©Õ½F±o«¥ì;A:Ÿ X­Ç`C^W¢”ý&H礫÷Õ£ØW•(e Òù)Àê=´ºÿè!6ä5%JÙO‚t>A °ß8z€ ¥ì%A:Ÿ X;WO=Ćܒ甲‡é|‚`}¾½ºÝè!6äÍÕûK”²?é|‚`}îXýÏ£‡Ø ?;õQÊ>¤ó R€õúž¦Ëw÷ÅŸúŽ(e× Òù)Àz}\õ”ÑClØKN}G”²Ëé|‚`ý~¬ºýè!6èºê¿žú(eW Òù)Àú}^õU£‡Ø°—U'Oý@”²‹é|‚`ýîTýôè!xñé?¥ìA:Ÿ ØŒ§U—b€?:ý¢”]"H礛ñÏ«¯=Ä×T¿úD)»BÎ'H6ãÁM»¤ûè·ªëOƒ(eÒù)Àf|Bõ‚ê¶£ä7Î|ƒ(eÛ Òù)Àf|LõŸ«ËF2ÈÍÕ Ï|£(e› Òù)Àfܱé±×ýF2Ð˪wžùFQʶ¤ó R€Í¸sõ_ª‡Œd°œíoz XA:Ÿ ØŒ»5ÝÜgŸwHkºt÷™gû ;¥lA:Ÿ ØŒU/NVýAõ¦³ý„(e›Òù)Àf|mS~âèAâGs]R=§ºÅ:òº²ºô°_ø »ªñ_§u¯ã+ûjër¼ñçŠu¯«VöÕÎt‡êÿ÷|Ië}ÕíÏõóœR¶Òùì¬ß£ªŸ«î9z…ùµêýçúI—ï²t‚t>A °^S=½ú½éÙœ÷Ò];¥,™ O¬ÏGTßY}oõ‘ƒgYª×5ÝäèœD)K%Hç¤ëq‡ê›«ï®>~ð,K÷£M/sN¢”%¤ó R€Õ»¢úÆêIÕϲ ÞYý§ ý"QÊÒÒù)ÀêÜ­z\õÄê³ϲmþCuý…~‘(eIé|‚`ž;5Åç#ªGW®.:Ñvº¶úɃüBQÊRÒù)ì¯Û7=žâÜN}NT7Vw®îZ]V}Ru¿êþÕ'çUJVá«¿;È/¥, OÀúŒêaÕCª{W—W;p&8›“ÕSú‹E)£ Òù)ì®ãÕçW_së·5v8Ÿ®ÞxÐ_,JIÎ'H`7Ý¡úö[×Ýχñþê‡óD)£Òù)ìžKª§Tß[}ôàYà(þ]ÓKÁ˜(eA:Ÿ €ÝóÈêgªûŽŽèïª=ìorW)6MÎ'H`·\Üt¹ãï%HÙn?R½÷°¿ÉN)›$H礰[îPýrõ˜ÑƒÀL¯«žv”ß(JÙA:Ÿ €Ýr÷ê·³;Êö»¥úÖŽø8U”² ‚t>A »åîM—ëÞkô °¿Øt<‰ç”²n‚t>A »å£švH)»àÝÕ÷Ìy¢”u¤ó RØ-—T¿’KvÙßÓt×Ý#¥¬‹ OÀîùêsF+òûÕ/Ì}'¢”u¤ó RØ=ªþÕè!`EÞSý‹¦›Í"JY5A:Ÿ €Ýs¢ú©<þfw|[õ¦U¼#)X%A:Ÿ €Ýô”<”ÝñŒê—VõÎD)«"H礰›îX}ïè!`Eþ[õ«|‡¢”U¤ó RØ]ßÑô20°ín¬¾ªzï*ß©(e.A:Ÿ €Ýuqõí£‡€ùÞêå«~§¢”9é|‚vÛT?zXÿXýØ:Þ±(å¨é|‚vßWVà%Õ7¯ë‹RŽBÎ'H`÷]\}þè!`¦·Wo[E)‡%H礰^}äè!`†k«ÇVo[祆 OÀþxøè`†›ª¯­þ|ÝH”rP‚t>A ûå!£€#º¥zRõë›ø`¢”ƒ¤ó RØ?÷=ÑÿZ=}SL”r!‚t>A ûé“FGðýÕnòŠRÎGÎ'H`?¯îA ûë#F‡ôª'øÀ¢”³¤ó RØo'F‡ðCÕw4Ýàhã.ñAY4A:Ÿ ®=À-M75ÚèsHÏ$J9 O5EéMMÏ-…%º©ú¦êÏáò]>HÎ'H€Sn©®=œÃõÕã[@–(e"Hç¤À™ÞA œÍ«GgxYõêå£9(Ýo‚t>A œË¢ø³÷žYý-ð²rQº¿é|‚8Ÿ?=4ÝÐ詾º…ÞZ”î'A:Ÿ .ä5ÕU£‡`¯ýMõϪ;zó¥ûGÎ'H€ƒzáèØ[ϪXýáèA.D”îA:Ÿ ãé£`Oú–ê+«ÿ>x–¥ûCÎ'H€Ãzeõg£‡`o¼¤zPõ3£9 Qºé|‚8ª§Ž€÷žê)Õ#«¿<Ë¡‰ÒÝ'Hç¤À¿ÒtÓ#X‡gUŸRýxÓv·Ž(Ým‚t>A Ìusõ]£‡`ç¼±zLÓsG÷Ú£‡!Jw— O«ò›ÕoŒ‚ðžê_WŸÚôxuë‰ÒÝ$Hç¤ÀªýËêÝ£‡`klºÑÕU×guDéî¤ó R`ÞV=©ºeô l•›ªŸ¯îÝôR/ï;Îê‰ÒÝ"Hç¤À:ýzõ#£‡`+œ¬~±ú´êª¿;\Ø%ÕsšþçÍ:Úº²ºô°_xVêªÆë^ÇWöÕÖåxãÏë^W­ì«ÅQ\T=³ñǵÌõß«SÝ­=qñèX ;¤óÙ!6å–êë«ÛU< ËquÓsFÿ}S˜ÂÖ°C:Ù!];¥ÀØ)eSNTÏoüñ`[7T¿ÖôŸ6 ÙJ‚tþ¤Ë"J%¥l’0ÝÏõ_«'Wj|‹¹dw>—죬¾¼éqÝž…õzUõ‚êYÕ_ žeQDév¤ó R`)NVO¨~5Ï1Ý%¨þ¸)DŸWýõØq–K”nA:Ÿ –æÔŽ©0Ý^7UUýQSŒþvõ÷C'Ú¢t»Òù)°TÂt»üCõʦ}qõ'Õ{‡N´¥Déö¤ó R`é„éòü]õú¦ç„¾ªzõ­ß¾}äP»D”nA:Ÿ ¶…0]w55ÏÅÕ±[× M—Ú¾¯zÓ냾³zë­ß[õŽÓ¾õø‘½çe_æ//û²=¼$ °^†¥8Q=·ñÇË6¯æqàâ=çe‡t>;¤À¶:uWÞçd‹=¦úõ„颉Òå¤ó R`Û Óù„é‰Òe¤ó R`WÓù„邉Òå¤ó R`×Óù„éB‰Òe¤ó R`W Óù„é‰Òå¤ó R`× Óù„éˆÒe¤ó R`_Óù„邈Òñé|‚Ø7Ât>aº¢t,A:Ÿ ö•0O˜.€(GÎ'H€}'L禃‰Ò1é|‚`"L禉Òͤó R€'L禃ˆÒͤó R€³¦ó ÓDéæÒù)Àù Óù„醉Òͤó R€ƒ¦ó Ó ¥ë'H礇#Lç¦"J×KÎ'HŽF˜Î'L7@”® OÌ#Lç¦k&J×CÎ'HVC˜Î'L×H”®ž O¬–0O˜®‰(]-A:Ÿ Xa:Ÿ0]Qº:‚t>A °^Ât>aºb¢t5é|‚`3„é|Ât…Dé|‚t>A À’Ü2z€ ؇ϑó¦ó Ó¥óÒù)KssÓö]vÝèXa:Ÿ0]Qzt‚t>A ÀR]3z€5»vô,†0O˜Î$JFÎ'HX²w`ÍÞ9zåT˜>wô [L˜Î JOÎ'HXº7`ÍvýóãðNV_‘0C˜‘(=A:Ÿ `¼~ôkö†Ñ°HÂt>az¢ôàé|‚€mñ§£X³WŒ€Å¦ó SÖâ’ê9M·O·Ž¶®Ì_L.ìªÆ«ë^ÇWöÕÖéŠÆŸ/Öµ®¯n³º/;êDÿÎ]/Ìã_VDÎ_‚”ƒ¥À’¼¡ñçŒu¬­ò‹ÄN¦ó—0=—KvçsÉ.ÛêÊÑ¬É GÀÖp)ï|.åe;¤ó—RËN)°$ŸÑøsÆª× Õ]VùEb/Ø1¿ì˜rh‚tþ¤…(–æ/ÞXåúÕÕ~yØ#Âtþ¦˜ ¿)G%J¥ùÆÆŸ7V¹¹Ú/{F˜Î_” ¤ó— eQ ,Í%ÕîXÅú½mØOÂtþ¦œ“ ¿)s‰R`‰¾®ñ玹ëæê³Vý…ao ÓùK˜òÒùK² ¢X¢‹ª?hüùcÎúù•UØwÂtþ¦| ¿)«"J¥ºu]ãÏ!GYW玻¬‡0¿„)‚tK²J¢X²ïlü9ä°ëæê ×ñÅ€[ ÓùK˜î1A: RVM”KvQõK?fýÀZ¾ðá„éü%L÷ ¿)ë J¥»MõâÆŸK²žÙÒ° Âtþ¦{DÎ_‚”u¥À6¸Sõ²ÆŸOü[ÍÒÓùK˜îA:ùGŽu¥À¶ø¨ê%?§œmýjSÀÂtþ¦;LÎ_‚”u¥À6¹´ú?¯œ¾~¼:¶ÎO@˜Î_Ât ÒùK² ¢Ø6UOnüËż»úò5®pÂtþ¦;Ä_ˆùK²)¢ØVŸV½´1ç•TŸ°þOÍãðùK˜îæ/AÊ&‰R`›«¾¡zK›9Ÿ¼ªú¢|fptÏ_Ât‹ù 0 R6M”»àDõ-Õ«[Ïyä¥M—êzî(ÛÂãòùK˜n!þü%HA”»æ³«Ÿjþîé몧6]& ÛÈãóùkgÃt_PùDõ¬êKF²Å^T}iuÃèAØ;WU÷=Äš]\Ý4z`ã.ªî_=¼zhuŸêòê®ÕmNûu×TWWoª^S½¢é¥g®Úܨ°6§Ïweõeyœ¾hþfþ²CÊHvJ}u»ÑÀ†x¼>íìŽé.p€Ï_‚”ÑD)ì>Ûç/aº@ìùK²¢öƒÇïó—0]ôü%HY Q ûÃãøùK˜.€yþ¤,‰(€ýâñüü%LrÏ_‚”¥¥°<®Ÿ¿„éÜùK²D¢ö“Ç÷ó—0Ý ìü%HY*Q ûËãüùK˜n€uþ¤,™(€ýæñþüåñþ9@ ì>Q xÜ?yÜ¿L&ûA”åñÿ*–Çÿ+ä€t@²?D)pŠ˜¿tÀ 8ˆìQ œNÌ_z` ý#J€3é‚ùKÏÇ~¥ÀÙèƒùK‚ÎÇþ¥À¹è„ùK'€ÍÆ~¥Àùè…ùK/œ‡Ì¢¸Ý0醳p`9° D)p0úaþÒ§q@9 àQ ”Ž˜¿tD$|8Q †ž˜¿öº'@ 8“(KWÌ_{Ùœ(ŽB_Ì_{Õ œ‹(ŽJgÌ_{Ñ œ(æÐó×N÷†Ä"J€¹tÇüµ“ÝáÀp`ÀAˆR`ôÇüµSýá€p@ÀA‰R`UtÈüµâ@p ÀaˆR`•ôÈüµÕ=âØóŽ@”«¦K毭ìð{ú3‰R`ôÉüµU}â|ÏþÀa…D)°.:eþÚŠNñ½'а&¢X'½2-ºWüïø0l€(ÖM·Ì_‹ì°;ú &J€MÐ/ó×Êú墼ճ«/^ÁûÚWϯ_= vUuÏÑC¬Ù}ª›F,ÒÍÕ{ª=ì‰Õ³ª/=È{Qõ¥Õ sÞÉÜ(¤ó Rø}ˆR€ ¹¾zSõÚêÕKª?®n8ì*a:ßì0¥‚t>A N”œÝ{ªÿ\=£úÍ\q«$L盦GRA:Ÿ …L”\Ø[ªWýtuíàY`WÓùŽ¦ÇŽðÁé|‚8ªO¨~¬zcõ/s5X…“ÕWTÏ=Èû‚¦›GúæG‡RA:Ÿ Vá.ÕOV/¯8xØÂt¾#…éa¢ôDõ+ Ò9)°jŸ^½¬ú®VóÊ °Ï„é|‡ÓƒFé©k¬w„¡˜\Y=!A ¬Þ¥M—ôþruÛÁ³À¶¦ó*L¥—4]²ëI¿G÷üVðú=ð„ê·ª;޶ܩ0}þèA¶Ø4ml^r¡_x¡(½¸úÿrÉî.Ù6é³›^>F˜Â<'›Ç Ó£û⦞¼ø|¿èBQúMKv€>³éô‰ÑƒÀ–;¦.å=ºÇ7½„Õ9/J¿»é6ãKv€‘Õ´ÁÌãRÞù¾¡©/Ïê\wh{hõ'àú_ÎêÊêˤpXWU÷=ÀŽybÓåsÀ<§nþê^;Gó¦ÿ,{ñ™?q¶(½Cõ—Õ=Ö<Ô®òR8:Q °zïmzÓ7 žvÁ©—Éôª$GóƦóÑûNãÙ.ßý¾éQy)°4w¬~|ô°#NV_žç˜Õ=ªÿãÌ7ž¹Szßꕹl÷(ìÂ|vJÖç1Õ‹F¡ÉU¹¦IDAT;ÂŽéÑÝX= zí©7œ¹Súý Ò£°C ,Ýwîû‰‡cÇôè.iº:÷ƒNÒû6}a9wÙ¶ÁƒšvKÕ¸1wå=ªÇ7õgõáQúmÕñ³ÝìÛä;F;ÆŽéѯ¾õÔN]ÂqiõÖêcFL´¥¼ì ¬žç”¬×ÍÕ'Wo=ì˜Kªgçåbãï«»UןÚ)}t‚ô0\² l£cM—Í«åRÞÃûèêóêC—ï>vÜ,[Ç%»À6û¢ÑÀŽr)ïá}Q}(J?oà ÛÄ)°íQÝ~ô°£ì˜ΣkŠÒ˪O;ËV°C ì‚‹«v˜ÓƒûÄêãU=ɰC ìQ ëeÇôà|¬º×è)Î)°kÜéÖÏŽéÁÜóXõI£§X0;¤À.ºÇè`OØ1½°Ëå¥`ÎÅ)°«îŸ6é¯FTvL«þê¢êÒê=·~»O¼ì ,ÏÕkG°®¨^?zàƒ.©ž]}ÉèA6ìduÇcMQö§ƒ‡Ù4—ìÂ2½¾z×è!vÜ»ª7Œø0ûz)ï+ªŽÝúƒŽœdÃ\² ËuKûu>á7šÎ·À²ì㥼¿Qu*JŸ7pM²C Ë·oÿC°i/=pNû¶cúüª‹N{Ã˪‡™e#<‡¶Ã‰ê-Õ]F°ƒþ®º{ÁÒíÃsL_V=¼>´SZõ³cfÙ;¤°=NV¿8z€õóy<Û`vLÿßSß9}§ôÒ꯫»m|œõ²C Û粦óÑmG°Cn¨îY½mô ÀíêŽéÕMç£ëêÃwJo¨ž:b¢5²C Ûéê¦ÿÍ`u~.A ÛfWwLÿM·i}øNiMÏåzeÓkWm;;¤°ÝîR½®úÈуì€÷V÷múO?`ûìÒŽéUÕý;­ÓŽñ NVOÙäDkb‡¶ß»ªï=ÀŽø× RØf»´cú°Ó~¶éõ«¶q½°éù±Àö;VýNãÏ+–eYÛ¼þ :° .©žÓøóÊQ×Ïœí“:óòÝSnWýiÓeÛäùÕã›v|Ýp÷ê/ª;` ½»ú'Õ[G¬Ì‰êWªÇä^[=¤ºæÌŸ8óòÝS®©¾°éµ¬¶Å•Õ¤°kÞšËñŽâƦÇF‚vËÉêË«çŽäþ¾úâΤñ¨êÚÆoó^h=¯é €ÝõuÕM?ßX–emú©é¼ ì®M4ú|s¡umSWÎò¹-;LŸ“ …}ñM S˲¬ ­›šÎ—Àî;ѲŸczmSO®Ä?mzNÂèOêÌõ³ÕÅ«ú$­ð5Õõ?ÿX–e-q]ßtžöÇÅ-óFµïnêÈ•ºOõš|r·4=Gâ»Wý [ãÕ;.²,ËZÒzGÓùØOßÝÔI£ÏE·4uã}Öõ‰Þ¶úñÁŸà›ªÏ^×'lmºãöè“®eYÖÖoV—컇UohìùèÕí×ý‰V=ºz݆?¹“ÕS«;làó¶ÃEM7ò¸ºñ-˲F¬«›Îƒçz™?`ÿÜ¡©›N¶ÙóÑëš:q£NTOnºÍø:?¹›ªg¶}¯™ lΪ¬þ¡ñ-˲6±þ¡é¼w§Îî¾Mµî›D¾µ© ‡Þ|öÒ¦;¼½´Õ~rïnºTøŠÍ}*À–»SÓó)–òüw˲¬U¯×4çÄ(pPW4uÕªo\ûÒ¦¼t¾Ôã~M/Šú…ÕC;|-ÿMÓs"^xë·×¯t:`Ÿ|FõØê1ÕªãcÇ8’›ªWVWV/¨^6v`‹Ý¦éòÚ/¼õÛO<äï?Y½¢©ÕžW½zUƒ­óù—V¬>µº¼º{ÓõÍ·kz½š“ÕßVo¬®ªþ¬é®q«vûêÓ›.c¹¼úøê#šÎI^V X‚TïkzŒôö¦;¾¶úóêýãÆvØÇU®îUÝ£é&’'š#]ÓtNzkÓùèUÕ_V7¬cÿúR,Î)®ßIEND®B`‚alire-1.2.1/doc/catalog-format-spec.md000066400000000000000000001161511430264165500175410ustar00rootroot00000000000000# Catalog format specification ## Big picture Each release belonging to a crate is described as a TOML file. This file has minor differences depending on its location: a local manifest is found at the top-level directory of the sources of a project, in which case its named `alire.toml`, whereas a manifest found in an index (e.g., the community index), is named `-.toml`. Other than that, contents follow the same conventions and there are only slight differences (some fields are intended only for an index manifest, and cannot appear, or are optional, in a local manifest). These differences are highlighted in the following descriptions, where necessary. Each TOML description file contains exactly one release, except for the special external definitions that are described in their own section. ## Information encoding This section describes the various encodings used in this format to encode information. First, there are two kinds of data: atomic and composite. Atomic data designates values that cannot be decomposed. There are only two atomic data types: - mere strings (`"Hello, world!"`); - booleans (`true`, `false`); When a string denotes a relative path intended to be portable across operating systems, it must use forward slashes as directory separator: `"path/to/my/resource"`. We can then split composite data in two kinds: lists (TOML's arrays) and mappings (JSON's tables). Lists are just sequences of other values, for instance a list of strings: ```toml ["A", "B"] ``` Mappings are the traditional sets of associations from keys (here, always strings) to other values. For instance, the following represents a set of dependencies, with version constraints: ```toml libfoo = "^1.2" libbar = "^2.0 & /=2.1.3" # Excluding a known bad version ``` In some contexts, information can be dynamic: special encodings can be used to make data vary depending on the environment (OS, architecture, ...). The environment is represented as a set of specific variables which can have a specific set of values: see the [Parameters](#parameters) section below for a comprehensive list. All properties that support dynamic expressions follow the same structure, in which the expression (case-like) is inserted between the key and its value. For example, given a static expression: ```toml key = "value" ``` one of its cases would be expressed by the following inline TOML table: ```toml key.'case(var)'.var_value = "value" ``` Several expressions can be inserted between a property key and its value, leading to a combinatorial explosion if all cases have specific values. The equivalent to an `others` Ada clause in this format is a `'...'` entry. Here is an example of a conditional boolean value. ```toml {'case(distribution)' = { 'debian|ubuntu': true, '...': false }} # Or in a more idiomatic TOML syntax ['case(distribution)'] 'debian|ubuntu' = true '...' = false ``` Depending on the value of the `distribution` environment variable, this will return `true` (its value is `debian` or `ubuntu`) or `false` (for other values). Note that these and subsequent examples are not showing the left-hand-side property to which such a value would be assigned. A little variation allows building environment-dependent composite data. For instance, to make the dependency on `libbar` above dynamic: ```toml { "libfoo": "^1.2", "case(os)": { "linux": {"libbar": "^2.0"}, "windows": {"libwinbar": "^3.0"}, "...": {} } } # Or in a more idiomatic TOML syntax libfoo = "^1.2" ['case(os)'.linux] libbar = "^2.0" ['case(os)'.windows] libwinbar = "^3.0" ['case(os)'.'...'] ``` The `case(os)` part selects dependencies depending on the value of the `os` environment variable. If the `os` environment variable contains `linux`, this will create the following dependencies: ```toml libfoo = "^1.2" libbar = "^2.0" ``` If the `os` environment variable contains `windows`, this will create the following dependencies: ```toml libfoo = "^1.2" libwinbar = "^3.0" ``` And finally for other `os` values: ```toml libfoo = "^1.2" ``` ## Release Information This section describes the actual properties that must or can appear in a manifest file to describe a release. Unless specified, all the entries must be static, i.e. they cannot depend on the context. - `name`: mandatory string. The name of the crate this release belongs to. Use `alr help identifiers` to see the rules such names must follow. - `version`: mandatory string. The semantic version of the release. - `description`: mandatory string. One-line description about the package. For instance: ```toml description = "Library to handle foobars" ``` - `long-description`: optional free-form string to provide information about this package, in addition to `description`, without length restrictions. - `authors`: optional array of strings. Flat list of human-readable names for the authors, i.e. the people that wrote the software that is packaged. For instance: ```toml authors = ["Alice Example", "Bob For Instance "] ``` - `maintainers`: mandatory (for indexing) array of strings. Flat list of human-readable names (optional) for the maintainers, with a contact email (mandatory); i.e. the people that maintain the crate metadata in Alire. For instance: ```toml maintainers = ["alice@example.com", "Bob For Instance "] ``` - `maintainers-logins`: mandatory (for indexing) array of strings. Flat list of github login usernames used by the maintainers of the crate. This information is used to authorize crate modifications. For instance: ```toml maintainers-logins = ["alicehacks", "bobcoder"] ``` - `licenses`: mandatory (for indexing) string. A valid [SPDX expression](https://spdx.org/licenses/). Custom license identifiers are accepted with the format: `custom-[0-9a-zA-Z.-]+` ```toml licenses = "MIT" ``` For a double license: ```toml licenses = "GPL-3.0-only OR MIT" ``` For a custom license: ```toml licenses = "custom-my-license-1.2" ``` - `website`: optional string. URL to the original project's website. For instance: ```toml website = "https://myproject.example.org/" ``` - `tags`: optional array of strings. Flat list of topics covered by the crate. Tags will help users find crates related to their interests: ```toml tags = ["spark", "security"] ``` - `available`: optional dynamic boolean expression. Determines whether the package is available for the current platform (true) or not (false). For instance: ```toml [available.'case(distribution)'] 'debian|ubuntu' = true '...' = false ``` - `depends-on`: optional array of dynamic dependencies expressions. For instance: ```toml [[depends-on]] # A static dependency libfoo = "^1.2" [[depends-on]] # A dynamic dependency [depends-on.'case(os)'.linux] libbar = "^2.0" [depends-on.'case(os)'.windows] libwinbar = "^3.0" ``` Available constraint operators are the usual Ada relationals (`=`, `/=`, `>`, `>=`, `<`, `<=`) plus caret (`^`, any upwards version within the same major point) and tilde (\~, any upwards version within the same minor point). **Note that caret and tilde do not have any special behavior for pre-1 versions.** This means, for example, that `^0.2` will still mean any release below `1.0`. The Semver specification does not make any promises about the compatibility of pre-1 versions, and there are differing interpretations of these operators out there for such versions. Bear in mind this when expressing your restrictions; for pre-1 versions you most likely want to use `~0.x` constraints (compatibility within a minor version). Logical operators for and (&), or (|) are accepted; see the `Semantic_Versioning` project documentation on [extended version sets](https://github.com/alire-project/semantic_versioning#types). See also the [section on compiler dependencies](#compiler-versions-and-cross-compilers) for more details on how to use the `depends-on` property for cross-compiling or compiler version selection. - `project-files`: optional list of strings. Each is a path, relative to the root of the source directory, to a `.gpr` project file to be made available. Expressions are accepted. For instance: ```toml project-files = ["my_project.gpr", "utils/utils_for_my_project.gpr"] [project-files.'case(word-size)'] bits-64 = ["my_project.gpr"] bits-32 = ["my_project32.gpr"] ``` - `gpr-externals`: optional table, giving a mapping from the name of external variables in the `.gpr` project files to sets of possible values (as array of strings), or an empty string if this set is infinite. For instance: ```toml [gpr-externals] BUILD_MODE = ["debug", "profile", "release"] TAG = "" ``` - `gpr-set-externals`: optional dynamic table, setting values of project external variables when building the project. This should not be used to specify default values, the default values must be specified in the `.gpr` project file. Expressions are accepted before the mapping. For instance: ```toml [gpr-set-externals] BUILD_MODE = "release" [gpr-set-externals.'case(os)'] linux = { OS = "gnu-linux" } # Compact table syntax is convenient in this case windows = { OS = "ms-linux" } # to see all enumeration values, one per row. ``` - `environment`: optional dynamic table used to modify environment variables that will apply at build time. Variables and values are specified with the form `VARIABLE. = "value"`, where `` is one of `append`, `prepend`, or `set`. For instance: ```toml [environment] C_INCLUDE_PATH.append = "/usr/include/something" MY_PROJECT_ASSETS.set= "${CRATE_ROOT}/assets" PATH.append = "${DISTRIB_ROOT}/usr/bin" ``` Predefined variables are provided by Alire and will be replaced in the value: - `${CRATE_ROOT}` absolute path to the deployment directory of the crate. - `${DISTRIB_ROOT}` absolute path to the root directory of the system distribution. On UNIX systems it will be `/`, on Windows `msys2` it will be the `msys2` installation directory (e.g. `C:\Users\user_name\.cache\alire\msys2`). Environment entries can use dynamic expressions: ```toml [environment.'case(distribution)'] msys2 = { C_INCLUDE_PATH.append = "${DISTRIB_ROOT}/mingw64/include/SDL2" } ``` - `executables`: optional dynamic list of strings. Each one is the simple name of an executable provided by the package. Executables are looked for by `alr` in the build tree and must not include a path. If only one executable is given, it is considered the default for `alr run`. For instance: ```toml executables = ["my_main"] ``` - `actions`: optional dynamic list of actions to perform when certain events take place in a workspace. The general action syntax is: ```toml [[actions]] type = command = ``` `` is an array of strings for a shell command to run in the source directory. For events that cause a workspace-wide triggering of actions (all `pre_/post_` actions described next), the actions are invoked in a dependency-safe order, starting at the leaves of the dependency graph (releases with no dependencies) and moving up to the root release (the working release, or the release being obtained with `alr get`). In this context, the root release is considered part of the dependency solution, and so its actions are executed too, always in the last place. `` can be either: - `post-fetch`: the command is to be run whenever there are new sources deployed in the workspace, in any release in the solution. All releases `post-fetch` actions are run after the new deployment is complete. Initial retrieval, subsequent modification of dependencies, pinning a directory or repository is considered a deployment of new sources. A manual `alr update`, even if it results in no changes, will also trigger this action in every release in the solution. - `pre-build`: the command is to be run right before the build of the workspace starts. This kind of action is run for all releases in the solution. - `post-build`: the command is to be run right after a build has successfully completed. This kind of action is run for all releases in the solution. - `test`: the command is run on demand for crate testing within the Alire ecosystem (using `alr test`). This kind of action is run only for the root crate being tested, after its build succeeds, and after any `post-build` actions. Since actions may end being run more than once they should take this into account and allow multiple runs with the expected results intended by the packager. Actions accept dynamic expressions. For example: ```toml [[actions.'case(os)'.linux]] type = "post-fetch" command = ["make"] [[actions.'case(os)'.windows]] type = "post-fetch" command = ["cmd", "build"] [[actions.'case(os)'.'...']] # An explicit empty case alternative, which is not mandatory ``` - `auto-gpr-with`: optional Boolean value that specifies if the project (gpr) files of a crate can be automatically depended upon ('withed') directly by the root project file. (The default is true.) This feature is meant to simplify the process of using dependencies in Alire. However, not all project files are supposed to be direct dependencies. Some are intended to be extended, for example, and in that case a crate can disable the feature by setting `auto-gpr-with=false`. - `origin`: dynamic table. Mandatory for index manifests and forbidden in workspace manifests. This table describes how sources are obtained, using the following fields: - `url`: mandatory string which points to a source file or repository. - `hashes`: mandatory string array for source archives. An array of "kind:digest" fields that specify a hash kind and its value. Kinds accepted are: `sha512`. - `archive-name`: optional string. If `url` points to a source archive, this can specify the name of the file to download, which is needed in order to properly extract the sources, in case the URL does not identify it. - `commit`: mandatory string for VCS origins that describes the VCS-specific revision to be checked out (a git/hg hash, a svn revision). - `subdir`: optional relative path, only valid for repository origins, that when provided indicates that the crate is not located at the repository root. This option enables the possibility of publishing several crates from the same repository (sometimes referred to as a *monorepo*). Examples of origin tables: ```toml # Clone a git repository with a crate at its root [origin] url = "git+https://github.com/example-user/example-project" commit = "ec8b267bb8b777c6887059059924d823e9443439" ``` ```toml # Download and extract a source archive origin = "https://example.org/0123456789" archive-name = "archive.tar.gz" hashes = ["sha512:bf6082573dc537836ea8506a2c9a75dc7837440c35c5b02a52add52e38293640d99e90a9706690591f8899b8b4935824b195f230b3aa1c4da10911e3caf954c04ac"] ``` ```toml # Clone a git repository with the crate in a subdirectory [origin] url = "git+https://github.com/example-user/example-project" commit = "ec8b267bb8b777c6887059059924d823e9443439" subdir = "examples" ``` - `available`: optional dynamic boolean expression. If it evaluates to `false`, the package is not available for the current platform. - `notes`: optional string. Provides miscellaneous information about this release. For instance: ```json notes = "Experimental version" ``` - `configuration`: optional table to control crate configuration code generators: For more information on crate configuration, see [Using crate configuration](#using-crate-configuration). - `disabled`: Completely disable configuration code generation for the crate (default: `false`) - `output_dir`: Path to the directory where the configuration code will be generated, relative to the crate root (default: `config`). - `generate_ada`: Enable generation of Ada configuration (default: `true`). - `generate_gpr`: Enable generation of GPR file configuration (default: `true`). - `generate_c`: Enable generation of C configuration (default: `true`). - `auto_gpr_with`: Enabled generation of list of withed project in the GPR file configuration (default: `true`). - `configuration.variables`: optional table of crate configuration variable definitions. For more information on crate configuration, see [Using crate configuration](#using-crate-configuration). The keys of the table are names of the variables. Variable definitions themselves are tables with the following entries: - `type`: mandatory string which defines the type of the variable, it can be: - `String`: any string - `Boolean`: either `True` or `False` - `Enum`: enumeration type - `Integer`: an integer value that can be encoded in 64-bit - `Real`: a real value that can be encoded in IEEE 754 binary64 - `default`: optional default value for the variable. Will be used if no crates explicitly set a value for this variable. Must be a valid value for the type. - `first`: (optional) for `Real` and `Integer` types only. Defines the lower bound of valid values for the type (inclusive). - `last`: (optional) for `Real` and `Integer` types only. Defines the upper bound of valid values for the type (inclusive). - `values`: mandatory for `Enum` types. An array of strings containing all the possible values for the enumeration. Example: ```toml [configuration.variables] Device_Name = {type = "String", default = "no device name"} Print_Debug = {type = "Boolean", default = false} Debug_Level = {type = "Enum", values = ["Info", "Debug", "Warn", "Error"], default = "Warn"} Buffer_Size = {type = "Integer", first = 0, last = 1024, default = 256} Max_Power = {type = "Real", first = 0.0, last = 100.0, default = 50.0} ``` - `configuration.values` optional table of variables assignment: The keys of the table are crate names, and entries are sub-tables of `variable_name` and `value`. The type of the value has to match the definition of the variable type. Example: ```toml [configuration.values] crate_1.var1 = 42 crate_1.var2 = true crate_2.var1 = "Debug" ``` - `build-profiles`: optional table of strings that sets the build profile of crates in the solution. For more information on build profiles and switches, see [Build profiles and switches](#build-profiles-and-switches). There are 3 build profiles available in Alire: - `Development` - `Release` - `Validation` Example: ```toml [build-profiles] depend1 = "validation" # Set depend1 build profile to validation depend2 = "development" # Set depend2 build profile to development my_crate = "release" # Set my_crate build profile to release ``` A wildcard key can be used to set the build profile of all crates that are not otherwise specified: ```toml [build-profiles] "*" = "validation" # Set all build profiles to validation ``` - `build-switches`: optional table of build profile switches definitions. For more information on build profiles and switches, see [Build profiles and switches](#build-profiles-and-switches). The keys of the table are either build profiles or the wildcard `"*"`: - `Development` - `Release` - `Validation` The values are profile definitions, themselves tables with switch categories as keys and switches selection as values. This list of switch categories and their corresponding selection is as follow: - `Optimization` - `Performance` - `Size` - `Debug` - `Debug_Info` - `No` - `Yes` - `Runtime_Checks` - `None` - `Default` - `Overflow` - `Everything` - `Compile_Checks` - `None` - `Warnings` - `Errors` - `Contracts` - `No` - `Yes` - `Style_Checks` - `No` - `Yes` - `Ada_Version` - `Compiler_Default` - `Ada83` - `Ada95` - `Ada05` - `Ada12` - `Ada2022` - `GNAT_Extensions` For example, to enable all run-time checks in the release profile: ```toml [build-switches] release.runtime_checks = "Everything" ``` To disable style checks for all profiles: ```toml [build-switches] "*".style_checks = "No" ``` All switch categories also accept a custom list of switches, for instance: ```toml [build-switches] release.optimization = ["-O1"] validation.style_checks = ["-gnatyg"] ``` - `provides`: specifies a list of releases of another crate for which the current release is a drop-in replacement. I.e., the crate is either API-compatible or call-compatible, depending on how it is to be used (as a source library, or providing some command-line tool). Example: ```toml name = "foo" provides = ["bar=1.1"] # A crate depending on `bar^1` might find this `foo` release in its solution instead. ``` - `forbids`: an array of tables containing dependency specifications, just as the `depends-on` property. Releases matching one of the forbidden dependencies are prevented from appearing in a solution with the release doing the forbidding. There are two use cases for this property: 1. To codify known conflicts between releases for some reason (for example, sources with the same name). 2. To provide drop-in replacements for another crate, in conjunction with a `provides` field. In this case the release must both provide and forbid the crate for which it is a replacement. Example: ```toml name = "bar" version = "1.0" provides = [ "foo=1.0" ] [[forbids]] baz = "*" # This crate cannot coexist with ours for some reason foo = "*" # No other crate that provides foo is needed/allowed at the same time ``` ## Work-in-progress dependency overrides It is usual to develop several interdependent crates at the same time. In this scenario, it is often impractical to rely on indexed releases which are not intended to be modified. Instead, one would prefer to use a work-in-progress version of a crate to fulfill some dependency. Alire provides *pins* to support this use case. Pins override dependencies, they are intended to be used locally, and to be fulfilled by proper dependencies once a crate is ready to be published. The use of pins is based on two ideas: * Dependencies are given, as normally, in the `depends-on` array of the manifest, even for those dependencies to be pinned. This way, once the release is ready, pins are simply removed and the actual dependencies are used in their place. * Dependency overrides, aka *pins*, are given under the `[[pins]]` array of the manifest. Three kinds of pins are available, all of them with the syntax: `crate_name = { pin_attributes }` The specific pin kinds and their attributes are: * Pins to versions: used to force the use of a particular version of an indexed crate. * `version`: a string containing a single version to be used. * `crate_name = { version = "1.2+hotfix-1" }` * Pins to local crates: a local directory will fulfill the crate dependency, no matter what version is given in its local manifest. "Raw" Ada projects without an Alire manifest can be used too, as long as their project file matches the crate name and it is located in the directory given as override. * `path`: an absolute or relative path to the crate directory. * `crate_name = { path = "../my/wip/crate" }` For the common case of directories containing an Alire manifest, dependencies and pins will be included recursively in the build context. * Pins to git repositories: the repository will be cloned locally and its directory will be used as in the previous case. This pin may optionally include a commit to fix the checkout to be used, or a branch to track. Otherwise, the default branch will be used. Running `alr update` will refresh the checkout. * `url`: the URL of a git repository * `commit` (optional): a complete git commit hash. * `crate_name = { url = "https://my/repo.git" } # Updatable pin to default branch` * `crate_name = { url = "https://my/repo.git", branch="feature" } # Updatable pin` * `crate_name = { url = "https://my/repo.git", commit="abcdef..." } # Fixed pin` ### Using pins for crate testing Pins are also useful to have a separate test project that depends on your main crate. The recommended setup is as follows: ``` /path/to/my_crate ├── alire.toml └── tests └── alire.toml ``` I.e., a `tests` crate is initialized within the main `my_crate`. In `tests` manifest, you have a dependency and local relative path pin for `my_crate`: ```toml # tests/alire.toml [[depends-on]] my_crate = "*" # Any version of the main crate aunit = "*" # We can have dependencies for testing only [[pins]] my_crate = { path = ".." } # Overridden by the latest sources ``` Then, `my_crate` is published normally, and `tests` can be used locally for any kind of testing needed on `my_crate` without polluting `my_crate` manifest with test specifics (like extra dependencies used by the test setup). ## External releases The above information applies to regular releases distributed from sources (that is, the Ada projects whose distribution is the main Alire goal). Some special supporting releases also exist that are described differently. A release is considered "external" when it is not built from sources and, furthermore, its semantic version cannot be known until run time. Hence, the availability and version of these releases is detected by `alr`. Several definitions for these external releases may exist so they are defined in a manifest as a vector with key `external`: ```toml [[external]] # Common entries to all externals kind = "hint" # One of several predefined external kinds hint = "Please install SDL in your platform from source or system packages" # Specific external kind parameters might follow ``` All external kinds can define these regular properties: - `available`: when defined, it restricts the external detection to the given environment conditions. - `hint`: optional dynamic string containing an explanation for the user on how to make the external entity available. This explanation is shown on request with `alr show --external`, or after `alr get`, for any external dependency that could not be detected. ### External kinds: hints A plain undetectable external kind intended to simply serve as a hint. For crates that are known to be unavailable through Alire, it serves to provide a generic or customized hint to the user. It has no specific fields, other than the common ones just described. Its key is `"hint"`: ```toml [[external]] kind = "hint" # Identifies this external kind # Bare minimum external. Optionally, the hint/available fields can be used. ``` ### External kinds: command-line tools This external kind is used to describe commands that can be run in the system, and that are able to provide their own version via some particular invocation. Their specific fields are (all mandatory): ```toml kind = "version-output" # Identifies this external kind version-command = ["gnat", "--version"] # Invocation that will provide the version when the tool is available version-regexp = "^GNAT ([\\d\\.]+).*|^GNAT Community ([\\d]{4}).*" # TOML-escaped GNAT.Regpat-compatible regular expression. Parenthesized # matches will cause the matched expression to be parsed as the Semantic # Version of the tool. provides = "another_crate_name" # This crate will be equivalent to `another_crate_name` for the solver. The # version will be the same as detected for the current external. For example, # all GNAT compilers provide the "gnat" crate, and so there cannot be two # compilers in the same solution. ``` ### External kinds: system packages Systems that have their own package manager (e.g. Linux) can readily provide many complex dependencies still unpackaged as source code in Alire. Alire can use these on supported platforms (at this time, Debian & Ubuntu. Do not hesitate to contact us if you would like to maintain other distributions) during resolution. A system external gives a list of platform package names that supply the dependency natively. The platform package manager will be used to detect their availability and version. To that effect, the `origin` field is used (which can accept dynamic expressions in this context): ```toml kind = "system" # Identifies this external kind origin = ["libncursesada3", "libncursesada5"] # As versions appear this list will grow. To speed up detection, dynamic # expressions may become recommended for certain system packages. ``` For Ada pre-compiled system libraries that require the platform compiler for linking (e.g., in Debian/Ubuntu), and that cannot be used with other GNAT compilers, this should be expressed with the `available` property, e.g.: ```toml available.'case(toolchain)'.user = false # `available` defaults to true, so it is enough to flag the user toolchains ``` ## Parameters - `os`: name of the OS. Currently supported values are: `linux`, `macos` and `windows`. - `distribution`: name of the Linux distribution, or `none` if running on a different OS. Currently supported values are: `debian`, `ubuntu`. - `toolchain`: takes `system` value in distributions with the system Ada compiler first in PATH (GNAT FSF in Debian/Ubuntu), `user` otherwise (GNAT Community editions, other cross-target toolchains). - `word-size`: architecture word size. Currently supported values are: `bits-32`, `bits-64`, `bits-unknown` ## Using crate configuration `Alire` provides a mechanism for crates to expose a list of variables that can be set by other crates depending on them. The configuration variables will then be converted to Ada, C and GPR source files that can be used to change the behavior or feature set of the code. Let's start with a simple example. A crate named `test` can print debug log on the console. However printing on the console has a performance impact, for an embedded project it can even have a significant code size impact. Therefore it would be best if this logging can be disabled/enabled at compile time. To achieve this, a crate maintainer can define a configuration variable in the crate manifest `alire.toml`. The definition will be like so: ```toml [configuration.variables] Enable_Logs = {type = "Boolean", default = false} ``` A single variable of type `Boolean` with a default value of `false`. From this definition, `Alire` will generate various source files, including an Ada package specification: ```ada package Test_Config is Enable_Logs : constant Boolean := False; end Test_Config; ``` In the crate source code, this configuration package can be used like so: ```ada if Test_Config.Enable_Logs then Print_Log ("This is a log message."); end if; ``` If one of the crates depending on `test` sets the configuration variable to `true`, e.g.: ```toml [configuration.values] test.Enable_Logs = true ``` The constant value will change in the generated configuration package: ```ada package Test_Config is Enable_Logs : constant Boolean := True; end Test_Config; ``` Which will enable logging in the `test` crate. It is possible for multiple depending crates to set `test.Enable_Logs` to the same value, however if two depending crates set the variable to a different value then the configuration is invalid and `Alire` will print an error. If no depending crates set the `test.Enable_Logs` variable, then its default value is used. ### When to use crate configuration? Usually when something has to be static or known at compiler-time, either for performance or memory usage. ### When _not_ to use crate configuration? When the Ada languages provides a better alternative. There are many ways to provide an Ada API that will result in compile time optimization or static memory usage. For instance, discriminants are an effective way to let the user define the size of a buffer: ```ada type Buffered_Thing (Size : Positive) is private; private type Buffer_Array is array (Positive range <>) of Unsigned_8; type Buffered_Thing (Size : Positive) is record Buf : Buffer_Array (1 .. Size); end record; ``` With this definition, users are then able to allocate either statically, on the stack or on the heap depending on their project. ```ada Thing : Buffered_Thing (Size => 256); ``` ### Use cases #### Log levels Enumerations variables in crate configuration can be used to set a level of log verbosity: ```toml [configuration.variables] Log_Level = {type = "Enum", values = ["Info", "Debug", "Warn", "Error"], default = "Warn"} ``` #### Buffer size Integer variables can be used the define the size of a static buffer: ```toml [configuration.variables] Buffer_Size = {type = "Integer", first = 0, last = 1024, default = 256} ``` This is useful in particular for embedded projects where compile time memory usage is preferred over dynamic allocation. #### Server URL String variables can be used to define the URL of a website or service: ```toml [configuration.variables] URL_Name = {type = "String", default = "example.com"} ``` #### PID coefficients Real variables can be used for PID coefficients: ```toml [configuration.variables] Proportional = {type = "Real"} Integral = {type = "Real"} Derivative = {type = "Real"} ``` #### Worst case allocation Integer variable can be used to define The maximum length of file names in a file-system: ```toml [configuration.variables] Max_Filename_Length = {type = "Integer", first = 5, last = 128} ``` #### Select algorithm in GPR project file Crate configuration also generates a GPR project file, therefore it can be used to control which units are compiled in the project. ```toml [configuration.variables] Sort_Algorithm = {type = "Enum", values = ["bubble", "quick", "merge"]} ``` The generated GPR will look something like this: ```ada project Test_Config is type Sort_Algorith_Kind is ("bubble", "quick", "merge"); Sort_Algorith : Debug_Level_Kind := "quick"; end Test_Config; ``` It can be used in the main GPR file like so: ```ada package Naming is for Body ("Test.Sort") use "test-sort__" & Test_Config.Sort_Algorith; end Naming; ``` With the files `test-sort__bubble.adb`, `test-sort__quick.adb` and `test-sort__merge.adb` each implementing a different algorithm. ## Platform Specific Code In the crate configuration Alire also generates a few built-in values to identify the host platform: - `Alire_Host_OS` - `Alire_Host_Arch` - `Alire_Host_Distro` They can be used in the main GPR file to add a different source directory based on the OS. For instance: ```ada for Source_Dirs use ("src", "src/" & Test_Config.Alire_Host_OS); ``` with the following directory tree: ``` +-- src +-- host_specific.ads +-- linux | +-- host_specific.adb +-- macos | +-- host_specific.adb +-- windows +-- host_specific.adb ``` ## Build Profiles and Switches As part of crate configuration, Alire will generate a list of compiler switches in the configuration GPR file. The list of switches for a given crate is controlled from two features: - build-profiles - build-switches There are 3 build profiles available in Alire: - `Development` - `Release` - `Validation` By default, the root crate is in `Development` and the dependencies are in `Release`. The defaults can be overridden in two ways: - The build profile of the root crate can be changed with a switch to the `alr build` command: - `$ alr build --release` - `$ alr build --validation` - `$ alr build --development` (default) - In the root crate manifest, the build profile of each crate in the solution can be changed with the `[build-profiles]` table. This can be used, for instance, in a unit test crate to set the crate under test in `validation` profile, or to debug one of the dependencies. Example: ```toml [build-profiles] lib_under_test = "validation" lib_to_debug = "development" ``` Each crate can customize the compiler switches corresponding to its profiles using the `[build-switches]` table. In general, this should be avoided to preserve consistency in the ecosystem. However, there are cases where it makes sense for a crates to change its build switches. For instance, a SPARK crate that is proved to be safe from errors can disable run-time checks in all profiles: ```toml [build-switches] "*".runtime_checks = "none" ``` It is also possible to specify a custom list of compiler switches for a category: ```toml [build-switches] release.optimization = ["-O1", "-gnatn"] ``` ### Using switches in GPR file Alire will generate a list of switches in the crate configuration GPR file. It will look something like this: ```ada abstract project my_crate_Config is [...] Ada_Compiler_Switches := External_As_List ("ADAFLAGS", " ") & ( "-Os" -- Optimize for code size ,"-gnatn" -- Enable inlining ); [...] ``` In the main GPR file, "with" the crate config GPR and use the `Ada_Compiler_Switches` variable to define compiler switches: ```ada with "config/my_crate_config.gpr"; project My_Crate is [...] package Compiler is for Default_Switches ("Ada") use My_Crate_Config.Ada_Compiler_Switches; end Compiler; ``` ## Compiler versions and cross-compilers Dependencies in Alire are used also to deal with compiler versions and cross-compilers. Also related is the information on toolchains available in the [Toolchain management](./toolchains.md) document or via `alr help toolchains`. ### Excluding compiler versions One may know that a particular compiler version has a problem with some code. This may be expressed with dependencies on the generic `gnat` crate, which although is not found in the catalog, is a crate that all GNAT compilers provide. (Such a crate without actual releases, but provided by other crates, is called a virtual crate.) For example: ```toml gnat = ">=7" # We require a minimum compiler version gnat = "/=7.3" # We know a precise version is incompatible ``` Since only one dependency on a same crate may appear, the relational operators `&` (and), `|` (or) can be used instead: ```toml [[depends-on]] gnat = "/=7.3 & >=7" ``` ### Requesting a compiler for a concrete target The other use of compiler dependencies is to specify that a compiler for a particular target is needed. (Note that the project file **also** has to specify the proper target and runtime.) This way Alire can configure the appropriate environment for the build. For example: ```toml gnat_arm_elf = "*" # Any compiler targeting ARM ``` Dependencies on cross-compilers should **only** be used in crates that actually require a concrete target (e.g., final binaries) to avoid preventing their use as general libraries with any compiler. ## Further reading ## You can inspect [index files](https://github.com/alire-project/alire-index) to get an idea of how projects are included into the catalog. alire-1.2.1/doc/classes.graphml000066400000000000000000000265741430264165500164110ustar00rootroot00000000000000 Name Name Semantic Version Major Minor Patch Milestone Origin URL Hash Release Dependencies Properties Crate alire-1.2.1/doc/configuration.md000066400000000000000000000051171430264165500165570ustar00rootroot00000000000000# Configuration `alr` provides a generic mechanism to `list`, `get`, `set` or `unset` configuration options, either in a local or global context. Option names (keys) can use lowercase and uppercase alphanumeric characters from the Latin alphabet. Underscores and dashes can also be used except as the first or last character. Dot '.' is used to specify sub-categories, e.g. 'user.name' or 'user.email'. Option values can be integers, floats, Booleans (true or false), or strings. The type detection is automatic, e.g. 10 is integer, 10.1 is float, true is Boolean. You can force a value to be a string by using double-quotes, e.g. "10.1" or "true". Extra type checking is used for built-in options (see below). Specific config options: - `--list` List configuration options - `--show-origin` Show origin of configuration values in `--list` - `--get` Print value of a configuration option - `--set` Set a configuration option - `--unset` Unset a configuration option - `--global` Set and Unset global configuration instead of the local one - `--builtins-doc` Print Markdown list of built-in configuration options Examples: - `alr config --global --set my_option option_value` Will set a configuration option with the key `my_option` and the string value `option_value` in the global configuration file. - `alr config --get my_option` Will print the value configuration option `my_option` if it is defined, otherwise the command fails. ## Custom configuration options The `alr config` command allows you to set and get any combination of configuration option `key` and `value`. You can use this feature to store your own project related configuration, or implement tools that integrate in an `Alire` context. However, be careful when naming custom configuration options because `Alire` may use the same `key` in the future. We recommend using a distinctive sub-category name, for instance: `my_project.my_config_option`. ## Built-in configuration options The options used by `Alire` are pre-defined and documented. We call these options `built-ins`. A built-in option has a pre-defined type that is checked when setting or loading a configuration file. For instance: - `alr config --global --set user.email "This is not an email address"` will fail because the value tentatively assigned to `user.email` is not an email address. The built-ins also have a short description to document their type and usage. ## Built-ins list Here is the list of `Alire` built-in configuration options. You can also get this from `alr` with `alr help config`. alire-1.2.1/doc/getting-started.md000066400000000000000000000277131430264165500170230ustar00rootroot00000000000000# Getting Started ## Installation You can download the last release of Alire at the [GitHub repository](https://github.com/alire-project/alire/releases). ## `alr` on Linux On Linux, `Alire` is simply provided in an archive. Once the archive is extracted you have to add `alr` in the environment `PATH`: ```bash $ export PATH=/bin/:$PATH ``` Alire provides GNAT toolchains hosted on x86-64 for Linux. If those toolchains do not work for you, or if you are on another host architecture like ARM, you have the option to look at the GNAT toolchains from the Linux distribution. ## `alr` on Windows On Windows an installer is provided. The installer will create a shortcut to start `PowerShell` with `Alire` in the environment `PATH`. The first time you run `alr` the program will ask if you want to install [msys2](https://www.msys2.org/). This is recommended as `alr` will use `msys2` to automatically install required tools such as `git` or `make` that you would otherwise have to install manually. `msys2` will also provide external libraries required by some projects in the Alire index, allowing you to build more projects out of the box. Alire provides GNAT toolchains hosted on x86-64 for Windows. Those toolchains should work for all cases, if not, let us know. ## `alr` on macOS On macOS, `Alire` is simply provided in an archive. Once the archive is extracted you have to add `alr` in the environment `PATH`: ```bash $ export PATH=/bin/:$PATH ``` If you try to run it on recent versions of macOS, you will get a popup saying `“alr†cannot be opened because the developer cannot be verified.` and inviting you to move it to the bin. The way round this is to remove the quarantine attribute, ```console $ xattr -d com.apple.quarantine bin/alr ``` Alire provides GNAT toolchains hosted on x86-64 for macOS. If those toolchains do not work for you, or if you are on another host architecture like the Apple M1, you have the option to look at the GNAT toolchains from the community. ## `alr` for other platforms If `alr` is not available on your platform, you can try to build it from sources. Go to the [GitHub repository](https://github.com/alire-project/alire/) for more information. ## First steps The following miniguide shows how to obtain and build already packaged projects, and create your own. First, create or enter into some folder where you don't mind that new project folders are created by the `alr` tool Run `alr` without arguments to get a summary of available commands. Run `alr --help` for global options about verbosity. Run `alr help ` for more details about a command. ### Downloading, compiling and running an executable crate Obtaining an executable project already cataloged in Alire is straightforward. We'll demonstrate it with the `hello` project which is a plain "Hello, world!" application (or you can use the `hangman` or `eagle_lander` projects as funnier alternatives). Follow these steps: 1. Issue `alr get hello` 1. Enter the new folder you'll find under your current directory: `cd hello*` 1. Build and run the project with `alr run`. This will build and then launch the resulting executable. The first time you run this command, the `toolchain selection assistant` will ask you to select your preferred default toolchains (GNAT compiler and GPRbuild). For this getting started example, we recommend to just press enter twice to select the defaults. As a shorthand, you can use `alr get --build hello` to get and build the program in one step. ### Creating a new crate Alire allows you to initialize an empty binary or library crate with ease: 1. Issue `alr init --bin myproj` (you can use `--lib` for a library project) The first time you run this command, `alr` will ask a couple of questions to automatically fill-in information about the crate: - `GitHub login`: is used to identify the maintainer of the crate when contributed to the community index. - `Full name`: Name of the author of the crate - `Email address`: Point of contact to author of the crate All the questions are optional for now, you can just press enter to use the default values. The `alr init` command will create a basic `crate` structure in the `myproj` directory. 1. Enter the folder: `cd myproj` 1. Build the crate: `alr build` 1. Run the program: `alr run` We can now edit the sources of this executable in the `src/` directory. For instance, add a "Hello world" to `src/myproj.adb`: ```ada with Ada.Text_IO; procedure Myproj is begin Ada.Text_IO.Put_Line ("Hello, world!"); end Myproj; ``` Use `alr run` to build and run the program again: ```console $ alr run # Building myproj/myproj.gpr... Compile [Ada] myproj.adb Bind [gprbind] myproj.bexch [Ada] myproj.ali Link [link] myproj.adb Build finished successfully in 0.35 seconds. Hello, world! ``` ### The Alire manifest Besides the `alr` command, the main interface with Alire is the `manifest`. The manifest is a text file named `alire.toml` in the root directory of the crate. It contains all sorts of information about the crate, some mandatory such as the `name` and `version`, others optional like the `licenses`. Alire manifests are written in [TOML](https://toml.io) format. You can have a look at the manifest to get a idea of its content, but nothing has to be edited by hand so far. ## Dependencies and upgrading Alire keeps track of dependencies in the manifest (`alire.toml`) of your crate. Adding dependencies can be done with the `alr with` command: * `alr with crate_name` adds a dependency. You can immediately 'with' its packages in your code. * `alr with --del crate_name` removes a dependency. Alternatively you can edit the file to add dependencies and then issue: * `alr update`, which will fetch any modified dependencies in your project. Using `alr with` without arguments will show the current dependencies of your project. Using one of `--solve`, `--tree`, `--versions`, `--graph` will show different details about the complete solution needed to fulfill dependencies. ### Add a dependency Let's add a dependency to the `libhello` crate. ```console $ alr with libhello Requested changes: # libhello ^1.0.0 (add) Changes to dependency solution: + libhello 1.0.0 (new) Do you want to proceed? [Y] Yes [N] No (default is Yes) ``` `alr` is showing the new dependency solution, i.e. all the crates in the dependency graph and their version. Press enter to accept the new solution. `alr` will then download the sources of the `libhello` crate. ### Use the dependency You can now edit the `src/myproj.adb` source file again, and write this piece of code to call a function from the `libhello` crate: ```ada with Libhello; procedure Myproj is begin libhello.Hello_World; end Myproj; ``` Run `alr run` to build and run the new executable: ```console $ alr run # Building myproj/myproj.gpr... Setup [mkdir] object directory for project Libhello [mkdir] library directory for project Libhello Compile [Ada] myproj.adb [Ada] libhello.adb Build Libraries [gprlib] hello.lexch [archive] libhello.a [index] libhello.a Bind [gprbind] myproj.bexch [Ada] myproj.ali Link [link] myproj.adb Build finished successfully in 0.34 seconds. Hello, world! ``` As you can see, the `libhello` library sources are automatically built and linked in your program. ## Finding available projects For quick listing of crates and their descriptions you can use the `search` command with the `--crates` switch: * `alr search --crates [substring]` Otherwise, `search` will look into releases, providing more details about specific releases: * `alr search ` will look for `substring` in crate names. * `alr search --list` will list the latest release of every crate. * `alr search --list --full` will list all releases in the catalog. Even more details are obtained with: * `alr show ` This last command will show generic information. To see the one that specifically applies to your platform: * `alr show --system ` The list of projects and their descriptions are also available on the Alire website: * [alire.ada.dev](https://alire.ada.dev) ## Build environment To create a build environment, `alr` sets environment variables such as `GPR_PROJECT_PATH` before running `gprbuild`. If you want to run `gprbuild` yourself or inside an editor (GNAT Studio), you can use the `printenv` command to print the build environment: * `alr printenv` ## Troubleshooting By default `alr` is quite terse and will hide the output of subprocesses, mostly reporting in case of failure. If you hit any problem, increasing verbosity (`-v` or even `-vv`) is usually enough to get an idea of the root of the problem. Additionally, `-d` will show tracebacks of exceptions. ## Running tests `alr` comes with a test suite for self-checks. See the instructions in the [README](https://github.com/alire-project/alire/blob/master/testsuite/README.md) of the `testsuite` folder. Additionally, you can test in batch the building of crates in your platform with the `alr test` command. (See `alr test --help` output for instructions.) ## Migration of an existing Ada/SPARK project to Alire First you have to decide on a crate name for your project, this name will have to follow the naming rules of Alire. You can find those rules using the command: ```bash $ alr help identifiers ``` Avoid using `ada` as a prefix for your crate name, this will make the project harder to find in a list. `ada` suffix is ok when the project is a binding for an existing library (e.g. `sdlada`, `gtkada`). We will use the name `my_crate` as an example, and consider that the repository uses the same name. Clone your project repository and enter the directory: ```bash $ git clone https://github.com/github_login/my_crate.git $ cd my_crate ``` At this point you have a choice: 1. Let Alire generate a new GPR project file for you. This is recommended for most projects, and in particular if your project has simple code organization and GPR project file. One of the advantages is that Alire will create a GPR project file “standardized†for best integration in the ecosystem. 1. Keep your existing GPR project file. This is recommended for projects with complex GPR project file(s). ### 1: Using Alire GPR project file If you want Alire to generate a project you first have to delete the existing GPR project file: ```bash $ rm *.gpr ``` And then use `alr init` command to create a skeleton for your crate: For a library: ```bash $ alr init --in-place --lib my_crate ``` For an application: ```bash $ alr init --in-place --bin my_crate ``` If this is your first time using `alr init`, you will have to provide some information like your name and GitHub login. You can ignore the warnings such as `Cannot create '[...]/my_crate/src/my_crate.ads'`, Alire is trying to create a root package for your crate but you probably already have one. From this point you can edit the GPR project file to change the source dir or compilation flags, if needed. And then try to compile your crate with: ```bash $ alr build ``` ### 2: Using your own GPR project file(s) If you want to keep the existing GPR project file, use `alr init` with the `--no-skel` option to skip the project skeleton creation: For a library: ```bash $ alr init --in-place --no-skel --lib my_crate ``` For an application: ```bash $ alr init --in-place --no-skel --bin my_crate ``` If this is your first time using `alr init`, you will have to provide some information like your name and GitHub login. If your GPR project file does not match the crate name (i.e. `my_crate.gpr`), you have to add a `project-files` field in your `alire.toml` manifest. For instance: ```toml project-files = ["project_file.gpr"] ``` Although this is not recommended (see Best practices), you can have multiple GPR project files: ```toml project-files = ["project_file_1.gpr", "project_file_2.gpr"] ``` You can now compile your crate with: ```bash $ alr build ``` alire-1.2.1/doc/introduction.md000066400000000000000000000015121430264165500164240ustar00rootroot00000000000000# Introduction `Alire` is a source-based package manager for the Ada and SPARK programming languages. It is a way for developers to easily build upon projects (libraries or programs) shared by the community, but also to easily share their projects for others to build upon. In the Alire vocabulary, sources of projects/libraries/programs are provided by what is called a `crate`. A crate can depend on crates, and other crates can depend on it. For instance, the `libgpr` crate depends on the `xmlada` crate. Crates can have multiple dependencies, themselves having multiple dependencies. This forms a dependency graph. Alire's main task is to automatically fetch, build and upgrade the crates of the dependency graph so you don't have to do it by hand. The main interface into the `Alire` ecosystem is a command line tool called `alr`. alire-1.2.1/doc/policies.md000066400000000000000000000074071430264165500155230ustar00rootroot00000000000000# Policies ## Crate ownership Because Alire comes late in the history of the Ada and SPARK languages we will not apply a strict "first come, first served" policy on crate names. At least for the first months or years, we allow ourselves a degree of control on the projects/crates published in the index, with the following goals: - Long term support: Owner and maintainers of a project are most likely in the best position to maintain the corresponding Alire crate. - Respect the ownership of projects: Owner and maintainers of a project deserve to be credited for their work. - Avoid user confusion on the names of crates: Crate names should be clear with regard to the project they contain. For instance, do not try to impersonate existing crates or projects. To that end we will potentially reject a crate or transfer the ownership of a crate. We count on the goodwill of the contributors to help us conduct this moderation in a kind and courteous way. Do not submit a crate to the Alire index if you are not willing to comply with this policy. As the Alire project matures, we expect to do less moderating and potentially remove this policy in favor of a "first come, first served" policy. ## Release immutability A release (identified by a unique semantic version) is protected against changes by its integrity hashes. If errors are identified post-publication, a release could be withdrawn, or superseded by a new one (using the appropriate major/minor/patch/build version changes), but not modified. ## Best practices - Avoid using `ada` as a prefix for your crate name, this will make the project harder to find in a list. `ada` suffix is ok when the project is a binding for an existing library (e.g. `sdlada`, `gtkada`). - Split big projects in multiple crates: - If your project is a collection of components (like GNATcoll for instance) and each component has different dependencies, you should consider splitting the collection into multiple Alire crates. The components can still be maintained in the same repository and use the same release archive/commit (e.g. [gnatcoll_sqlite](https://alire.ada.dev/crates/gnatcoll_sqlite), [gnatcoll_sql](https://alire.ada.dev/crates/gnatcoll_sql), [gnatcoll_postgres](https://alire.ada.dev/crates/gnatcoll_postgres)). - If your project is an application/executable/tool, some parts of the application may be interesting on their own and could benefit the ecosystem. For instance a parser for a standard file format would be useful across projects. - GPR project file clashes: to prevent issues when combining the GPR project files of different crates, we recommend to follow the rules below: - Use a project file name that matches the name of the crate (e.g. `my_crate.gpr` for a crate named `my_crate`) - Avoid using multiple GPR project files for a single crate - Avoid using common names for GPR project files such as `shared.gpr`, `common.gpr`, `config.gpr`, etc. - Prefix GPR scenario variables with the name of your crate: ``` Build_Mode := External ("MY_CRATE_BUILD_MODE", "release"); ``` - Avoid common names for GPR scenario variables such as `OS`, `TARGET`, `BUILD_MODE`, `MODE`, etc. - For library projects, do use the "standard" `LIBRARY_TYPE` external, but wrap it in a crate specific external: ``` type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := external ("MY_CRATE_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); for Library_Kind use Library_Type; ``` Having the `MY_CRATE_LIBRARY_TYPE` external will allow users to override the value `LIBRARY_TYPE` just for this crate, if need be. alire-1.2.1/doc/publishing.md000066400000000000000000000277741430264165500160710ustar00rootroot00000000000000# Publishing your projects in Alire Publishing a project in Alire is done with the help of the `alr publish` command. The steps to take are described after some introductory concepts (jump to these steps directly [here](#detailed-steps); you can also ask for help on the [gitter channel](https://gitter.im/ada-lang/Alire) of the project. ## General concepts The community index is a collection of [TOML](https://github.com/toml-lang/toml) files stored in the [alire-index](https://github.com/alire-project/alire-index) repository, under the [index](https://github.com/alire-project/alire-index/blob/master/index) directory. Each file contains a release for a crate and is named after the crate and version it contains. A file contains the description of a release, with other metadata. The complete specification of such TOML files is available in this [document](catalog-format-spec.md). ## New crates and releases Publishing a new crate is achieved through a pull-request against the index repository, in which the TOML file for the release must be provided. ### Index branches The community index is supported through two kinds of branches: - `stable-x.x.x` branches are used by stable versions of `alr`. - `devel-x.x.x` branches are used to introduce breaking changes in the index format, during the development of `alr`. Your `alr` version knows which branch to use, so you do not need to manually select one. When using `alr publish` to assist on creating a release, you will be provided with an upload link for the branch your `alr` is using. However, when submitting releases manually, you must decide to which branch they will be added: selecting the latest stable branch results in the release becoming immediately available to the latest stable `alr`. Conversely, using the latest development branch will make the releases available for testing by unstable clients, and will become generally available with the next stable release of `alr`. Note that, as of this writing, only development branches exist, until the first stable release of `alr` is made. ## Checks on contributions Each crate is "owned" by a list of maintainers, provided with the `maintainers-logins` property of the crate file. After the initial submission, which will be manually approved (see the [policies](policies.md) for details), the maintainers of a crate are the only people allowed to submit new releases or metadata modifications to the corresponding crate. Other checks your submission will go through are: - It contains all required metadata. - It builds on all of our CI configurations. - You can disable an unsupported target with the `available` property. ## Detailed steps Depending on how you develop your project, you can use one of the following methods to prepare your release submission: ### Starting from a git repository that contains an Alire workspace For this common use case, you need: - A git repository that is clean an up-to-date with its remote. - The repository already contains the release you want to publish. - The commit with the release must exist both locally and at the remote. - The repository must also be an Alire-enabled workspace: - It contains a top-level `alire.toml` manifest describing the release. - The remote host must be one of a few trusted major open-source sites. - This requirement is motivated by vulnerabilities identified with SHA1, whose migration to a stronger hash is [not yet complete] (https://git-scm.com/docs/hash-function-transition/) in `git`. - `alr` will inform you if your host is not supported. Please contact us if you think a site should be allowed. The complete list can be consulted by running `alr publish --trusted-sites`. - This is a temporary measure until more sophisticated publishing automation is supported. See the [Remote Source Archive](#remote-source-archive) case for alternatives to this scenario (you are not forced to change your code hosting, or even have an online repository). By default, the last commit is used for the release. You can alternatively provide another commit, tag, or branch. In any case, the git revision will be used to obtain a final commit. That is, a release cannot evolve with a branch, or be updated by moving a tag. - Within the repository, issue `alr publish` to use the last commit. You can, alternatively, issue: `alr publish . ` Note the path between `publish` and your non-commit revision. Likewise, you can run this command from outside your repository, as long as you supply the proper path to it. At this point, `alr publish` will carry out a few tests and, if everything checks out, it will create a `${repo_root}/alire/releases/crate-version.toml` file. This file must be submitted to the community index via a PR. A link for conveniently creating this PR will also be provided by `alr`: - Upload the generated index manifest file (`crate-version.toml`) to the supplied page link on github and create a pull-request. ### Starting with a remote repository, without local clone This case is analogous to the previous one, but you don't need the local repository. The same considerations about allowed hosts discussed in the previous scenario apply: - The repository already contains the commit with release you want to publish. - The repository must also be an Alire-enabled workspace: - It contains a top-level `alire.toml` manifest describing the release. - The remote host must be one of a few trusted major open-source sites. - This requirement is motivated by vulnerabilities identified with SHA1, whose migration to a stronger hash is [not yet complete] (https://git-scm.com/docs/hash-function-transition/) in `git`. - `alr` will inform you if your host is not supported. Please contact us if you think a site should be allowed. The complete list can be consulted by running `alr publish --trusted-sites`. The only difference when invoking `alr` is that you must supply the remote URL and commit (not a tag or branch). The commit must exist in the repository: `alr publish ` The checks will be carried out and the outcome will be the same as in the previous scenario. ### Starting with a remote source archive This case can be used when you use another VCS other than `git`, or do not work with an online repository. In this use case, you start from an already prepared final remote tarball/zipball: - The archive **must** contain a single directory (name not important) containing, in turn, the sources. This is the kind of archives automatically generated by GitHub, GitLab, Sourceforge... or through `git archive`. - The `alire.toml` manifest must be placed at the top-level with the rest of your sources (inside the same single directory just described), containing all required information except for the `[origin]` table, which will be created by `alr`. - This archive **must not** contain the `alire` directory generated by `alr` in working directories. The `alire` directory is designed to be put in your VCS ignore list. With the source archive already uploaded to the online host where it is going to be served (there are no restrictions on this host), you should issue `alr publish ` and the publishing process will carry on as in the previous cases, performing the checks and providing you with a file to submit to the index, and an upload URL to do so. ### Starting with a local source folder Invoking `alr publish --tar` inside an Alire workspace will result in the creation of a source archive at `${CRATE_ROOT}/alire/archives/`. This archive must be manually uploaded (for now) by the user to a publicly accessible hosting service. After the upload, the user can supply the URL to fetch this archive to the publishing assistant (which will be waiting for this information), and the assistant will resume as if it had been invoked with `alr publish ` (see #starting-with-a-remote-source-archive). ### Support for complex projects whose sources become multiple Alire crates In case your project does not easily map to a single Alire crate (e.g., because you manage multiple project files with different dependencies, or there are other reasons to keep the sources together even if they generate several crates), you have several options. The simplest one is to store each crate in a subdirectory within the repository, with its corresponding Alire manifest, sources and project files. With the repository up-to-date with the remote, and the local copy checked out at the desired commit, issuing `alr publish` in each subdirectory will properly recognize that the crate is nested below the repository root. Furthermore, when using this method, all nested crates will share the same storage when retrieved as dependencies. A similar alternative would be to publish each crate relying on source archives In this case you can use `alr publish --tar` normally inside each subdirectory. Compared with the previous options, there is no disadvantage to this method if you favor source archives. Another possibility would be to use a bit of scripting to create temporary subfolders with the described organization, and again using `alr publish --tar` normally. Finally, the `alr publish` command provides a `--manifest ` switch to work in place with several crates. You can have different manifests at custom locations (other than the expected `./alire.toml`) and provide each one in turn with the `--manifest` switch to create their respective crate. In this case, `alr` temporarily uses the given file as the root manifest, so all sources will be packaged for each crate. This is a bit wasteful, but as long as each crate's project files are properly defined (no shared sources), this remains an option to split the sources into crates. With the current support for autodetection of crates in subdirectories, this option is not recommended for new repositories. ### Starting from other configurations If your case does not fit well into any of the situations above we definitely want to hear about it, to see how it can be brought into existing or new Alire workflows. ### Creating the PR via cloning. Instead of uploading the generated index manifest file via the github upload link, you can follow the usual procedure to submit a PR to a github repository: 1. Fork the community index to your GitHub account. 1. Clone your fork locally and place generated manifest at the intended folder. 1. Commit and push the changes to your fork. 1. Create the pull request from your fork against the community repository through the GitHub web interface (or the [`hub`](https://github.com/github/hub) tool). 1. The base branch you select for the pull request will determine where your changes will become available; see the section on [index branches](#index-branches) for details. ## Publishing outcome Once the pull request is verified and merged, the new release will become available for normal use. The open source Ada ecosystem needs all the help it can get, so thank you for contributing! ## ALR Badge If you like, you can add a nice, shiny badge to your project page which links back to the [Alire website](https://alire.ada.dev). This can even serve as a reminder to republish your project once you published a new release, because the badge shows the latest version of your project that is known to Alire. The [Alire website](https://alire.ada.dev) is updated once a day, every day. Hence, after we accepted and merged your pull request, it might take up to a day for your changes to appear there, usually less. To add the badge, all you need to do is add the line ``` [![Alire](https://img.shields.io/endpoint?url=https://alire.ada.dev/badges/YOUR_CRATE.json)](https://alire.ada.dev/crates/YOUR_CRATE.html) ``` to your `README.md`. Of course, you need to replace the string `YOUR_CRATE` with your actual project's crate name. Here's an example: ``` [![Alire](https://img.shields.io/endpoint?url=https://alire.ada.dev/badges/hal.json)](https://alire.ada.dev/crates/hal.html) ``` This will be shown as: [![Alire](https://img.shields.io/endpoint?url=https://alire.ada.dev/badges/hal.json)](https://alire.ada.dev/crates/hal.html) alire-1.2.1/doc/toolchains.md000066400000000000000000000066161430264165500160600ustar00rootroot00000000000000# Toolchain management Toolchains are comprised by a GNAT compiler and a `gprbuild` project file processor. Alire strives to simplify the availability of GNAT releases, which are packaged to be retrieved and used with ease. The user can now select a preferred compiler via `alr toolchain --select`. Releases may still override this selection (for example to use a cross-compiler). There are two kind of dependencies on GNAT compilers: generic dependencies on the `gnat` crate, which apply to every compiler, and dependencies on a precise native or cross-compiler. The native compiler for each platform is always `gnat_native`, whereas cross-compilers follow the naming convention `gnat_` (e.g., `gnat_riscv_elf`). Alire will only offer to install valid cross-compilers for the host platform. ## Identifying available compilers Compilers available for download can be listed with `alr search --full --external-detect gnat_`. They will also be shown by the selection assistant, `alr toolchain --select`. Running `alr toolchain` without arguments will show the installed compilers and the preferred compiler, if any. ## Manual compiler installation Besides selecting a default compiler with `alr toolchain --select`, the user may install other compilers via `alr toolchain --install`. Installed but unselected compilers will not be used, though, unless a crate explicitly requests them via dependencies. Compilers can be removed with `alr toolchain --uninstall`. ## Automatic compiler installation If a crate requires a target-specific compiler via its dependencies, `alr` will attempt to use first a matching installed compiler. Otherwise, a matching compiler will be automatically downloaded. Generic dependencies on `gnat` will never cause a compiler download. ## Automatic compiler selection by Alire When a build is launched, or `alr printenv` is run to obtain a build environment, `alr` will use the available compilers as follows: 1. Any target-specific compiler needed due to dependencies will be selected. 1. Otherwise, if the user has defined a preferred compiler, it will be selected. 1. If no preferred compiler has been defined, Alire will rely on the existing user environment. ## Specifying dependencies on GNAT compilers for crate publishing From the point of view of a user preparing a release for publication, these are the considerations to bear in mind: - Do not use any dependency on a compiler if you do not have a reason to do so. - Use dependencies on `gnat` to specify known compiler version restrictions. - Use dependencies on a precise gnat cross-compiler (e.g., `gnat_riscv_elf`) when your crate is purposely only available for such a target. - It is normally not necessary to specify a dependency on the native compiler (`gnat_native`) as that would unnecessarily limit the availability of a library crate that might be useful to dependent cross-target crates. - It may be useful to depend on `gnat_native` in cases where a crate builds a tool to be used always in the host platform, for example to be used in some action during the build process. ## Note about cross-compilation Independently of the compiler made available by `alr` in the environment, the crate project file still must define an appropriate `Target` attribute for the desired compiler. At the moment, Alire does not examine project file contents to identify necessary compilers, and relies only on regular `depends-on` dependencies. alire-1.2.1/doc/user-changes.md000066400000000000000000000520631430264165500162760ustar00rootroot00000000000000# User-facing changes log This document is a development diary summarizing changes in `alr` that notably affect the user experience. It is intended as a one-stop point for users to stay on top of `alr` new features. ## Release 1.2 ### New subcommand for listing and manual triggering of actions PR [#983](https://github.com/alire-project/alire/pull/983) Actions defined in a working release can be listed now with `alr action`. A specific kind of action can be triggered by specifying its kind. Actions in the complete dependency tree can be listed and triggered with the `--recursive` switch. ```console $ alr action # Display actions defined in the root release $ alr action --recursive # Display all actions in the root and dependencies $ alr action post-build # Run post-build actions in the root release $ alr action post-build -r # Run post-build actions in the root and dependencies ``` ### Support for crates in repository subfolders (monorepos) PR [#939](https://github.com/alire-project/alire/pull/939) A crate can now be located nested within a repository and still be published as a repository origin. This enables simpler publishing of such crates, as `alr publish` will automatically recognize the situation. For example, let us say we have this structure: ``` my_repo +-- my_crate +-- my_crate_examples ``` Running `alr publish` at `./git_repo/my_crate` or `./git_repo/my_crate_examples` will detect that the crate is not at the root and adjust the origin metadata to take into account the extra path. Other typical hierarchies that should likewise work are: ``` my_crate (also a repository) +-- examples my_repo +-- crate1 +-- examples +-- crate2 +-- examples ``` At this time `alr publish` will not remove pins, so that is still a manual adjustment that the user may have to perform prior to publishing; that is, the manifest at each nested crate must be manually readied for publishing (just as for any other regular crate). ### Root crate build profile PR [#896](https://github.com/alire-project/alire/pull/896) The default build profile for the root crate is `Development`. This can be changed with the `--release`, `--validation` and `--development` switches for `alr build`. ```console $ alr build --release # build with release profile $ alr build --validation # build with validation profile $ alr build --development # build with development profile $ alr build # build with development profile ``` ### Build profiles and switches PR [#895](https://github.com/alire-project/alire/pull/895) As part of the crate configuration feature, Alire will generate a list of compiler switches in the configuration GPR file. The list of switches is controlled from two features: - build-profiles - build-switches ### User defined command aliases PR [#853](https://github.com/alire-project/alire/pull/853) It is now possible to define in configuration (local or global) aliases for the `alr` commands. ```console $ alr config --set --global alias.graph 'show --graph' $ alr graph ``` Will run the `alr show` command with the `--graph` switch. ### New command `alr exec -- ` PR [#853](https://github.com/alire-project/alire/pull/853) This new command takes an executable and arguments and run them in the Alire environment/context of the current crate. ```console $ alr exec -- sh -c 'echo ${ALIRE}' True ``` ### Pass alr clean switches to gprclean PR [#853](https://github.com/alire-project/alire/pull/853) Using the `--` delimiter the switches and arguments for `alr clean` can now be passed to the underlying `gprclean` execution. For instance: ```console $ alr clean -- -XTEST=42 ``` ### Pass alr build switches to gprbuild PR [#850](https://github.com/alire-project/alire/pull/850) Using the `--` delimiter, the switches and arguments for `alr build` are now passed to the underlying `gprbuild` execution. For instance: ```console $ alr build -- -f ``` will force recompilation. ### Global switches only allowed before sub-command PR [#850](https://github.com/alire-project/alire/pull/850) Before this change the global switches (`-f`, `-n`, `--config=`, etc.) could be placed anywhere on the command line. For instance, the following two commands were equivalent: ```console $ alr -f show $ alr show -f ``` Global switches are now only allowed before the sub-command name. Such that: ```console $ alr -f show # Is OK $ alr show -f # Is not OK (unrecognized option '-f' for 'show') ``` ## Release `1.1` ### Lockfile moved to `alire` folder PR [#789](https://github.com/alire-project/alire/pull/789) The lock file (`alire.lock`) is now a purely internal file, regenerated as needed from scratch, and needs not be put under version control. Since, furthermore, this file is not intended for user edition or inspection, it is now created inside the `alire` folder of a crate. Existing lock files at the root of a crate will be automatically migrated to their new location the first time an `alr` command that uses the lock file is run inside a crate with the old situation. This change obsoletes the recommendation that accompanied PR [#501](https://github.com/alire-project/alire/pull/501) about putting the lock file under version control. ### Conflicting releases PR [#781](https://github.com/alire-project/alire/pull/781) For releases that have known incompatibilities (duplicated source names, drop-in equivalent crates), it is now possible to express this information through a `forbids` table array, with the same syntax as dependencies. For example: ``` [[forbids]] conflicting_crate = "^1" ``` Releases related by a `forbids` property will not appear simultaneously as dependencies in a solution, as the solver will discard these combinations. ### Toolchain management PR [#775](https://github.com/alire-project/alire/pull/775) A variety of GNAT compilers (native and cross-target) is now available through Alire. These compilers are managed with the `alr toolchain` new command. The available compilers can be listed with `alr search --full gnat_`. Toolchain configuration is common to all crates in the active configuration prefix (which can be switched with the global `-c` option or by providing a path with the `ALR_CONFIG` environment variable). The `alr toolchain --select` subcommand allows selecting the preferred default compiler (or none at all, to continue using the previous mode of operation) for crates that do not specify one. Crates that require a particular cross-compiler may now specify it as a regular dependency on, e.g., `gnat_riscv_elf`. In addition to a default compiler, the preferred version of a compiler for a target may be made available with `alr toolchain --install `. When launching a build, Alire will use preferably the default selected compiler or, if the default is for a different target, one of the other installed compilers. If no installed compiler is available for the crate target, Alire will offer to download the appropriate cross-target compiler. Finally, running `alr toolchain` without arguments will list the currently installed compilers and gprbuild versions. ### Pins to git branches PR [#754](https://github.com/alire-project/alire/pull/754) A new option for remote pins exist to track branches: ``` [[pins]] wip = { url = "https://gitrepo.com/wip.git" branch="feature" } ``` Running `alr update` will pull any changes from the branch. ### Pins stored in the manifest PR [#743](https://github.com/alire-project/alire/pull/743). The options to modify pins through the command-line (`with --use`, `alr pin [--unpin] crate` have been disabled in favor of direct edition of the manifest. This way, pins are more robust against lockfile format changes. These kinds of pins exist: ``` [[pins]] foo = { version = "1.3.2+bugfix" } # Require a specific version bar = { path = "../my/bar" } # Use a local crate to override a dependency baz = { url = "https://github.com/baz.git" } # No commit, will use HEAD, will update on `alr update` gru = { url = "https://gitlab.com/gru.git" commit="123456890abcdef..." } # Explicit commit, won't update ``` ### Automatic GPR 'with' now in crate configuration PR [#740](https://github.com/alire-project/alire/pull/740). When adding or removing dependency with `alr with`, the list of `with` statement for each project files of the dependencies is now automatically added to the GPR crate configuration file instead of the root project file. ### Git remotes for pinned releases PR [#715](https://github.com/alire-project/alire/pull/715) The pinning commands (`alr with --use`, `alr pin --use`) now also accept a git repository URL, which will be downloaded and used to override a dependency, as previously could be done only with local directories. The pinning feature works recursively, so unpublished crates can now have complete dependencies prior to submission to the community index (which relies only on indexed dependencies). ### Switch to help with publishing of multi-crate repositories PR [#635](https://github.com/alire-project/alire/pull/635). The `alr publish` command now supports a new `--manifest ` switch, to help with packaging sources that provide several crates. Maintainers can now prepare different manifest files for the corresponding crates, and select each one in turn for publishing, without the repository itself being an actual Alire crate. Source management must still be taken care of by maintainers; sources should not be shared by project files in different crates intended to be simultaneously included. ### Configuration of crates PR [#699](https://github.com/alire-project/alire/pull/679). PR [#673](https://github.com/alire-project/alire/pull/673). Pre-compilation parameterization of source files can be now achieved by declaring variables and initial constant values for these variables in the Alire manifests. This allows customizing code in both the root crate and dependencies. For example: ```toml [configuration.variables] Device_Name = {type = "String", default = "no device name"} Debug_Level = {type = "Enum", values = ["Info", "Debug", "Warn", "Error"], default = "Warn"} Buffer_Size = {type = "Integer", first = 0, last = 1024, default = 256} [configuration.values] crate_1.var1 = 42 crate_1.var2 = true crate_2.var1 = "Debug" ``` Check more examples and details in the catalog specification section ["Using configuration"](https://github.com/mosteo/alire/blob/master/doc/catalog-format-spec.md#using-crate-configuration). ## Release `1.0` ### Narrow down versions for dependencies given without restrictions PR [#675](https://github.com/alire-project/alire/pull/675). When a user requests a dependency without narrowing down its version set (e.g., `alr with foo`), the solved version will be used to instead add an "update-safe" dependency (e.g., `foo^1.x`, `foo~0.x`). To truly request any version, this can be explicitly entered as `alr with 'foo>=0'`. This behavior can be disabled by setting the `solver.autonarrow` configuration option to false. ### The command `alr list` has been renamed to `alr search --crates` PR [#671](https://github.com/alire-project/alire/pull/671). To consolidate search functionality under the single `alr search` command, the old behavior of `alr list` can now be achieved with `alr search --crates`. By default, `alr search` looks into releases, but now it can look too into crates with the new `--crates` switch. ### Document caret/tilde use for pre-1.0 versions, and warn about it PR [#669](https://github.com/alire-project/alire/pull/669). Alire does not change the meaning of caret (^) and tilde (~) operators for pre/post-1.0 versions. This interpretation has been clarified in the catalog specification, and `alr` will warn about any suspicious usage. This warning may be disabled by the user with the new `warning.caret` configuration option. ### Do not perform build relocations PR [#667](https://github.com/alire-project/alire/pull/667). GPRBuild machinery for build relocation is incompatible with some use cases, so now all builds are performed in place, using the locations given in project files. This should only have a user-visible impact for pinned dependencies, which will see changes in their build directory when Alire builds for dependent crates are run. ### Switch to check for unknown enumeration values in the index PR [#656](https://github.com/alire-project/alire/pull/656). To allow backwards-compatible use of new supported environment configurations in the index, unknown values in dynamic case expressions are silently ignored when loading an index. In order to allow pinpointing these values (or truly wrong entries), a new switch `alr index --check` can be used that will reject an index containing unknown values. This error, either in indexes or a local manifest, can be downgraded to a warning with `--force`. ### Switch manifest `licenses` field to SPDX expressions PR [#629](https://github.com/alire-project/alire/pull/629). The `licenses` in crate manifests now expects a valid [SPDX expression](https://spdx.org/licenses/). Custom license identifiers are accepted with the format: `custom-[0-9a-zA-Z.-]+`. Example: ```toml licenses = "MIT OR custom-my-own-license" ``` For the `1.x` release, usage of the previous `licenses` format is obsolete and will trigger a warning. In future major releases this format will not be accepted at all. ### Custom editor command for `alr edit` PR [#611](https://github.com/alire-project/alire/pull/611). The code editor launched by `alr edit` can now be configured instead of using the hard-coded GNATstudio. Use `alr config --set --global editor.cmd " "` for custom editor and command line arguments. The token ${GPR_FILE} is replaced by a path to the project file to open. For instance: ```shell $ alr config --set --global editor.cmd "emacs ${GPR_FILE}" ``` The default editor is still GNATstudio. ## Release `0.7-beta` ### Assistance to generate and publish as tarball PR [#529](https://github.com/alire-project/alire/pull/529). By using `alr publish --tar`, the publishing assistant starts with the creation of a tarball of the sources in an Alire workspace. The user must upload this tarball to an online location, after which the assistant proceeds as if it had been invoked with `alr publish http[s]://url/to/tarball.tgz`. ### First publishing assistant PR [#527](https://github.com/alire-project/alire/pull/527). A new publishing assistant can be invoked with `alr publish [URL [commit]]`. At this time, the assistant requires that all necessary metadata for a release, excepting the `[origin]` table, is informed in the `alire.toml` file. The assistant has local and remote modes of operation. In the local mode, the user invokes the assistant from within a repository on its computer that is up-to-date with its remote, and that contains an Alire workspace. In this case, it is enough to run `alr publish`. In the remote mode, the user must prepare a source file or repository in their final online locations, and use `alr publish []`, with the commit being mandatory for repositories and not needed for source archives. In all cases, `alr` will fetch the sources, perform a few checks on the completeness of the information, and generate a final metadata file, intended to be submitted to the community index via pull request. An upload link is provided for convenience that can be used to create this pull request. Complete information about this feature is available in the updated [Publishing](publishing.md) page. Other features of the assistant are that, in the local mode, a branch or tag can be specified to pinpoint a commit, and that the test build of the crate can be skipped with `--skip-build`. ### Move manifest and lock files to top-level folder PR [#501](https://github.com/alire-project/alire/pull/501). The metadata information about a crate/release has been reworked to simplify user workflows and internal operation. Metadata is stored in the manifest file, which as of this PR is always called `alire.toml` and located at the root directory of an Alire-enabled workspace. A companion lock file, `alire.lock`, stores information about the dependency solution and overrides. These two files can be safely put under version control. The manifest, in particular, is intended to evolve with your Ada project, by being an up-to-date record of any necessary dependencies and other properties (version, project files, executables, maintainers, etc.). The manifest internal format has been simplified by eliminating the possibility of multiple releases from its contents, which removes some nesting, and removing or making optional some fields that only make sense at the time of publishing a crate to some index. Check the [catalog-format-spec.md] file for details. The `alire` directory continues to exist, and it is used to store the source code of dependencies, local configuration and backup files. It can be safely ignored for VCS, as its contents are either not critical or can be reconstructed from the manifest information. ### New `alr with --versions` switch PR [#464](https://github.com/alire-project/alire/pull/464). A new `alr with --versions` switch is available to obtain version-focused information of dependencies. Namely, the combined dependencies on a crate are shown, with the release in the solution, and the last known version for the crate: ``` CRATE DEPENDENCY SOLVED LATEST a_project (root) 0.0.0 unknown hello ^1 1.0.1 4.0.0 libhello (^1.0) & (~1.0) 1.0.1 2.0.0 superhello * 1.0.0 1.0.0 unobtanium * missing unknown wip * /fake unknown ``` ### New `alr with --graph` and `alr with --tree` switches PR [#465](https://github.com/alire-project/alire/pull/465). The ASCII art dependency graph generated with `graph-easy`, that was printed at the end of `alr with --solve` output, is moved to its own `alr with --graph` switch. A fallback tree visualization is generated when `graph-easy` is unavailable. This new tree visualization can also be obtained with `alr with --tree`: ``` my_project=0.0.0 ├── hello=1.0.1 (^1) │ └── libhello=1.0.1 (^1.0) ├── superhello=1.0.0 (*) │ └── libhello=1.0.1 (~1.0) ├── unobtanium* (direct,missed) (*) └── wip* (direct,linked,pin=/fake) (*) ``` ### Automatically 'with' GPR project files from dependencies PR [#458](https://github.com/alire-project/alire/pull/458). When adding or removing dependency with `alr with`, a list of `with` statement for each project files of the dependencies can be automatically added to the root project file: ``` -- begin auto-gpr-with -- -- This section was automatically added by Alire with "libhello.gpr"; -- end auto-gpr-with -- project Test is ... ``` This feature can be permanently enabled or disabled with a local or global configuration option: ```bash alr config --global --set auto-gpr-with false ``` Crates with project files not compatible with this feature can disable it using the `auto-gpr-with` entry: ```toml auto-gpr-with=false ``` ### Show release-specific dependency sets in solutions PR [#453](https://github.com/alire-project/alire/pull/453). The dependency solution shown with the `--solve` switch now details for each release the particular version set with which a dependency is brought into the dependency closure. For example: ``` Dependencies (graph): hello=1.0.1 --> libhello=1.0.1 (^1.0) superhello=1.0.0 --> libhello=1.0.1 (~1.0) ``` ### Use crate metadata when pinning to a directory PR [#450](https://github.com/alire-project/alire/pull/450). When pinning a dependency to a directory (`alr pin|with --use`), detect if the target contains Alire metadata (as usual, in an `alire` subdir). In that case, use it to determine further dependencies and project file scopes. Also, the target dependency name is verified. For such a target directory, a shortcut `with` command is available since the crate name can be determined from the metadata: `alr with --use /path/to/target` (note the absence of a crate name). ### Allow working with incomplete solutions PR [#447](https://github.com/alire-project/alire/pull/447). Before this patch, any change in dependencies that resulted in an incomplete solution caused a final "invalid solution" error. Now, any incomplete solution will be presented to the user with details about the unfulfilled dependencies. This solution can be accepted and worked with normally, although the user is responsible to provide in the environment any missing project files. This change affects all commands that compute a dependency solution, i.e., `get`, `pin`, `update`, `with`. ### Use a directory to fulfill a dependency PR [#439](https://github.com/alire-project/alire/pull/439) A local path can now be used to fulfill a dependency. The path can be supplied during initial dependency addition or afterwards during pinning, via the `--use` switch. Such a path will be added to the environment generated by `alr setenv`. Examples: ```bash $ alr with some_crate --use /some/absolute/or/relative/path # To simultaneously add a dependency and the directory to use for its GPR file. # The dependency needs not to exist in the loaded indexes. $ alr with indexed_crate $ alr pin indexed_crate --use /path/to/gpr/containing/folder # To pin a previously added dependency. ``` alire-1.2.1/elim/000077500000000000000000000000001430264165500135435ustar00rootroot00000000000000alire-1.2.1/elim/ajunitgen.gpr000066400000000000000000000010461430264165500162420ustar00rootroot00000000000000with "../deps/xmlezout/xml_ez_out"; project Ajunitgen is for Source_Dirs use ("../deps/ajunitgen/src"); for Object_Dir use "obj"; package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnato", "-fstack-check", "-gnata", "-gnat12"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; package Linker is for Switches ("ada") use ("-g"); end Linker; end Ajunitgen; alire-1.2.1/elim/alire.gpr000066400000000000000000000012701430264165500153510ustar00rootroot00000000000000with "../deps/aaa/aaa"; with "../deps/ada-toml/ada_toml"; with "../alire_common"; with "ajunitgen"; with "../deps/gnatcoll-slim/gnatcoll"; with "../deps/semantic_versioning/semantic_versioning"; with "../deps/simple_logging/simple_logging"; with "../deps/xmlezout/xml_ez_out"; library project Alire is for Library_Name use "alire"; for Source_Dirs use ("../src/alire", "../src/alire/os_linux"); for Library_Dir use "lib"; for Object_Dir use "obj"; for Languages use ("Ada"); package Compiler renames Alire_Common.Compiler; package Builder renames Alire_Common.Builder; package Binder renames Alire_Common.Binder; package Ide renames Alire_Common.Ide; end Alire; alire-1.2.1/elim/alr.gpr000066400000000000000000000014631430264165500150370ustar00rootroot00000000000000with "../deps/aaa/aaa"; with "../deps/ada-toml/ada_toml"; with "../deps/ansi/ansi"; with "alire"; with "../alire_common"; with "ajunitgen"; with "../deps/semantic_versioning/semantic_versioning"; with "../deps/simple_logging/simple_logging"; with "../deps/spdx/spdx"; with "../deps/xmlezout/xml_ez_out"; project Alr is for Source_Dirs use ("../src/alr", "../src/alr/os_linux"); for Object_Dir use "obj"; for Exec_Dir use "bin"; for Main use ("alr-main.adb"); for Languages use ("Ada", "C"); package Compiler renames Alire_Common.Compiler; package Builder is for Switches ("Ada") use Alire_Common.Builder'Switches ("Ada"); for Executable ("alr-main.adb") use "alr"; end Builder; package Binder renames Alire_Common.Binder; package Ide renames Alire_Common.Ide; end Alr; alire-1.2.1/elim/run.sh000077500000000000000000000001231430264165500147020ustar00rootroot00000000000000#!/bin/bash gnatelim -Palr -main=alr-main.adb -XBUILD=DEBUG -XLIBRARY_TYPE=static alire-1.2.1/resources/000077500000000000000000000000001430264165500146275ustar00rootroot00000000000000alire-1.2.1/resources/alr.desktop000066400000000000000000000001341430264165500167760ustar00rootroot00000000000000[Desktop Entry] Name=alr Exec=alr Icon=alr Type=Application Categories=Development;Utility; alire-1.2.1/resources/alr.png000066400000000000000000000101171430264165500161130ustar00rootroot00000000000000‰PNG  IHDRôxÔúbKGDÿÿÿ ½§“ pHYs-xþ,tIMEä  ( t~ÜIDATxÚíÝìµu]Çñ'Þ`H¡b·Êo1"šÊ¨™X£X˜©“T$h˜3ü+ÛÌÄ(§älÔÔ–47~,š£rôƒ‚!býádLJ?¤45÷ÍÝç{×-!ÜÜ÷÷\×uÎy<¶Ï¾^×÷}®ë¼^ç:ç\§`Çíb,‘}ªãªÃª}«‡ª¯T_¨®3¶Ó~Õ±Õ¡ÕS«]dálY[T_¯¾\ÝUÝ]}Çx`yJì;×Nð-³þ±:ÞÈx{TgW÷lÇqd-þº¾º¨úÍêp‡?,žwíàÉKu¤ñ±æhUWVgTœ0]ÖB|gOø÷åJ{z³KÂÂÏzäºqíêÀnN˜ŽgWß]ÇýFº’rÖxŽ8Ú)ã‡ÿ¦9œàçíJy†P³v`][ý¼Ó–'ü·®7ñÊøª0³vb}±z‘Ó–#ü·®ÝzéùÀŸµ^ëªf_7<ü·T6§Ð²æ°ÞíÔ‚Åÿ­‹åõûÂÊšÓºµÚ¸h'Ä“<'0áðÿrÃß…íd£_Zo5æäfw9Â67*€q}·úŽ€ðX=7 ¼½§)¬jøo©>äa&âî··—À*†ÿÃÕÁÕ­*`"†¾-ðSV1ü©îðP²iàíÍõ9ZþÂ`ûlx{ßSþã;`àí}W@øŒï·7ׯ*Â_ølŸç ¼½{„?À¸^4Â6çúµC@ø €Ç÷*á/üÕóæ¶y³€ðÏÕA#l÷á0ž÷Œ´Ý{„?À8ö¯Þ¸l¯þá/üÛù#m÷já0Žã«_iÛŸRþÃ{ruňۿR@ø ïÚj÷‘¶ýùê!á0¬+ªŸqû— ±@ø €ÿsyuÂÈûpñÙÍc-ü…?@»WŸ«^0ò~ÜX}Õ„?Àü½¼úö¿êO‡Ú ü…?°ªö­.­þ¹Úc"ûô1á0Ï­.¨¾Q½zBûuÞóá/üUðüê—›ýªßOLtO@øSv`õ²êàê©Õ.Ú·]«½Öþ>«:t-ü§î²ê~áLÍ~ÕYÕoTŒcݽmè *Â_øç¼ê­Æ07Ww+`*®®¯ö1й:sŒú€ðþÀ£yiu›ðŸ»wVßR„¿ð¦à°êc˜»»ª޵q@ø à‘>oƒø…17®álëÏsÙgW7+Â_øSð£Í¾æÇ|ÝX½wìP„¿ð¶zÌ݃ÕqSØ@ø `«3Œ`þ[þÂ˜Šƒs‡¿y;¹ºi*;£áÔìÞþÌÏ;ª¿šÒ)Â_ø[¯0çT<µR„¿ðÊWÿæåÕ»§¸c~ @ø  ê#Xwï˜â+@ø `[_1‚uõ«Õ%SÞA@ø  f¿úÇÎ{¨zaú´ÿã3 üøÏz¸¹ÚoÂ_þÛºÜvØû«#›ÈM~á/ü'âŒà »·zAuÖ¢í¸ ü¶út rùz"Ϊhöã> GþÛz<®K›½×ÿþEþ'á°­/U¿m êÊfwL|MõEÿgáðHçVÃÿúËjcuÂÚsþRpáðh~}íùíÔýÿo­>TWmZÆPþ?̯­ý]•ðÅêãk¯øo_öVþ«Zn­®ª>U]Ñ}‡_þÂP~ð9pÛ϶ýWuwuçÚß»Ö^å__ݶêª ü¶·lÙ¦ LÑG«·{¨¶o€íuZuÑ„÷ïÌê/v¾oÄJÂ_ø+LÓ}sf.2R%á/ü󪯭Ãñò;F©0®ç@`œ»ƒÇÉMÕáÆ§ ü…¿ÀâÚPSýÇv—U/72%`Ñí²$á{nï»Ìà#Î t@uìÚyûÔêÁê+Õ ÕµÆ3X 8mÂûwqõf“Wþ^ù»¸€ðþ   üQ%á,] ¸ØC$ü…¿(@ @ø£JÂPþ(€€ðG”á/üP„¿ðW@ þÂ_P@ P„¿ðWP”á/ü”%@ø @%@ þ½þ  ,c Ømäð¿½Úu¢ÏæêàêNçÑÊ9·z²1°æ¡êžê†êêµLßékO›èþ½iíï)^ùOkmZÛGVó €e=ÖúLõj§¦+y;@ø£X+¹îª^ìUµàæf·÷þ‹ÉÏó²ˆö1%`êÇÑ< À _õ[lß3Ð÷@ ˜úq4Ïp·ðg Ž#pÜ*Kyͳ\7âÐþKã:#`]oKS.\ÖãhÞ_ü·æ{þËåþê›ÆÀ‚¹Ò–Ƙ÷ ˜ëq4ï[ôî[½bàð÷iÿåó¬ê¥ÆÀ99w\&cÝ6ø”EÚ††»mâÃÍ~Ž“åóã¹½¬µ8ëNÙ¥uá€ÇÑyóþgæ}à¡ê™Õ‹½òg'|»Ù/J>ß(X'Tß2WvÒ+›Æ·évÊ“š}•Á+vÆÞ^YZ °þÄ©êJÀ:¬w.Ó°^,üY§WVBÆšêú’ST X‡uÍ2ëõ­ÿOn>Ç1¸rÎ4Ö×}Í~Ã%`gÖmË<¬×iHÿY=ñ·²N8Ö„ÖÍÂ¥½o_ùï²ìÃzúÚ ³£CºØñF³ßw¸CøX#¯?t*Rýt³~îèqô®Uد<Á"pYõ<Çr5àË‚Èx]Xíïôã~«úú8Ž>Úˆ?5…Ë Ï®^[W^í×ìëƒ_«þµútõ×ÕƒŽ-ák¥òØê°f7¡z²±°“¶Tß©î©n¬®jöU0x,ÇT'U?ÕìjåÞ;Òww³Ûû^Yý“1°PþÏyòˆQgíNIEND®B`‚alire-1.2.1/scripts/000077500000000000000000000000001430264165500143045ustar00rootroot00000000000000alire-1.2.1/scripts/alr-completion.bash000077500000000000000000000055551430264165500201050ustar00rootroot00000000000000#!/usr/bin/env bash if ! builtin type -P alr &>/dev/null; then echo alr must be in PATH for completion to work return fi # Commands/Topics: all line-first words not starting with capital letter, after # COMMANDS _alr_commands=$(alr | grep COMMANDS -A 99 | awk '{print $1}' | grep -v '[[:upper:]]' | xargs) # Long global switches _alr_global_switches=$(alr -h | grep -Eo -- '--[[:alnum:]-]+' | xargs) # Crate names _alr_crates=$(alr search --crates | cut -f1 -d' ') # Command-aware long switches function _alr_completion() { curr=$2 prev=$3 # Identify which command is being entered, if any found=false for word in "${COMP_WORDS[@]}"; do # completed words for cmd in $_alr_commands; do # alr commands if [ "$word" == "$cmd" ]; then # Note that $cmd holds the identified command, that we will use later found=true break 2 fi done done # When no command found, suggest commands and long global switches. # Although global switches can be used even after the command is given, by # hidding them after the command we obtain clearer command-specific # suggestions. $found || COMPREPLY+=($(compgen -W "$_alr_commands $_alr_global_switches" -- $curr)) # When command found, always add the compatible command switches if $found ; then cmd_switches=$(alr $cmd -h | grep -Eo -- '--[[:alnum:]-]+' | xargs) [ "$cmd_switches" != "" ] && COMPREPLY+=($(compgen -W "$cmd_switches" -- $curr)) fi # Command-specific completions $found &&\ case $cmd in get | show | toolchain) # Suggest crate names COMPREPLY+=($(compgen -W "$_alr_crates" -- $curr)) ;; index) # Suggest paths when adding a new index [ "$prev" == "--add" ] && compopt -o dirnames ;; publish) # Suggest files when using a non-standard manifest [ "$prev" == "--manifest" ] && compopt -o filenames ;; run) # Suggest only the executables explicitly declared by the release COMPREPLY+=($(compgen -W "$(alr run --list |\ sed -n '/builds these executables/,//p' |\ tail -n +2 |\ awk '{print $1}')" -- $curr)) ;; with) # When the previous word is "with", show any crate: [ "$prev" == "with" ] && COMPREPLY+=($(compgen -W "$_alr_crates" -- $curr)) # When the previous word is "--del", show direct dependencies: [ "$prev" == "--del" ] && COMPREPLY+=($(compgen -W "$(alr with | tail +2 | grep -Eo -- '[_a-z0-9]+')" -- $curr)) ;; esac } # Bind the function that performs context-aware completion complete -F _alr_completion alr alire-1.2.1/scripts/aptdetect000077500000000000000000000012241430264165500162060ustar00rootroot00000000000000#!/bin/bash set -o errexit set -o nounset #apt-file update apt-file --regexp search '/usr/share/ada/adainclude/.+\.gpr$' | while read line; do package=`echo $line | cut -f1 -d:` gpr=`echo $line | cut -f2 -d' '` target=`echo $package | sed 's/^lib//' | sed -r 's/[0-9]+.*//' | sed 's/-/_/g'` # echo $package $target if echo $gpr | grep -q ${target}.gpr; then version=`apt-cache policy $package | grep Candidate | awk '{print $2}'` descr=`apt-cache show $package | grep 'Description-..:' | cut -f2- -d' '` echo $package $target $version $descr else : #echo $package $gpr discarded fi done alire-1.2.1/scripts/ci-github.sh000077500000000000000000000031251430264165500165170ustar00rootroot00000000000000#!/usr/bin/env bash trap 'echo "ERROR at line ${LINENO} (code: $?)" >&2' ERR trap 'echo "Interrupted" >&2 ; exit 1' INT set -o errexit set -o nounset export PATH+=:${PWD}/bin # For Darwin, have to define OS=macOS for alr_env.gpr # Windows defines it anyway # Linux (undefined) selects the default [ `uname -s` == "Darwin" ] && export OS=macOS # Build alr gprbuild -j0 -p -P alr_env # Disable distro detection if supported if [ "${ALIRE_DISABLE_DISTRO:-}" == "true" ]; then alr config --global --set distribution.disable_detection true fi # For the record echo ENVIRONMENT: env | sort echo ............................ echo GNAT VERSION: gnatls -v echo ............................ echo ALR VERSION: alr version echo ............................ # Set up index if not default: if [ "${INDEX:-}" != "" ]; then echo Setting default index to: $INDEX alr index --name default --add "$INDEX" fi echo ALR SEARCH: # List releases for the record alr -q -d search --list --external echo ............................ echo TESTSUITE: # Run e3.testsuite echo cd testsuite # On Windows, python3/pip3 don't explicitly exist if [ "${OS:-}" == "Windows_NT" ]; then run_python=python run_pip=pip else run_python=python3 run_pip=pip3 fi echo Python version: $($run_python --version) echo Pip version: $($run_pip --version) $run_pip install --upgrade e3-testsuite echo Python search paths: $run_python -c "import sys; print('\n'.join(sys.path))" echo Running test suite now: $run_python ./run.py -E || { echo Test suite failures, unstable build!; exit 1; } cd .. echo ............................ alire-1.2.1/scripts/git-fingerprint000077500000000000000000000002051430264165500173370ustar00rootroot00000000000000#!/bin/sh echo alr compiled from `git remote get-url origin` `git branch -q | cut -f2 -d' '; git show -q | head -1 | cut -f2 -d' '` alire-1.2.1/scripts/gnat_install.qs000066400000000000000000000017351430264165500173360ustar00rootroot00000000000000function Controller() { installer.setValue("TargetDir", installer.value("InstallPrefix")); installer.autoRejectMessageBoxes(); installer.installationFinished.connect(function() { gui.clickButton(buttons.NextButton); }) } Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.currentPageWidget(); page.deselectAll(); page.selectComponent("com.adacore.gnat"); gui.clickButton(buttons.NextButton); } Controller.prototype.LicenseAgreementPageCallback = function() { var page = gui.pageById(QInstaller.LicenseCheck); page.AcceptLicenseRadioButton.click(); gui.clickButton(buttons.NextButton); } Controller.prototype.IntroductionPageCallback = Controller.prototype.TargetDirectoryPageCallback = Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.FinishedPageCallback = function() { gui.clickButton(buttons.FinishButton); } alire-1.2.1/scripts/installer/000077500000000000000000000000001430264165500163015ustar00rootroot00000000000000alire-1.2.1/scripts/installer/README.md000066400000000000000000000001361430264165500175600ustar00rootroot00000000000000# Alire Windows Installer Based on MSYS2 installer: https://github.com/msys2/msys2-installer alire-1.2.1/scripts/installer/alr_icon.ico000066400000000000000000001054521430264165500205720ustar00rootroot00000000000000 hV  ¨¾00 ¨%f@@ (B; õ 6}(  × × ÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿ$ÿÿÿ-ÿÿÿ-ÿÿÿ-ÿÿÿ-ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{{{Šlll‘××× ÇÇÇËËËpppÌVVVéWWWçWWWçWWWéMMM|µµµààà=Ã???A2ÇZZZ“òòò ””” ÑjLKQQQ†bbbvµµµååå¹ÿkwõ(((ÿ***ÿí/ÿÿÿÿÿÿfff¹ÿ nÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ'   À ÿ’wõÿí/ÿÿÿÿÿÿeee¸ÿ€€€åÞÞÞÕÙÙÙÕÙÙÙÕÙÙÙÕÙÙÙÕÖÖÖäkkkþÿtwöí.ÿÿÿÿÿÿ===’ÿÿ ÿ ÿ ÿ ÿ ÿÿÿÊ!p™9µ¾½½½½¾»Ž(  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ñ€á€Á€‡ÃÀ‡ÂàÂðÂøÃüÀþÀÿÀÿ‡àÿÏàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(0` $× × ÿÿÿÿÿÿÿÿÿBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿLÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿNÿÿÿOÿÿÿ>ÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿ/ÿÿÿ8ÿÿÿÿÿÿÿÿÿ ÿÿÿ¦õõõúôôô¬ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»óóóüìììûíííûíííûíííûíííûíííûíííûíííûíííûíííûíííûíííûíííûíííóôôôaíííÿÿÿÿÿÿÿÿÿÿÿÿUýýýãòòòíôôôJòòòÿÿÿ ÊÊʸOOOÿYYYÿÌÌÌ®ÿÿÿþþþÿÿÿÿÿÿÿÿÿ#ÃÃÃãEEEÿ///ÿ000ÿ000ÿ000ÿ000ÿ000ÿ000ÿ000ÿ000ÿ000ÿ000ÿ000ÿ000ÿ333ÿ;;;«ÿÿÿÿÿÿÿÿÿUûûû眜œÿ;;;ÿ888“lÿÿDDDÿÌÌÌ®ÿÿÿþþþÿÿÿþþþÿÿÿ#pppäÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÿÿÿÿÿÿÿÿÿUûûûç–––ÿÿÿÊ ÃÿÿDDDÿÌÌÌ®ÿÿÿþþþÿÿÿþþþÿÿÿ#iiiäÿü;¿¿¿¿¿¿¿¿¾à ÇsÿÿÿÿÿÿÿÿÿUûûûç———ÿÿÿôn)ÄÿÿDDDÿÌÌÌ®ÿÿÿþþþÿÿÿþþþÿÿÿ#jjjäÿó@ ‘‘‘òòò˜ùùùÂüüü8ûûûÿÿÿÿÿÿÿÿÿÿÿÿUûûûç———ÿÿÿôt)ÄÿÿDDDÿÌÌÌ®ÿÿÿþþþÿÿÿþþþÿÿÿ#jjjäÿò9ÿÿÿÿÿÿ1âââí———ÿ‘‘‘ÿÿÿ ÿÿÿÿÿÿÿÿÿUüüüç———ÿÿÿôt)ÄÿÿDDDÿÌÌÌ®ÿÿÿþþþÿÿÿþþþÿÿÿ#jjjäÿò9üüüÿÿÿ6qqqñÿÔÿÿÿÿÿÿÿÿÿUüüüç———ÿÿÿ þ***‰$$$$$$)ÄÿÿDDDÿÌÌÌ®ÿÿÿþþþþþþÿÿÿ#jjjäÿò9ùùùþþþ6WWWñÿæ%ÿÿÿÿÿÿ(ûûûß———ÿÿÿÿzzzþóóóÔÿÿÿaÿÿÿÿÿÿ)ÄÿÿDDDÿÌÌÌ®ÿÿÿþþþÿÿÿ#jjjäÿò9ùùùþþþ6WWWñÿæ%üüüÿÿÿ+˜˜˜äÿÿÿÿ'''ÿSSSÿ¨¨¨ôííígÿÿÿ)ÄÿÿDDDÿÌÌÌ®ÿÿÿÿÿÿ"jjjäÿò9ùùùþþþ6WWWñÿæ%‰‰‰´´´ ©ÿÿÿÿÿÿ ÿjjjÙÏÏÏ!ÀÀÀ)ÄÿÿDDDÿËËˬÿÿÿ=iiiâÿò9ùùùþþþ6WWWñÿæ%>©´´´Âñÿ ý'''a000)ÄÿÿCCCý×××Érrrïÿò9ùùùþþþ6WWWñÿæ% 111x ÿÿ¬)ÄÿÿGGGÿYYYÿÿò9ùùùþþþ6WWWñÿæ%ÿÿÿÿÿÿççç<<<ÿÿÐ)Äÿÿÿÿò9ùùùþþþ6WWWñÿ ð¶¶¶}ÿÿÿeÿÿÿgÿÿÿgÿÿÿgÿÿÿgÿÿÿgÿÿÿgÿÿÿiÿÿÿ›çççó000ÿÿÊ)Äÿÿÿò9ùùùþþþ6WWWñÿÿÁÁÁÿáááÿßßßÿßßßÿßßßÿßßßÿßßßÿßßßÿßßßÿÔÔÔÿoooÿÿÿ˜)Äÿÿó9õõõýýý CCCÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿã7)Äÿë/†††ÿÿÿ™ÿÿÿÿÿÿÿÿÿÿÿÿÿÜT(’n/™©¨¨¨¨¨¨¨¨©¡v(ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÃüÿƒüü~€ü|À|øà<ðððð`ø ð`üð`þð`ÿðpÿ€ðpÿÀðÿàðÿððÿøðÿüðÿþøÿÿ?ü?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(@€ @× × ÿÿÿÿÿÿÿÿÿ:ÿÿÿUÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿUÿÿÿbÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿaÿÿÿbÿÿÿVÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿTÿÿÿ<ÿÿÿÿÿÿÿÿÿÿÿÿIÿÿÿêÿÿÿþÿÿÿ¹ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ¦ÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿ­ÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³ÿÿÿýÿÿÿíÿÿÿPÿÿÿÿÿÿÿÿÿÿÿÿ~äääÿÿÿééé¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ"ûûûâ¹¹¹ÿ}}}ÿzzzÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ’’’êžžž.§§§ÿÿÿÿÿÿÿÿÿÿÿÿµüüüÿ¹¹¹ÿ†††ÿ”ÿÿÿ!!!ÝÝÝìììAVVVíÿÿfffÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%¿¿¿åÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿµýýýÿÿÿÿÜ&Æÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%“““åÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¤ÿÿÿÿÿÿÿÿÿÿÿÿµýýýÿÿÿÿÿò;fóÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%‘‘‘åÿÿþîèèèèèèèèèèèèèçääÏFÿÿÿÿÿÿÿÿÿÿÿÿµýýýÿÿÿÿÿþ£ oòÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%’’’åÿÿøa%(((((((((((($$$.¨¨¨w»»»™žžž?ÿÿÿ000ÿÿÿÿÿÿÿÿÿÿÿÿµýýýÿÿÿÿÿþ¨oòÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%’’’åÿÿ÷CÿÿÿÿÿÿÿÿÿQÿÿÿðÿÿÿÿÿÿÿ»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿµýýýÿÿÿÿÿþ¨oòÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%’’’åÿÿ÷Cÿÿÿÿÿÿÿÿÿ„ÙÙÙÿuuuÿwww퀀€5ÿÿÿÿÿÿÿÿÿÿÿÿµýýýÿÿÿÿÿþ¨oòÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%’’’åÿÿ÷CÿÿÿÜÜÜõõõ†\\\ÿÿÿ‹ÿÿÿÿÿÿÿÿÿÿÿÿµýýýÿÿÿÿÿÿ©oòÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%’’’åÿÿ÷Cÿÿÿ±±±äää†999ÿÿÿ°ÿÿÿÿÿÿÿÿÿ±ýýýÿÿÿÿÿÿ___þâââ°ÿÿÿ;ÿÿÿÿÿÿoòÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ%’’’åÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿ±ÿÿÿÿÿÿDýýýöÿÿÿÿÿ###ÿ§§§ÿÞÞÞÿùùùêÿÿÿlÿÿÿÿÿÿoòÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿÿÿÿ%’’’åÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿ±þþþÿÿÿ)§§§Þÿÿÿÿÿÿ ÿÿaaaÿÊÊÊòþþþZðððÿÿÿoòÿÿÿeeeÿèèè¼ÿÿÿ#ÿÿÿÿÿÿ%’’’åÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿ±¿¿¿ÿÿÿœÿÿÿÿÿÿÿÿÿ$$$ÿ   Îÿÿÿðððoòÿÿÿeeeÿèèè¼ÿÿÿ!ÿÿÿ#’’’åÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿ±Tëýýýýýÿÿÿÿ úqqqVfffoòÿÿÿeeeÿèèè¹ÿÿÿG‘‘‘ãÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿ±7XXXXYrËÿÿÿ¡oòÿÿÿdddþðððÕ™™™òÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿ±€€€```8%%%íÿÿÞ!oòÿÿÿiiiÿŒŒŒÿÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿ±ÿÿÿýýýÿÿÿY†††ùÿÿô=oòÿÿÿÿÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿµÃÃÃÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿKÿÿÿÖ•••ÿÿÿöAoòÿÿÿÿÿ÷Cÿÿÿ°°°äää†999ÿÿÿHHHîûûûÊÿÿÿÉÿÿÿÉÿÿÿÉÿÿÿÉÿÿÿÉÿÿÿÉÿÿÿÉÿÿÿÉÿÿÿÉÿÿÿÉÿÿÿÒÿÿÿòóóóÿPPPÿÿÿè+oòÿÿÿÿ÷Cÿÿÿ±±±äää†999ÿÿÿJJJÿÜÜÜÿßßßÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿËËËÿiiiÿÿÿÿ¶ oòÿÿÿ÷Cÿÿÿ¿¿¿ÜÜÜh444ýÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòQoòÿÿöBooowww×ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷€oòÿÚ%¢ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü×h R‡@ {‘‘‘‘‘‘‘‘‘‘‘‘‘’…[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‡ÿð?ÿ‡ƒÿàÿÿàþ€ÿàü€àøÀ?àðÀà?àààüÀðàü€øàü?üàüþàüÿ`üÿ€ üÿÀüÿàüÿðüÿÿøüÿÿüüÿþüÿÿüÿÿ€üÿÿÀüÿÿàüÿÿðþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰PNG  IHDRö{`í ¼IDATxÚíÝ}õÇñwïì#OnDX„=@WP$WÂåNb®.æH‰eÄ$ÄD£§ÞIå¼3&˜Ã˜:¯.î•9Oï\bÊD+•¤4‰Ä§zÙÏÝœ›tÀÂå~£Ÿ›*×"ö%n·e€ÿeõI‡-,þá7ŒŸÑ”HÉn¤7ñ`{-o³†Ó’]Їßx†É‰”íöÄÃì·ánβñ¼”Îá¯ùæY«>¡}¨Kä]ƒÏ—ø§_1½ ,ü‰xkøÓ©é­:¸¯3!éb”+HãŸ[62%Þ¢Vc7|û@&éf¾øÒ×É$Êrì `¶ØvÝk5I‡7Ȳ—¿òߟ4¶c)nü¨esãø¯P+_cšß éK€´‡ÎàÃI¡ås~£¥µI—o„ô‡&3Ý…&¦DzèígŽqœlñ•¸–_³Óëåt%@5„šŠ^D;“ˆî ÑGýtóÿÍ6Ž[ý|VÒîUœ4%@u„?€I\Ë@ÜJ:ù-÷±™A¿Õ2¬ä'¼áþbzú§Lø?ýù2œÍ <ÈUÅ.Îg‰×KiI€S*üqr˜Ï]\çõgK½r$  ðW¤…۸ܕŜåþB@á¯Øt¾Êl¿fpŽû É'À)~3#Z<ÏûþŒ+ý‚9‰î/$}p †^ëìþ^sO$“Õh †É\ÀMëpšµ1Ï;`:ýç$Ã_=s×sŒ¬݉ ƒ“uÞ¥ƒÛø< OŒo¦ÍïßšÝÏ’K€ÀáoãÃÕyM3RôÓÁj~H_î/¯Ž~N£û™bR 8üçqK*dº98ð·óó¡q§¿Jƽ!M&JÿwX¦Ï¿Ÿn¾Í–ÜÇý†„ÜÏ ’H€’>ý—QÓÀj5r¶óz¡Ÿ}~«:TŠ?J ÿ² T¤›ð$Ûà]vø­x^·?Ç]¿%6þ  ûYÛü`'Üþo —þËþ yþxï#tû­±Û½ƒg—þ,]î — s8 {ôQ¿•zØêþB|#%wý€ <Â7âžö]}~Ì3ãw:~«¼În÷âJ€rº~ÜtêÞñ¦Õ 5ößU6ÒåþB<‡€r¿›x!–ÒU·F®à>óŸýˆßy=K%Ž œ®ßþMTße€8Õ0‘¬âJZЬù"ÿãõRô PNø;N†l©¥…V¦øÌÐD†f°‹˜ZôCÒÇõo{=@(ê(§ë×ÁMlglÎá.§•Æ¢uÈàPl„ÜaÚ®©¿=^6Êíúmsmÿîäâ(.z´pý¦yóYÏ›™¢ì–Ûõ{á?Ÿç’(ŸaåÀê-kz=g…GØTÐõcáoäË|(šM_Ì—Þ9kã>kDÕ(üÁÍ/6§»\³YËùϳ£Æ§N£I€ zþc.üðAÿ¸Ëu&·ó±>~MßZQ$@E=ÿ1èÌ(ê6o²ŠÌv~ë_«á÷Ôó/Õ ö®Ïâv®¢a€‡xÍͰ[€r®÷Íž?û°ú¿mê6kXÄr5ð<‘³^?Ûç<{ÂÍÌÌžµÅæ1äcØ%Öµ5Ÿ2ÅÿŒ EÖevß3‚6;ªVc×îîZâS&ÙíEËš™½gW{Õì°0êú•ÄrkëÔO³5”iõ\Ĭ 9·ù‡øUñš /Ôõ+]†U´e¸†-<ìÿ‡¢Æ³+Y>|«Ðz¾ÃáâÿV¨ëWŽ)|`wÐǯÊJÆ3ƒ±”K8k¸K÷2ßdWº '4ìSžæ¡ÇMÍ¥ãÑ@)àÐLã˜È$ΦœÏÙ…OÌÞÃÖ«Û0@á/Wf¸þçòo8Z.ço˜L3ãçvñpkx V·•ŸªëW¾£¼7üË\ÚYàŠÐ Oñ*ç1“É4¬Cc«y<øÉ_¥  ®_%°-ÿ×¹Ü(:YËnç Gxëy:è§¿r%œ÷?>tÞ¿Áû¼¤S{À0ìsvÈ ì²OYÇPO³ïÛ‰ü°Ív£´nÃò°k †f÷UM)Ðo/ÛÖf>•`´ÈÃ?&kµGF§À•ÁSà =m_³yVïºrÂ_Bãÿ~Ug¼PtžîðÖ°9¶®Üh±«ùikœÍ~NÄÇþ¼êImÜoõÞez*7p{¥¹•p¯&SøÓv–w™î.e~ŸaØl·Ö ‡Š3b8öçUMjà=ûŒW‰ðñ’·Y5)cøÓf¿·V·ò òÝÒƒá1¥@,]¿‚jIqôÙý6sDiíô'˜Uæv=úéib;öçUJŠÀ¬×ž´eÖlÃk´…ÖÞ»þºWüŸ×ç·åZàƒtÁw”z–±˜çØJ7ãhc1’­ëƒeí±ƒÁ«|øDþý\îÄ‚\&šÄàÞâ_!RŽr>ýeû‡¤´˜oo~F³Ö?´ÏGl¹ù&ï­§²;kׯ :Ò˜-Öa^Þ° +ÞçÔu j cí¹Y—.~aCØëʆ†BN˜{þ#ª" €}滆¿Ë®i¿SÓ ÄÞóQ©K€““¹¿`£ÂØÖZC8£òié $þ´&VgŸµ¬?¯¸Çn®¼ù/xÄS ±c^%¤2À0Çε[l=o[ì7v‡- û‚lÒ‚ÄÃ0:8#Ôz/-@M6Ŧڄh¦bùè ×@PõLõ<ˈæûyŠp £ÜGØÏ>Ž…û{܆†ÚqXÊÐ{”þdFýæð_!6:åà6ððz"_9’\Êöÿ»~ÃÒµìã+…÷h„R •v¿QÚW/bK²Çþ*Nã\v3Xq äï‚ß0Óþ*Mc[ø_„gXeÝÁ—½¾8r´%¼URø#iü«:¸%’º¨$Yôþ‘t„¿jÀXŹ Sàq&¹mµfÔïg›ÐXp‹g,=ÿª›O0#ŠÇÜ;;)|¬ðzó\ÚY^|j‹{RŽL+vfÿ¾Îè[ Ó.M£è@œðh¨ `'Ötu³ßYL27xψâ9jQz=Ü¡a¤À[nß\À°Œ­~éÝyAŽý‘õüG”èë6Ûi$}T/eéç+×Jé}âSð‹moŸ­µÚT„8ú쟭.é°_žcnäõRj l.:SÕ°zû®™Ùkö —ûÞæÅÔówK³7l¹ß½xiZ:ùL,5ã™.ß.>_ôXmØ,{)·™ív•MÈÛ@-±ßÅüé/L³ö›˜tp‹,uvቿ¸™º8úE^)°ÇnÈ=$àý2]лäVê¼¶“1hêЕõyÜËRãÓÈL>Ƨ˜K¡Äžís.÷°”Gy…ž fÝFÅ¡‰\ÊŠþs_ííã.­“W oaÄe¢ÙÜÅ¥¬c=40²b m÷‰þ 1«-øùýßÎàVÒÅa˜FóÐ;ÄÁw`¸±™ÌÕ¬àm‘Máia#-|€L††q„þè_W^)ÐÌ*® ‹êseª¡a‚çVòàG†'W8LdbáºI|úß-¼9!êþU¥NÐMLHïù0žÙÿôòŽ÷6òÿ­“>ï–LãÿVác”Rï5vÇù}¼'Çn9.Pà ^ñŽ[~YòKŽ{¬—Ô±ÿë¢T‰@–Çé¬|3¥89@ìYž`_ M6Å671öüG•i²ýÔó6Œ´yÚf[˜‚‚×’ë™™­·sÞ¬fXn~wÁì)[”LøO–é[g}IǶ¨Aûƒýy¢õ4Û²Þ‚2e­Ã–”P&ðö-ÛjGlвvÔvX»ÍIj·Þ/Ót»Í^²Ã®ž¼¬³]v·µ%^O-öuÛl‡lвvÌvÛ=6¯X™œÑ¢–Y,`o²•½ô%}ÒePËL0+ìùv¡èc?[y•ÞÔS†³Y@+µt²•=É—IDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD¤zý?’tövâf{ÁIEND®B`‚alire-1.2.1/scripts/installer/alr_installer_icon.ico000066400000000000000000000650761430264165500226560ustar00rootroot00000000000000 hV ˆ ¾  ¨F00 ¨%î00 ¨%–D(  × × V{(5vž_9y¡b8x¡b5w b3v b0tŸb.sŸb,ržb*qžc!f’S 8Uiž E‰´›_§Õÿ\¦Õþ\¥ÕþZ¥ÔþX¤ÔþV£ÔþT¢ÔþS ÓþQ ÓþH—Éó h–S>·ÿ3MO–éS¢ÖÿJŸÖÿKŸÕÿJœÑÿIšÏÿJ›ÏÿKžÔÿM ×ÿM¡×ÿMÐÿ*|¯[6ŽÅižL’¿¦;wžÿ>ŒÀÿA‘Æÿ(Z{ÿ+`ƒÿ+`ƒÿ<„³ÿGœÓÿ6w¢ÿA‡µþ.‚¸X4…¹f™L•Ħ>„±ÿ%\ÿ2x¦ÿ'_„ÿ>’Èÿ7€°ÿ2v¡ÿ0qœÿMkÿCÁþ.¶X5…¸f™J“¦E˜Ïÿ0|­ÿKjÿ"X{ÿ<•Ïÿ2|¬ÿ'a‡ÿ1zªÿ!Wzÿ7w¢þ1…ºX6†¸f™H‘Á¦?“Êÿ5Êÿ+v¨ÿ(lšÿ6Ëÿ1‚·ÿUzÿ"\ƒÿ"^†ÿ=†·þ0ƒ¶X7†¸f™F¿§:Çÿ.‰Äÿ/‰Åÿ/ˆÃÿ/‰Äÿ1‹Æÿ2‹Åÿ2ŠÄÿ2ŒÇÿA“Èþ0³X9‡¸d›M“ÀŸf¦Ñÿa¢Íÿ[œÇÿQ’½ÿ<‡¸ÿ1‰Äÿ8ŠÀÿ6ƒµÿ4~¯ÿ4„·ü v¬T$x­t¬ÐD»h„¶×þ‘¿Ýÿ¾Üÿ½Üÿ^ŸÊÿ&ºÿ"v­ÿm ÿ#w­ÿ y³ä h¢*i£+}°%y­*h¤ËÛ€´Öÿ‚µ×ÿ†¸Øÿa¡Ëÿ)·ÿ'¹ÿ-‡Âÿ.ˆÃÿx²¦W h¢_›V”,|°7:…¶YBŒºbJ‘¾p9…¶…7‰¿ê2ŒÆÿ*„¾îx³šl¤%s« h¡n¥:оØ*¹¹r«F_˜ fŸ g j¢ u«Jo¥$x¯ÿÿÀ€€€€€€€ÀÀÀÀþþ?ÿÿ(0 × × 1L!em-sŸ‰.sžˆ.sžˆ-ržˆ,ržˆ*qˆ)pˆ(pˆ&oœˆ%nœˆ$mœˆ#mœˆ"l›ˆh—‚IoA.!g“sa£Î÷j­Øÿi¬Øÿi¬Øÿg¬×ÿe«×ÿc©Öÿa¨Öÿ_§Öÿ]¦ÕÿZ¥ÕÿY¤ÔÿW¢ÔÿU¢ÓÿQžÐÿ.}®Ã.K!Þÿ%0y¨‹i¬ÙÿM ×ÿM¡×ÿN¡×ÿN¡×ÿN¡×ÿN¢×ÿO¢×ÿO¢ØÿO¢ØÿO¢ØÿO¢ØÿP¢ØÿP¢ØÿU¥Ùÿ=Œ¿äCm%}ÂNts¶ç4€±ƒd©ÖÿIžÖÿJžÕÿJžÔÿJžÕÿJžÕÿJžÔÿJžÔÿKžÔÿKžÕÿKŸÖÿKŸÕÿLŸÖÿL ×ÿQ£×ÿ>ŽÁáX‘ fŸhœcŸÊ4ƒ´Z–½ÿ1o™ÿE˜ÏÿGœÔÿC”Éÿ([|ÿ%Roÿ&Spÿ&Spÿ*[|ÿC‘ÄÿHÕÿHœÔÿ6y¤ÿ@‚®ÿ?Ãà\˜ h¢f™cŸË3‚´[œÆÿNnÿ)b‡ÿB—Ïÿ;ˆ»ÿÄÿAŽ¿à]˜ h¡f™^œÈ1€±SœÌÿ/‰Åÿ0ŠÅÿ0ŠÆÿ1‹Æÿ1ŒÈÿ1‹Çÿ2‹Çÿ2‹Æÿ2Èÿ3Éÿ3Éÿ3ŽÉÿ3Éÿ>“ÊÿA޾à]˜ h¡eš\šÇ0±‚TœÌÿ3‹Åÿ3ŠÄÿ2ˆÂÿ0†¾ÿ.ƒ»ÿ+¶ÿ,ƒ¼ÿ0ŠÅÿ3‹Æÿ5Æÿ5Çÿ5Çÿ5Æÿ@“Èÿ@Œ½á^™ h¡bI½+|¯vs¬Òÿy±Öÿu­ÒÿsªÏÿl¤ÉÿašÀÿW‘¶ÿ;…¶ÿ/ˆÄÿ8ŒÄÿ;‰¼ÿ9‚±ÿ7z¦ÿ4w£ÿ3€²ÿ!v­Ùdž h¢,}°r©=g¤Ëì¾Ýÿ¾Üÿ¾Ýÿ¾Ýÿ޾Ýÿ‹»ÛÿM•Åÿ&½ÿ&ºÿ"s¨ÿf—ÿd•ÿq§ÿ#|¶ÿn¨Ÿ]– g¡ h¡U”Q•ÁÅŒ¼Ûÿ¾Ýÿ¾Üÿ½Üÿ¾ÜÿŒ»ÛÿK’Áÿ"{µÿ x±ÿrªÿ x±ÿ*„¿ÿ1‹Æÿ%€ºùk¥_n¨ fŸ.±xl§Íú³Õÿ€´Õÿ‚µ×ÿ…·Øÿ…·Øÿ]žÊÿ,¸ÿ)¹ÿ,†Áÿ1‹Æÿ2ŒÇÿ-‡Âÿu¯Ò ežh¢l¤ h¡$w¬`*{¯|1€²ƒ:†·ŒB‹º™F½§/~±¬3…¹í7Èÿ1‹Çÿ0ŠÅÿ'¼öu¯¹k¢CJ… g ^ R3y@ƒZ— :нÛ9Èÿ-†Àý z³Ðn§hb(‹ÐV h¡_š<Š»à6ˆ½åt¬† g "Qa› g¡ eŸp§r¨9RŽ^˜ g  g  g  g ÿÿÿàÀÀÀààààààààààààððÿ?ÿàÿáÿÿçÿÿÿÿ( @ × ×   R}`"m£%q ª%q ª&q ª%p ª$p ª$pŸª#oŸª"oŸª"nŸª!nŸª nŸªmžªmžªmžªlžªlžªlžªj¨Y‡y!4#JtPFŒ¹âu²Ùÿw´Ûÿw´Ûÿw´Ûÿv³Ûÿs²Úÿq±Úÿo°Ùÿm¯Ùÿk®Ùÿh¬Øÿf«×ÿcª×ÿa©Öÿ`§Öÿ]¦Õÿ[¥ÕÿY¤ÔÿV¢Óÿ<‹¾ò[‰|  Wˆkh§Ðÿ`«ÜÿP¢ØÿQ¢ØÿQ¢ØÿQ£ØÿQ£ØÿQ£ØÿQ£ØÿQ£ØÿQ£ØÿQ£ÙÿR£ÙÿR£ÙÿR¤ÙÿR£ÙÿR¤ÙÿR¤ÙÿR¤ÙÿT¥ÙÿU¢ÓÿkŸ« +A)ºÿa•di§ÏÿW¥ÙÿKŸÖÿKŸÖÿLŸÖÿLŸÖÿL ÖÿL ÖÿL ÖÿM ÖÿM ÖÿM ÖÿM ×ÿM ×ÿM¡×ÿM¡×ÿN¡×ÿN¡×ÿN¡×ÿO¢×ÿV¢Óÿo¥¨[ˆp«h ]g¦ÎÿU¥ÙÿIžÖÿIÔÿJÔÿJÔÿJžÔÿJŸÖÿJŸÖÿKŸÖÿKŸÖÿKŸÖÿK ×ÿKŸ×ÿKŸÕÿKŸÕÿKŸÕÿLŸÕÿL ×ÿM¡×ÿU¢Òÿsª¢M¯ìgšl¥i¡\f¤ÌÿC‚«ÿ:€°ÿGœÔÿG›ÓÿGœÓÿE—Íÿ0j‘ÿ)Yyÿ)Zyÿ)Zyÿ)Zyÿ(Ywÿ3o–ÿGšÑÿIÔÿIÔÿIÔÿ;‚°ÿ9}©ÿV¡Òÿsª¢@ŽÀf™l¦i¡\e¤Íÿ7m‘ÿ7Nÿ7~­ÿDšÓÿEšÒÿ>ŒÀÿ(:ÿD]ÿ$Rpÿ#Roÿ#Roÿ#Pmÿ.hÿD˜ÎÿF›ÓÿFœÔÿ6z§ÿ5Jÿ0l”ÿV¡Òÿsª¢AŽÀf™l¦i¡\d¤ÍÿJšÍÿ$]ÿ5Lÿ5{ªÿB™Òÿ;‰¼ÿ1Gÿ6€°ÿC™ÒÿB˜ÐÿB˜Ðÿ;‰¼ÿ-iÿA•ËÿC™Ñÿ4y¦ÿ4Iÿ*b‡ÿD˜ÏÿU Ñÿs©¢AŽ¿f™l¦i¡\c£ÌÿJœÒÿ<’Éÿ#Z~ÿ5Lÿ3|¬ÿ9ˆ¼ÿ1Gÿ5¯ÿ@—Ñÿ@–Îÿ@—Ðÿ2w¥ÿ6Kÿ=Åÿ7‚´ÿ,>ÿ -ÿ*fŽÿ@“ÊÿU Ðÿsª¢BÀf™l¦i¡\b¢ËÿHšÐÿ;“Ìÿ:Èÿ"Z~ÿ4Jÿ+j•ÿ0Fÿ2}®ÿ=•Ïÿ=”Íÿ=•Îÿ0u£ÿ5Jÿ:Ãÿ8ˆ¼ÿ(eŽÿ%_…ÿ6Lÿ)d‹ÿU Ðÿsª¢CÀf™l¦i¡\a¡ËÿE˜Îÿ8Êÿ9‘Ëÿ8ŽÆÿ Y}ÿ )<ÿ !1ÿ0{­ÿ:“Íÿ:’Ëÿ;“Ìÿ.t¢ÿ4Hÿ5‡¼ÿ9Èÿ:Èÿ:ÈÿQrÿIhÿVŸÐÿtª¢D¿f™l¦i¡\` ÊÿB–Íÿ6ŽÉÿ6Éÿ7Éÿ5ŒÅÿVzÿ,?ÿ.{®ÿ8‘Ìÿ7Êÿ8‘Ëÿ-v¦ÿ "2ÿ?ZÿC`ÿC`ÿA^ÿ4Jÿ,qŸÿVŸÏÿtª¢E¿f™l¦i¡\_ Êÿ@”Ëÿ3ŒÇÿ4Çÿ4Çÿ4ŽÈÿ2‰Âÿ*v¨ÿ2ˆÀÿ5ŽÉÿ5ŽÈÿ5ŽÉÿ2‡¿ÿ%f‘ÿ"_‡ÿ"_‡ÿ"_‡ÿ#b‹ÿ,w©ÿ7ÈÿVžÍÿtª¢E¿f™l¦i¡\^ŸÉÿ=’Êÿ0ŠÆÿ1‹Æÿ1‹Æÿ1‹Æÿ2‹Æÿ2Èÿ2ŒÇÿ2‹Çÿ2ŒÇÿ2ŒÇÿ3ŒÇÿ4ŽÊÿ4Ëÿ4Ëÿ4Ëÿ5Ëÿ4ŽÉÿ5ŽÈÿUžÍÿtª¢F¿f™l¦i¡\]žÉÿ8Èÿ,‡Äÿ-ˆÄÿ-ˆÄÿ-ˆÄÿ-ˆÄÿ.‰Äÿ.‰Äÿ/‰Äÿ/‰Åÿ/ŠÅÿ/‰Åÿ/‰Åÿ/ŠÅÿ/ŠÅÿ/ŠÅÿ/ŠÅÿ/ŠÅÿ1‹ÆÿVžÌÿtª¢H‘¿d›k¤h¡]^žÈÿP›ÍÿC“ÈÿB‘Æÿ@Ãÿ>‹¿ÿ8†¹ÿ4€²ÿ.y«ÿ(s£ÿ*~¶ÿ0ŠÅÿ6Çÿ=Èÿ?‘Èÿ?‘Èÿ>‘Çÿ>‘Çÿ>‘Æÿ@‘ÆÿO—Æÿr¨£<‰¹`Ÿi£ f¡N^žÇõ‰ºÛÿ„·ØÿƒµÖÿ³Ôÿ±Òÿx«Íÿo£ÇÿgžÂÿ^•¹ÿ8†¹ÿ-‡Ãÿ4‹Åÿ9‰¿ÿ8„¶ÿ6}¬ÿ4v¢ÿ2o˜ÿ.m—ÿ-y©ÿ"w­ÿj£—p§i¢dŸ#EŽ¼Éˆ¹Ùÿ¾Üÿ¾Üÿ¾Ýÿ¾Ýÿ¾Ýÿ޾Ýÿ¾Þÿ‚¶×ÿ?ŽÃÿ&‚Àÿ'ƒÀÿ$|µÿ!r¦ÿg—ÿ`Žÿ`‘ÿn¤ÿ$}·ÿt®ò g Nj¤ j¢@„#w«œ}²Õÿ½Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ¾Üÿ´Öÿ<‡¹ÿ$z³ÿ&~¸ÿ$x°ÿp¦ÿk¡ÿt¬ÿ&»ÿ/ŠÅÿ-‡Âÿq«Ûaœ h¢=ˆ¸q§Zd¢Éó¾Ýÿ½Üÿ½Üÿ½Üÿ޽Üÿ޽Üÿ¾Ýÿ‚µÖÿ>ŒÀÿ#~¹ÿx³ÿt­ÿw±ÿ)ƒ¾ÿ0ŠÅÿ2ŒÇÿ2ŒÇÿ&€ºÿk¤’ež i¢n¥aœ4ƒ´Ès«Ðþ€´Öÿ€´Öÿ‚µ×ÿ„¶Øÿ†¸Øÿ‡¹Ùÿ„¶Øÿ_ Êÿ.¶ÿ/ƒºÿ-†Àÿ0ŠÆÿ1‹Æÿ1‹Æÿ1‹Æÿ-‡Âÿt®í g G h i¦ dž@ƒk£6s©‰ tªŸ$w¬¦.~±«7„µ±>‰¹ºE޼ÄF½Ï'y­Ç*}²ñ@“Éÿ1‹Æÿ1‹Æÿ1‹Æÿ0‰Äÿ%€ºür¬Ñj¡e fŸ h RŽL†V“_™aœcœcž'^š00µÚB”Êÿ0‹Æÿ1‹Æÿ*„¾ýw±äl¦‡ e )b‘eh¢W”3ƒ·ÞG—Ìÿ1‰Âÿ&~·ïo¨£ h¡=a› d h¡W”4ƒµäI”Å÷v­Ãk£Xfž i  g¡džl¥¯s©tbœSZ• g  g  fŸX•Y–ÿÿÿÿÿÿÿðàààððððððððððððððððøø?ø?ÿÀÿþÿÿþÿÿþÿÿþ?ÿÿÿÿÿÿÿÿÿ(0` $× ×  !"""""""""""""""""""""""""""! &XŠ—hŸäi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïgŸá T€‰#^¨9†¶øŽÁâÿžËçÿŸËçÿŸËçÿŸËçÿŸËçÿÊæÿšÈæÿ˜Çåÿ•Æäÿ“ÄäÿÂãÿÁâÿ‹¿âÿˆ¿âÿ…½áÿƒ¼àÿ€ºßÿ}¹ßÿz·Þÿx¶Ýÿv´Ýÿs³Üÿp±Ûÿn°Ûÿk¯Úÿi®Ùÿe¬ÙÿX¢Ñÿt«ö W„  h¡÷˜Çæÿl±ÞÿV¥ÙÿV¥ÙÿV¥ÙÿV¥ÙÿV¥ÙÿV¦ÙÿV¦ÙÿU¦ÙÿV¦ÙÿV¦ÙÿV¦ÙÿV¦ÙÿV¦ÙÿV¦ÚÿU¥ÚÿU¥ÚÿU¥ÚÿU¥ÚÿU¦ÚÿU¦ÚÿU¦ÚÿU¥ÚÿU¥ÚÿU¥ÚÿU¥ÚÿT¥ÙÿU¥Úÿ^ªÜÿZ¤Óÿh é )%j¤û¥ÏëÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿO¡×ÿO¡×ÿO¡×ÿO¡×ÿO¢×ÿO¢×ÿO¢×ÿO¢×ÿO¢ØÿO¢ØÿP¢ØÿP¢ØÿP¢ØÿP¢ØÿP¢ØÿP¢ØÿP£ØÿP£ØÿP£ØÿQ£ØÿQ£ØÿS¤Øÿf­Úÿ h¡ø&9k£û£ÎêÿLŸÖÿLŸÖÿLŸÖÿL ÖÿL ÖÿL ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿN¡ÖÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿO¡×ÿO¡×ÿO¡×ÿQ£×ÿg­Úÿ h¡øImk£û¢ÍéÿJžÕÿJžÕÿJžÕÿJžÕÿKžÕÿKžÕÿKžÕÿKŸÕÿKŸÕÿKŸÕÿKŸÕÿKŸÕÿKŸÕÿLŸÕÿLŸÕÿLŸÕÿLŸÕÿLŸÖÿLŸÖÿLŸÖÿL ÖÿL ÖÿL ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿO¡Öÿh®Úÿ h¢÷f™ k£ú¡ÌèÿHÓÿHÔÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿJÔÿJžÔÿJžÔÿJžÔÿJžÔÿJžÔÿJžÕÿJžÕÿJžÕÿJžÕÿKžÕÿKžÕÿKžÕÿKžÕÿKŸÕÿKŸÕÿKŸÕÿM Õÿi®Ùÿ h¢÷f™ k£ú ÌèÿE—ÌÿAŽÁÿG›ÓÿG›ÓÿGœÓÿGœÓÿGœÓÿGœÓÿGœÓÿB‘Äÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>‰¸ÿ?‹¼ÿIœÓÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿF˜ÍÿC’ÅÿLžÕÿj®Úÿ h¢÷f™ k£úŸËçÿ-iÿÿ6|ªÿEšÒÿEšÒÿEšÒÿEšÒÿFšÒÿFšÒÿ $5ÿÿÿÿÿÿÿÿÿÿ<…µÿG›ÓÿGœÓÿGœÓÿGœÓÿGœÓÿC“Çÿ;Sÿ,ÿKžÔÿk®Úÿ h¢÷f™ k£úžÊçÿ>Äÿ7Nÿ ÿ5{©ÿC™ÑÿD™ÑÿD™ÑÿD™ÑÿD™Ñÿ ÿB]ÿ5z§ÿ5z§ÿ5{§ÿ5{§ÿ5{§ÿ5{§ÿ5{§ÿ7}«ÿD˜ÎÿEšÒÿEšÒÿEšÒÿEšÒÿA‘Æÿ:Rÿÿ6{¨ÿIÓÿl®Ùÿ h¡÷f™ k£úÊæÿA—Ïÿ<Âÿ6Mÿÿ4z©ÿB—ÐÿB˜ÐÿB˜ÐÿB˜Ðÿ ÿ!UvÿB˜ÐÿB˜ÐÿC˜ÐÿC˜ÐÿC˜ÐÿC˜ÐÿA”Êÿ/o™ÿA”ÉÿC™ÐÿC™ÑÿC™Ñÿ@‘Æÿ:Rÿÿ4y¦ÿD™ÑÿG›Òÿl®Ùÿ h¡÷f™ k£úœÉæÿ?–Îÿ?–Îÿ;Áÿ5Lÿÿ2y¨ÿ@–Ïÿ@–Ïÿ@–Ïÿ ÿ TuÿA—ÏÿA—ÏÿA—ÏÿA—ÏÿA—ÏÿA—Ïÿ5~®ÿÿ5~­ÿA—ÏÿB—Ðÿ>Åÿ9Qÿÿ3y¦ÿB˜ÐÿB˜ÐÿEšÑÿm®Ùÿ h¡÷f™ k£ú›Èåÿ>”Íÿ>”Íÿ>•Íÿ:ŒÁÿ3Iÿ ÿ1x§ÿ>•Îÿ>•Îÿ ÿ Suÿ?•Îÿ?•Îÿ?•Îÿ?•Îÿ?–Îÿ?–Îÿ3}­ÿÿ4}¬ÿ@–Îÿ@•Íÿ:Sÿÿÿ2Iÿ+j“ÿ?–ÎÿD™Ðÿn¯Ùÿ h¡÷f™ k£ú›Èåÿ<“Ìÿ<“Ìÿ<“Ìÿ<“Ìÿ8ŠÀÿ3Jÿÿ0w¦ÿ=”Íÿ ÿRtÿ=”Íÿ=”Íÿ=”Íÿ=”Íÿ=”Íÿ=”Íÿ2{¬ÿÿ2{«ÿ>•Íÿ>•Íÿ'd‹ÿSuÿSuÿYÿ/ÿA–Îÿp¯Ùÿ h¡÷f™ k£ú™Æäÿ8Êÿ8Êÿ8Êÿ8Êÿ9‘Êÿ9‘Êÿ5ˆ½ÿ3Kÿ ÿÿPsÿ9‘Ëÿ9‘Ëÿ:‘Ëÿ:‘Ëÿ:‘Ëÿ:’Ëÿ/zªÿÿ/y©ÿ:’Ëÿ:’Ëÿ:’Ëÿ;’Ëÿ;’Ëÿ;’ÌÿA^ÿ+ÿ?”Íÿr°Øÿ h¡÷f™ k£ú˜Åãÿ6Éÿ6Éÿ7Éÿ7Éÿ7Éÿ7Éÿ7Éÿ3†½ÿ2IÿÿPrÿ8Êÿ8Êÿ8Êÿ8Êÿ8Êÿ8Êÿ-x©ÿÿJjÿ Z€ÿ!Z€ÿ!Z€ÿ!Z€ÿ!Z€ÿFeÿÿ#`ˆÿ=“Ìÿs°Øÿ h¡÷f™ k£ú—Äãÿ5Èÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ1†¼ÿ5Mÿ"_ˆÿ6ŽÉÿ6ŽÉÿ6Éÿ6Éÿ6Éÿ6Éÿ/€´ÿ%ÿ ÿ ÿ ÿ ÿ ÿ ÿ!2ÿ \‚ÿ6ŽÈÿ<’Ëÿt±Øÿ h¡÷f™ k£ú–Äâÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3Çÿ3Çÿ4Çÿ4Çÿ4Çÿ4Çÿ4Èÿ4Èÿ4Èÿ4Èÿ4Èÿ4Èÿ5Èÿ5Çÿ5Çÿ5Çÿ5Çÿ5Çÿ5Çÿ5Çÿ5ŽÈÿ6ŽÈÿ6ŽÉÿ;‘Êÿu±Øÿ h¡÷f™ k£ú•Ãâÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2ŒÆÿ2ŒÇÿ2ŒÇÿ2ŒÇÿ2ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3Çÿ3Çÿ4Çÿ4Çÿ4Çÿ4Çÿ9Éÿv²Øÿ h¡÷f™ k£ú”Âáÿ/‰Åÿ/‰Åÿ/ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÆÿ1ŠÆÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2ŒÆÿ7Çÿw²Øÿ h¡÷f™ k£ú“Âáÿ-ˆÄÿ-ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.‰Äÿ.‰Äÿ.‰Äÿ.‰Äÿ/‰Äÿ/‰Äÿ/‰Åÿ/‰Åÿ/‰Åÿ/‰Åÿ/‰Åÿ/‰Åÿ/ŠÅÿ/ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ5Æÿy²Øÿ h¡÷f™ k£ú’Áàÿ,‡Ãÿ,‡Ãÿ,‡Ãÿ,‡Ãÿ,‡Ãÿ+…Áÿ+ƒ¾ÿ+ƒ¾ÿ*ºÿ+€¹ÿ+€¸ÿ)}´ÿ)}´ÿ)|±ÿ-‡Âÿ-ˆÄÿ-ˆÄÿ-ˆÄÿ-ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.‰Äÿ.‰Äÿ.‰Äÿ.‰Äÿ4ŒÅÿz³Øÿ h¡÷`Ÿh¢ü¾Ýÿy°Öÿs¬Ôÿp«Ðÿl¦Ìÿi¢ÈÿfŸÅÿdÂÿ[“¹ÿPаÿH¦ÿ=vœÿ4m“ÿ*cˆÿ!Y}ÿ*ƒ½ÿ2ŠÅÿ=‘ÈÿK˜ÌÿVžÎÿ]¢Ïÿ\¡Ïÿ\¡Ïÿ\ Îÿ[ŸËÿ[žÊÿ[Éÿ[Èÿ[Èÿ\žÉÿ:‡¸ÿ i¢ûi£Ø€µ×ÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ‰»Ûÿ„·ÚÿµÙÿ~µÙÿ~¶ÚÿpªÎÿ)‚½ÿ*…Áÿ*…Âÿ*…Âÿ(¹ÿ&x¯ÿ$s¦ÿ"lœÿ e“ÿ_‰ÿXÿQvÿQwÿ_ÿi¢ÿl¥ÿh¢âh¡}ZœÆû޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿh¢Éÿ)ƒ¾ÿ(„Àÿ(„Áÿ(„Áÿ&~¸ÿ$x¯ÿ"q¥ÿ j›ÿd’ÿ]ˆÿZ…ÿa•ÿh ÿx±ÿ/ˆÃÿm§þ h¡ j¢)q§ö޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿg¢Éÿ)‚¾ÿ&‚¿ÿ&‚¿ÿ&ƒÀÿ$}·ÿ"w®ÿ p¤ÿišÿd•ÿgœÿi¡ÿ {µÿ/ŠÄÿ1‹Æÿ-‡Áÿ h¢ÿ`Ÿ h¢ä…¹Ùÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿf¢Éÿ%t§ÿ%uªÿ&x®ÿ(}´ÿ&x®ÿ&v«ÿn¤ÿi¡ÿl¤ÿ#~¸ÿ0‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ {µÿ h¢æ h Œe¢Ëý޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿh¢Êÿ"¼ÿ"€½ÿ"€½ÿ"¼ÿr¬ÿi¢ÿn§ÿ&€ºÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿn¨þ i¢† eŸ5$x¬õ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿo¨Íÿ/†¿ÿ-„½ÿv°ÿj¢ÿv®ÿ+„¿ÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ-‡Âÿ h¡ÿi¥ i¢ÊH‘¿ü‡¹Úÿ¼Ûÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ‹»Ûÿ€´×ÿ'z®ÿ7†¹ÿD“Èÿ3ŒÆÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ/ŠÅÿp«þh¡Æcœ g œi¢Þ g¡ï g¡ùm¤þsªø%z®õ0~²ô7…·ôA‹»õH¾ùO•ÃûC¼ÿ g ôi¢üUÌÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ&€»ÿk£ýj Íf™€¿ k¡f # i 3 g C h S hŸb g¡r g  g Ci£à[¢Ðÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ,†Àÿpªô h£ã gŸJ i¢çb¥Ñÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1ŠÄÿx±÷i¢ói£zUªh¢ígªÔÿ1‹Æÿ1‹Æÿ6ŽÇÿ,„¼þj¤öh¢ª h¢i¢óm­×ÿ6ŽÈÿ<ŽÃÿsªôj¢Ë i¡. h ø„ºÝÿ9‡ºöh¡í g ^ g¡ük¤öh¡`Ÿ g t h¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüø?ø?ø?üüüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿþÿþÿþÿÿÿÿÿÿÿÿ€ÿÿ€ÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(0` $× ×  !"""""""""""""""""""""""""""! &XŠ—hŸäi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïi¡ïgŸá T€‰#^¨9†¶øŽÁâÿžËçÿŸËçÿŸËçÿŸËçÿŸËçÿÊæÿšÈæÿ˜Çåÿ•Æäÿ“ÄäÿÂãÿÁâÿ‹¿âÿˆ¿âÿ…½áÿƒ¼àÿ€ºßÿ}¹ßÿz·Þÿx¶Ýÿv´Ýÿs³Üÿp±Ûÿn°Ûÿk¯Úÿi®Ùÿe¬ÙÿX¢Ñÿt«ö W„  h¡÷˜Çæÿl±ÞÿV¥ÙÿV¥ÙÿV¥ÙÿV¥ÙÿV¥ÙÿV¦ÙÿV¦ÙÿU¦ÙÿV¦ÙÿV¦ÙÿV¦ÙÿV¦ÙÿV¦ÙÿV¦ÚÿU¥ÚÿU¥ÚÿU¥ÚÿU¥ÚÿU¦ÚÿU¦ÚÿU¦ÚÿU¥ÚÿU¥ÚÿU¥ÚÿU¥ÚÿT¥ÙÿU¥Úÿ^ªÜÿZ¤Óÿh é )%j¤û¥ÏëÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿO¡×ÿO¡×ÿO¡×ÿO¡×ÿO¢×ÿO¢×ÿO¢×ÿO¢×ÿO¢ØÿO¢ØÿP¢ØÿP¢ØÿP¢ØÿP¢ØÿP¢ØÿP¢ØÿP£ØÿP£ØÿP£ØÿQ£ØÿQ£ØÿS¤Øÿf­Úÿ h¡ø&9k£û£ÎêÿLŸÖÿLŸÖÿLŸÖÿL ÖÿL ÖÿL ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿN¡ÖÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿN¡×ÿO¡×ÿO¡×ÿO¡×ÿQ£×ÿg­Úÿ h¡øImk£û¢ÍéÿJžÕÿJžÕÿJžÕÿJžÕÿKžÕÿKžÕÿKžÕÿKŸÕÿKŸÕÿKŸÕÿKŸÕÿKŸÕÿKŸÕÿLŸÕÿLŸÕÿLŸÕÿLŸÕÿLŸÖÿLŸÖÿLŸÖÿL ÖÿL ÖÿL ÖÿM ÖÿM ÖÿM ÖÿM ÖÿM ÖÿO¡Öÿh®Úÿ h¢÷f™ k£ú¡ÌèÿHÓÿHÔÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿJÔÿJžÔÿJžÔÿJžÔÿJžÔÿJžÔÿJžÕÿJžÕÿJžÕÿJžÕÿKžÕÿKžÕÿKžÕÿKžÕÿKŸÕÿKŸÕÿKŸÕÿM Õÿi®Ùÿ h¢÷f™ k£ú ÌèÿE—ÌÿAŽÁÿG›ÓÿG›ÓÿGœÓÿGœÓÿGœÓÿGœÓÿGœÓÿB‘Äÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>ˆ¸ÿ>‰¸ÿ?‹¼ÿIœÓÿIÔÿIÔÿIÔÿIÔÿIÔÿIÔÿF˜ÍÿC’ÅÿLžÕÿj®Úÿ h¢÷f™ k£úŸËçÿ-iÿÿ6|ªÿEšÒÿEšÒÿEšÒÿEšÒÿFšÒÿFšÒÿ $5ÿÿÿÿÿÿÿÿÿÿ<…µÿG›ÓÿGœÓÿGœÓÿGœÓÿGœÓÿC“Çÿ;Sÿ,ÿKžÔÿk®Úÿ h¢÷f™ k£úžÊçÿ>Äÿ7Nÿ ÿ5{©ÿC™ÑÿD™ÑÿD™ÑÿD™ÑÿD™Ñÿ ÿB]ÿ5z§ÿ5z§ÿ5{§ÿ5{§ÿ5{§ÿ5{§ÿ5{§ÿ7}«ÿD˜ÎÿEšÒÿEšÒÿEšÒÿEšÒÿA‘Æÿ:Rÿÿ6{¨ÿIÓÿl®Ùÿ h¡÷f™ k£úÊæÿA—Ïÿ<Âÿ6Mÿÿ4z©ÿB—ÐÿB˜ÐÿB˜ÐÿB˜Ðÿ ÿ!UvÿB˜ÐÿB˜ÐÿC˜ÐÿC˜ÐÿC˜ÐÿC˜ÐÿA”Êÿ/o™ÿA”ÉÿC™ÐÿC™ÑÿC™Ñÿ@‘Æÿ:Rÿÿ4y¦ÿD™ÑÿG›Òÿl®Ùÿ h¡÷f™ k£úœÉæÿ?–Îÿ?–Îÿ;Áÿ5Lÿÿ2y¨ÿ@–Ïÿ@–Ïÿ@–Ïÿ ÿ TuÿA—ÏÿA—ÏÿA—ÏÿA—ÏÿA—ÏÿA—Ïÿ5~®ÿÿ5~­ÿA—ÏÿB—Ðÿ>Åÿ9Qÿÿ3y¦ÿB˜ÐÿB˜ÐÿEšÑÿm®Ùÿ h¡÷f™ k£ú›Èåÿ>”Íÿ>”Íÿ>•Íÿ:ŒÁÿ3Iÿ ÿ1x§ÿ>•Îÿ>•Îÿ ÿ Suÿ?•Îÿ?•Îÿ?•Îÿ?•Îÿ?–Îÿ?–Îÿ3}­ÿÿ4}¬ÿ@–Îÿ@•Íÿ:Sÿÿÿ2Iÿ+j“ÿ?–ÎÿD™Ðÿn¯Ùÿ h¡÷f™ k£ú›Èåÿ<“Ìÿ<“Ìÿ<“Ìÿ<“Ìÿ8ŠÀÿ3Jÿÿ0w¦ÿ=”Íÿ ÿRtÿ=”Íÿ=”Íÿ=”Íÿ=”Íÿ=”Íÿ=”Íÿ2{¬ÿÿ2{«ÿ>•Íÿ>•Íÿ'd‹ÿSuÿSuÿYÿ/ÿA–Îÿp¯Ùÿ h¡÷f™ k£ú™Æäÿ8Êÿ8Êÿ8Êÿ8Êÿ9‘Êÿ9‘Êÿ5ˆ½ÿ3Kÿ ÿÿPsÿ9‘Ëÿ9‘Ëÿ:‘Ëÿ:‘Ëÿ:‘Ëÿ:’Ëÿ/zªÿÿ/y©ÿ:’Ëÿ:’Ëÿ:’Ëÿ;’Ëÿ;’Ëÿ;’ÌÿA^ÿ+ÿ?”Íÿr°Øÿ h¡÷f™ k£ú˜Åãÿ6Éÿ6Éÿ7Éÿ7Éÿ7Éÿ7Éÿ7Éÿ3†½ÿ2IÿÿPrÿ8Êÿ8Êÿ8Êÿ8Êÿ8Êÿ8Êÿ-x©ÿÿJjÿ Z€ÿ!Z€ÿ!Z€ÿ!Z€ÿ!Z€ÿFeÿÿ#`ˆÿ=“Ìÿs°Øÿ h¡÷f™ k£ú—Äãÿ5Èÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ5ŽÈÿ1†¼ÿ5Mÿ"_ˆÿ6ŽÉÿ6ŽÉÿ6Éÿ6Éÿ6Éÿ6Éÿ/€´ÿ%ÿ ÿ ÿ ÿ ÿ ÿ ÿ!2ÿ \‚ÿ6ŽÈÿ<’Ëÿt±Øÿ h¡÷f™ k£ú–Äâÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3Çÿ3Çÿ4Çÿ4Çÿ4Çÿ4Çÿ4Èÿ4Èÿ4Èÿ4Èÿ4Èÿ4Èÿ5Èÿ5Çÿ5Çÿ5Çÿ5Çÿ5Çÿ5Çÿ5Çÿ5ŽÈÿ6ŽÈÿ6ŽÉÿ;‘Êÿu±Øÿ h¡÷f™ k£ú•Ãâÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2ŒÆÿ2ŒÇÿ2ŒÇÿ2ŒÇÿ2ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3ŒÇÿ3Çÿ3Çÿ4Çÿ4Çÿ4Çÿ4Çÿ9Éÿv²Øÿ h¡÷f™ k£ú”Âáÿ/‰Åÿ/‰Åÿ/ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÆÿ1ŠÆÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2‹Æÿ2ŒÆÿ7Çÿw²Øÿ h¡÷f™ k£ú“Âáÿ-ˆÄÿ-ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.‰Äÿ.‰Äÿ.‰Äÿ.‰Äÿ/‰Äÿ/‰Äÿ/‰Åÿ/‰Åÿ/‰Åÿ/‰Åÿ/‰Åÿ/‰Åÿ/ŠÅÿ/ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ0ŠÅÿ5Æÿy²Øÿ h¡÷f™ k£ú’Áàÿ,‡Ãÿ,‡Ãÿ,‡Ãÿ,‡Ãÿ,‡Ãÿ+…Áÿ+ƒ¾ÿ+ƒ¾ÿ*ºÿ+€¹ÿ+€¸ÿ)}´ÿ)}´ÿ)|±ÿ-‡Âÿ-ˆÄÿ-ˆÄÿ-ˆÄÿ-ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.ˆÄÿ.‰Äÿ.‰Äÿ.‰Äÿ.‰Äÿ4ŒÅÿz³Øÿ h¡÷`Ÿh¢ü¾Ýÿy°Öÿs¬Ôÿp«Ðÿl¦Ìÿi¢ÈÿfŸÅÿdÂÿ[“¹ÿPаÿH¦ÿ=vœÿ4m“ÿ*cˆÿ!Y}ÿ*ƒ½ÿ2ŠÅÿ=‘ÈÿK˜ÌÿVžÎÿ]¢Ïÿ\¡Ïÿ\¡Ïÿ\ Îÿ[ŸËÿ[žÊÿ[Éÿ[Èÿ[Èÿ\žÉÿ:‡¸ÿ i¢ûi£Ø€µ×ÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ‰»Ûÿ„·ÚÿµÙÿ~µÙÿ~¶ÚÿpªÎÿ)‚½ÿ*…Áÿ*…Âÿ*…Âÿ(¹ÿ&x¯ÿ$s¦ÿ"lœÿ e“ÿ_‰ÿXÿQvÿQwÿ_ÿi¢ÿl¥ÿh¢âh¡}ZœÆû޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿh¢Éÿ)ƒ¾ÿ(„Àÿ(„Áÿ(„Áÿ&~¸ÿ$x¯ÿ"q¥ÿ j›ÿd’ÿ]ˆÿZ…ÿa•ÿh ÿx±ÿ/ˆÃÿm§þ h¡ j¢)q§ö޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿg¢Éÿ)‚¾ÿ&‚¿ÿ&‚¿ÿ&ƒÀÿ$}·ÿ"w®ÿ p¤ÿišÿd•ÿgœÿi¡ÿ {µÿ/ŠÄÿ1‹Æÿ-‡Áÿ h¢ÿ`Ÿ h¢ä…¹Ùÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿf¢Éÿ%t§ÿ%uªÿ&x®ÿ(}´ÿ&x®ÿ&v«ÿn¤ÿi¡ÿl¤ÿ#~¸ÿ0‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ {µÿ h¢æ h Œe¢Ëý޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿh¢Êÿ"¼ÿ"€½ÿ"€½ÿ"¼ÿr¬ÿi¢ÿn§ÿ&€ºÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿn¨þ i¢† eŸ5$x¬õ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿo¨Íÿ/†¿ÿ-„½ÿv°ÿj¢ÿv®ÿ+„¿ÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ-‡Âÿ h¡ÿi¥ i¢ÊH‘¿ü‡¹Úÿ¼Ûÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ޽Üÿ‹»Ûÿ€´×ÿ'z®ÿ7†¹ÿD“Èÿ3ŒÆÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ/ŠÅÿp«þh¡Æcœ g œi¢Þ g¡ï g¡ùm¤þsªø%z®õ0~²ô7…·ôA‹»õH¾ùO•ÃûC¼ÿ g ôi¢üUÌÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ&€»ÿk£ýj Íf™€¿ k¡f # i 3 g C h S hŸb g¡r g  g Ci£à[¢Ðÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ,†Àÿpªô h£ã gŸJ i¢çb¥Ñÿ1‹Æÿ1‹Æÿ1‹Æÿ1‹Æÿ1ŠÄÿx±÷i¢ói£zUªh¢ígªÔÿ1‹Æÿ1‹Æÿ6ŽÇÿ,„¼þj¤öh¢ª h¢i¢óm­×ÿ6ŽÈÿ<ŽÃÿsªôj¢Ë i¡. h ø„ºÝÿ9‡ºöh¡í g ^ g¡ük¤öh¡`Ÿ g t h¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüø?ø?ø?üüüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿüÿþÿþÿþÿÿÿÿÿÿÿÿ€ÿÿ€ÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿalire-1.2.1/scripts/installer/auto-install.js000066400000000000000000000063401430264165500212560ustar00rootroot00000000000000// Run with: // ./alire-x86_64-*.exe --platform minimal --script auto-install.js -v // To specify the installation directory, add InstallPrefix="C:\custom_install\path\" // To see graphically what's happening, remove "--platform minimal" var install_dir = installer.value("InstallPrefix") function Controller() { installer.setDefaultPageVisible(QInstaller.Introduction, true); var page = gui.pageWidgetByObjectName( "ComponentSelectionPage" ); page.selectComponent( "com.msys2.root" ); page.selectComponent( "com.msys2.root.base" ); installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false); installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); installer.setDefaultPageVisible(QInstaller.PerformInstallation, true); installer.setDefaultPageVisible(QInstaller.InstallationFinished, true); installer.setDefaultPageVisible(QInstaller.FinishedPage, true); ComponentSelectionPage.selectAll(); installer.autoRejectMessageBoxes(); var result = QMessageBox.question("quit.question", "Installer", "Do you want to quit the installer?", QMessageBox.Yes | QMessageBox.No); console.log("(console.log) result " + result); installer.setMessageBoxAutomaticAnswer("OverwriteTargetDirectory", QMessageBox.Yes); installer.setMessageBoxAutomaticAnswer("stopProcessesForUpdates", QMessageBox.Ignore); } Controller.prototype.IntroductionPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.TargetDirectoryPageCallback = function() { gui.currentPageWidget().TargetDirectoryLineEdit.setText(install_dir); gui.clickButton(buttons.NextButton); } Controller.prototype.StartMenuDirectoryPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.PerformInstallationPageCallback = function() { var page = gui.pageWidgetByObjectName("PerformInstallationPage"); installer.setAutomatedPageSwitchEnabled(true); gui.clickButton(buttons.NextButton); } Controller.prototype.InstallationFinishedPageCallback = function() { console.log("(console.log) InstallationFinishedPageCallback "); var checkBox = gui.pageWidgetByObjectName("RunItCheckBox"); console.log("typeof checkBox is " + typeof checkBox); assert(typeof checkBox === 'object'); var page = gui.pageWidgetByObjectName("InstallationFinishedPage"); gui.clickButton(buttons.NexthButton); } Controller.prototype.FinishedPageCallback = function() { console.log("(console.log) FinishedPageCallback "); // var checkBox = gui.pageWidgetByObjectName("RunItCheckBox"); // console.log("typeof checkBox is " + typeof checkBox); // assert(typeof checkBox === 'object'); var page = gui.pageWidgetByObjectName("FinishedPage"); page.RunItCheckBox.checked = false; gui.clickButton(buttons.FinishButton); } /* Controller.prototype.ComponentSelectionPageCallback = function() { var page = gui.pageWidgetByObjectName( "ComponentSelectionPage" ) page.deselectComponent( "com.nokia.ndk.tools.maemo.usbdriver" ) gui.clickButton( buttons.NextButton ) } */ alire-1.2.1/scripts/installer/make-alire-installer000066400000000000000000000110211430264165500222210ustar00rootroot00000000000000#!/usr/bin/env bash _thisdir="$(dirname $0)" test "${_thisdir}" = "." && _thisdir=${PWD} _ifwroot="${_thisdir}"/qt-ifw _arch=$(uname -m) _date=$(date +'%Y%m%d') _dateqif=$(date +'%Y-%m-%d') _version=${ALR_INSTALL_OS}-$(git log -1 --pretty=format:%h)-${_date} _filename=alire-${_arch}-${_version}.exe _filename_tar=alire-${_arch}-${_version}.tar.xz _filename_zip=alire-${_arch}-${_version}.zip _log="${_thisdir}"/tmp/installer-${_arch}-${_version}.log if [ "${_arch}" = "x86_64" ]; then _bitness=64 else _bitness=32 fi _archivegen=archivegen _binarycreator=binarycreator _installerbase=$(which installerbase) _newalirebase="${_thisdir}"/tmp/newalire _newalire=${_newalirebase}/alire declare -a undo_commands _exitcode=5 exit_with_undo() { for _cmd in ${undo_commands[@]}; do eval "${_cmd}" | tee -a "${_log}" done exit ${_exitcode} } exit_cleanly() { _exitcode=$1; shift; local _message=$1; shift; echo "${_message}" | tee -a "${_log}" exit_with_undo } do_seds() { find "${_ifwroot}" \( -name "package.xml" -or -name "config.xml" \) -exec sed -i "s|@DATE@|${_dateqif}|g" "{}" \; find "${_ifwroot}" \( -name "package.xml" -or -name "config.xml" \) -exec sed -i "s|@VERSION@|${_version}|g" "{}" \; undo_commands+=("undo_seds") } undo_seds() { find "${_ifwroot}" \( -name "package.xml" -or -name "config.xml" \) -exec sed -i "s|${_dateqif}<|@DATE@<|g" "{}" \; find "${_ifwroot}" \( -name "package.xml" -or -name "config.xml" \) -exec sed -i "s|${_version}<|@VERSION@<|g" "{}" \; } create_archives() { local _data="${_ifwroot}"/packages/com.alire.root/data [ -d "${_data}" ] && rm -rf "${_data}" mkdir -p "${_data}" local _dirs="${_newalire}/"* local _compress_cmd="${_archivegen} --compression 9 \"${_data}/alire.7z\" ${_dirs}" pushd / > /dev/null echo "Run: ${_compress_cmd} ..." | tee -a "${_log}" eval "${_compress_cmd}" 2>&1 | tee -a "${_log}" _result=$? if [ "${_result}" -eq "0" ]; then echo " archivegen succeeded. Created ${_data}/alire.7z" | tee -a "${_log}" else exit_cleanly "3" "archivegen failed. See ${_log}" fi popd > /dev/null pushd "${_newalirebase}" > /dev/null # Tar archive local _compress_tar="/usr/bin/tar --transform='s/:/_/g' --dereference --hard-dereference -cJf \"${_thisdir}/${_filename_tar}\" alire" echo "Run: ${_compress_tar} ..." | tee -a "${_log}" eval "${_compress_tar}" 2>&1 | tee -a "${_log}" _result=$? if [ "${_result}" -eq "0" ]; then echo " tar succeeded. Created " | tee -a "${_log}" else die "Alire tar compressing fail. See ${_log}" fi # ZIP archive local _compress_zip="/usr/bin/zip -r \"${_thisdir}/${_filename_zip}\" alire" echo "Run: ${_compress_zip} ..." | tee -a "${_log}" eval "${_compress_zip}" 2>&1 | tee -a "${_log}" _result=$? if [ "${_result}" -eq "0" ]; then echo " zip succeeded. Created " | tee -a "${_log}" else die "Alire zip compressing fail. See ${_log}" fi popd > /dev/null } # Add -v to get more information. make_installer() { eval "\"${_binarycreator}\" \ -t \"${_installerbase}\" \ -p \"${_ifwroot}/packages\" \ -c \"${_ifwroot}/config/config.xml\" \ --offline-only \ \"${_filename}\" \ -v" | tee -a "${_log}" } trap exit_with_undo 1 2 15 create_chroot_system() { [ -d "${_newalirebase}" ] && rm -rf "${_newalirebase}" mkdir -p "${_newalire}" pushd "${_newalire}" > /dev/null mkdir -p bin/ cp -r "$ALR_INSTALL_DIR"/* . mkdir -p share/alire/ cp "${_thisdir}/alr_icon.ico" share/alire/ popd > /dev/null } if [[ -z "$ALR_INSTALL_DIR" ]] then echo "Please set \$ALR_INSTALL_DIR" exit 1 fi if [[ -z "$ALR_INSTALL_OS" ]] then echo "Please set \$ALR_INSTALL_OS" exit 1 fi if ! [ -x "$(command -v ${_archivegen})" ]; then echo "Error: ${_archivegen} is not installed." >&2 exit 1 fi if ! [ -x "$(command -v ${_binarycreator})" ]; then echo "Error: ${_binarycreator} is not installed." >&2 exit 1 fi if ! [ -x "$(command -v ${_installerbase})" ]; then echo "Error: ${_installerbase} is not installed." >&2 exit 1 fi if ! [ -x "$(command -v zip)" ]; then echo "Error: zip is not installed." >&2 exit 1 fi if ! [ -x "$(command -v tar)" ]; then echo "Error: tar is not installed." >&2 exit 1 fi mkdir -p "${_newalire}" if [ -f "${_log}" ]; then rm "${_log}" fi echo "Creating Alire install dir system ${_newalire}" | tee -a "${_log}" create_chroot_system do_seds create_archives make_installer ls -la exit_cleanly "0" "All done, see ${_filename}" alire-1.2.1/scripts/installer/qt-ifw/000077500000000000000000000000001430264165500175105ustar00rootroot00000000000000alire-1.2.1/scripts/installer/qt-ifw/config/000077500000000000000000000000001430264165500207555ustar00rootroot00000000000000alire-1.2.1/scripts/installer/qt-ifw/config/config.xml000066400000000000000000000006021430264165500227420ustar00rootroot00000000000000 Alire @VERSION@ Alire The Alire Developers Alire ../../alr_installer_icon ../../alr_installer_icon alire-1.2.1/scripts/installer/qt-ifw/packages/000077500000000000000000000000001430264165500212665ustar00rootroot00000000000000alire-1.2.1/scripts/installer/qt-ifw/packages/com.alire.root/000077500000000000000000000000001430264165500241215ustar00rootroot00000000000000alire-1.2.1/scripts/installer/qt-ifw/packages/com.alire.root/meta/000077500000000000000000000000001430264165500250475ustar00rootroot00000000000000alire-1.2.1/scripts/installer/qt-ifw/packages/com.alire.root/meta/installscript.js000066400000000000000000000025321430264165500303020ustar00rootroot00000000000000function Component() { var targetDir = installer.value("TargetDir", "@ApplicationsDir@/Alire") installer.setValue("TargetDir", targetDir); installer.setDefaultPageVisible(QInstaller.Introduction, false); installer.setDefaultPageVisible(QInstaller.TargetDirectory, true); installer.setDefaultPageVisible(QInstaller.ComponentSelection, false); installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false); installer.setDefaultPageVisible(QInstaller.StartMenuSelection, true); installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); } Component.prototype.isDefault = function() { // select the component by default return true; } function createShortcuts() { var shortcuts = ["@StartMenuDir@/Alire.lnk", "@DesktopDir@/Alire.lnk"]; for (shortcut of shortcuts) { component.addOperation("CreateShortcut", "powershell", shortcut, "-NoExit -Command \"$env:Path += \"\"\";@TargetDir@\\bin\"\"\"; \"$host.UI.RawUI.BackgroundColor = \"\"\"DarkBlue\"\"\"; clear-host\"", "workingDirectory=@HomeDir@", "iconPath=@TargetDir@/share/alire/alr_icon.ico", "description=Start App"); } } Component.prototype.createOperations = function() { component.createOperations(); createShortcuts(); } alire-1.2.1/scripts/installer/qt-ifw/packages/com.alire.root/meta/package.xml000066400000000000000000000004151430264165500271640ustar00rootroot00000000000000 Alire Ada/SPARK Source Package Manager @VERSION@ @DATE@ true alire-1.2.1/scripts/python/000077500000000000000000000000001430264165500156255ustar00rootroot00000000000000alire-1.2.1/scripts/python/alire/000077500000000000000000000000001430264165500167215ustar00rootroot00000000000000alire-1.2.1/scripts/python/alire/__init__.py000066400000000000000000000000001430264165500210200ustar00rootroot00000000000000alire-1.2.1/scripts/python/alire/index.py000066400000000000000000000015211430264165500204010ustar00rootroot00000000000000import os.path import rtoml def is_index(path, semver): # Look for an "index.toml" file that contains a matching 'version = "x.x"' target = os.path.join(path, "index.toml") if not os.path.isfile(target): return False with open(target) as file: try: contents = rtoml.load(file) if "version" in contents: version = contents["version"] if version == semver: return True else: print(f"Version mismatch: {path} version is {version}, expected {semver}") return False else: print(f"Malformed index file: no version found inside {path}") except rtoml.TomlParsingError: print(f"Not a target: {target} failed to load as TOML") raise alire-1.2.1/scripts/python/alire/utils.py000066400000000000000000000007721430264165500204410ustar00rootroot00000000000000def fix_manifest_order(obj): # Not sure why rtoml is not honoring this order even for pure load/save cycles... oh well delayed = dict() # extract tables/table arrays: for key in obj: val = obj[key] if isinstance(val, dict) or \ (isinstance(val, list) and len(val) > 0 and isinstance(val[0], dict)): delayed[key] = val # reinsert at last position for key in delayed: obj.pop(key) obj[key] = delayed[key] return obj alire-1.2.1/scripts/python/manifest-version.py000077500000000000000000000013301430264165500214700ustar00rootroot00000000000000#!/usr/bin/env python3 # Find all crates in new index format and move origin-related fields to their own table # # The update is done in place and for all indexes found under the current directory. import alire.index import os import rtoml from alire import index, utils from pathlib import Path FROM_VERSION = "0.2" INTO_VERSION = "0.3" def fix_manifest(file): # file is the absolute path to a manifest print(f" Patching {file}...") with open(file, "r") as orig: data = orig.read() with open(file, "w") as updated: updated.write(f'metadata-version = "{INTO_VERSION}"\n') updated.write(data) alire.index.migrate_indexes(os.getcwd(), FROM_VERSION, INTO_VERSION, fix_manifest) alire-1.2.1/scripts/python/separate-origins.py000077500000000000000000000042031430264165500214550ustar00rootroot00000000000000#!/usr/bin/env python3 # Find all crates in new index format and move origin-related fields to their own table # # The update is done in place and for all indexes found under the current directory. import glob import os import rtoml from alire import index, utils from pathlib import Path FROM_VERSION = "0.1" INTO_VERSION = {"version": "0.2"} def fix_url(url): # For good measure, replace incorrect local paths return url.replace("file://", "file:") def fix_manifest(file): # file is the absolute path to a manifest print(f" Patching {file}...") try: manifest = rtoml.load(Path(file)) except rtoml.TomlParsingError as ex: print(f"FAILED to patch {file}: " + str(ex)) raise if "origin" not in manifest: print(f" WARNING: manifest without origin? {file}") return origin = dict() url = fix_url(manifest.pop("origin")) # Move any '@commit' info to a separate key origin["url"] = url.split('@')[0] if '@' in url: origin["commit"] = url.split('@')[1] if "origin-hashes" in manifest: origin["hashes"] = manifest.pop("origin-hashes") if "archive-name" in manifest: origin["archive-name"] = manifest.pop("archive-name") manifest["origin"] = origin # Rewrite patched manifest with open(file, "wt") as file: rtoml.dump(utils.fix_manifest_order(manifest), file) def migrate(path): print(f"Migrating {path}...") # Visit all nested TOML files. We do not check for proper placement. for file in glob.iglob(os.path.join(path, '**/*.toml'), recursive=True): if "/index.toml" not in file and "-external.toml" not in file: fix_manifest(file) # Finalize by updating the index version with open(os.path.join(path, "index.toml"), "wt") as file: rtoml.dump(INTO_VERSION, file) def traverse(path): if index.is_index(path, FROM_VERSION): migrate(path) else: # keep looking for nested indexes with os.scandir(path) as iterate: for child in iterate: if child.is_dir(): traverse(child.path) traverse(os.getcwd()) alire-1.2.1/scripts/python/split-crates.py000077500000000000000000000145541430264165500206250ustar00rootroot00000000000000#!/usr/bin/env python3 # Find all crates in old index format (single file per crate) and generate one # file per release. # # The update is done in place and for all indexes found under the current # directory. import os import re import rtoml from copy import deepcopy from pathlib import Path FROM_VERSION = "0.3" INTO_VERSION = {"version": "0.4"} def is_index(path): # Look for an "index.toml" file that contains a matching 'version = "x.x"' target = os.path.join(path, "index.toml") if not os.path.isfile(target): return False with open(target) as file: try: contents = rtoml.load(file) if "version" in contents: version = contents["version"] if version == FROM_VERSION: return True else: print(f"Version mismatch: {path} version is {version}, expected {FROM_VERSION}") return False else: print(f"Malformed index file: no version found inside {path}") except rtoml.TomlParsingError: print(f"Not a target: {target} failed to load as TOML") raise def fix_order(obj): delayed = dict() # extract tables/table arrays: for key in obj: val = obj[key] if isinstance(val, dict) or \ (isinstance(val, list) and len(val) > 0 and isinstance(val[0], dict)): delayed[key] = val # reinsert at last position for key in delayed: obj.pop(key) obj[key] = delayed[key] def write_externals(crate_dirname, name, general, external): print(f" Writing externals for {name}...") crate = deepcopy(general) crate["name"] = name crate["external"] = external fix_order(crate) with open(os.path.join(crate_dirname, name + "-external.toml"), "wt") as file: rtoml.dump(crate, file) def write_release(crate_dirname, name, general, version, release): print(f" Writing release {name}={version}...") crate = deepcopy(general) crate["name"] = name crate["version"] = version # Ensure proper merging for key in release: if key in crate: if isinstance(crate[key], dict) and isinstance(release[key], dict): # Merge these dicts: crate[key].update(release[key]) elif isinstance(crate[key], list) and isinstance(release[key], list): # Merge arrays crate[key] += release[key] else: raise RuntimeError(f"Key {key} is both in general and release sections in {crate_dirname} {version}") else: crate[key] = release[key] # Fix relative origins which now are one level deeper than before if "origin" in crate and "../" in crate["origin"]: crate['origin'] = crate['origin'].replace("../", "../../", 1) # Fix dictionary ordering to ensure atoms (or arrays of atoms) are before tables/arrays of tables. Otherwise, rtoml # does not do it for us, and we end with an invalid TOML serialization order (top-level atoms must come before any # tables/arrays). fix_order(crate) # Fix `depends-on` to be an array. No matter that dependencies are grouped. if "depends-on" in crate: deps = crate.pop("depends-on") crate["depends-on"] = [deps] with open(os.path.join(crate_dirname, name + f"-{version}.toml"), "wt") as file: rtoml.dump(crate, file) def fix_ver(version): # Ensure the version has major.minor.patch numbers, for regularity, and that pre-release/build info is kept semver = r"^(?P0|[1-9]\d*)(?:\.(?P0|[1-9]\d*))?(?:\.(?P0|[1-9]\d*))?" \ r"(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|" \ r"\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$" parts = re.match(semver, version).groupdict() return parts["major"] + \ (("." + parts["minor"]) if parts["minor"] is not None else ".0") + \ (("." + parts["patch"]) if parts["patch"] is not None else ".0") + \ (("-" + parts["prerelease"]) if parts["prerelease"] is not None else "") + \ (("+" + parts["buildmetadata"]) if parts["buildmetadata"] is not None else "") def split_crate(parent_dir, crate_file): # crate_file is an os.DirEntry that points to an old-style merged manifests file print(f" Splitting {crate_file.path}...") try: crates = rtoml.load(Path(crate_file.path)) name = crate_file.name.split('.')[0] crate_dirname = os.path.join(parent_dir, name) if not os.path.isdir(crate_dirname): os.mkdir(crate_dirname) general = crates.pop("general") if "external" in crates: write_externals(crate_dirname, name, general, crates.pop("external")) # remaining top-level tables must be versions (general was already pop'd) for version in crates: write_release(crate_dirname, name, general, fix_ver(version), crates[version]) # Clean up unneeded merged manifest os.remove(crate_file) except rtoml.TomlParsingError as ex: print(f"FAILED to migrate {crate_file}: " + str(ex)) raise def split_contents(path): # Path points to a two-letter folder containing merged manifests with os.scandir(path) as contents: for entry in contents: if entry.name.endswith(".toml"): split_crate(path, entry) else: print(f"EXTRANEOUS entry looking for manifests: {entry.path}") def migrate(path): print(f"Migrating {path}...") # All two-letter folders will contain crates... with os.scandir(path) as contents: for entry in contents: if len(entry.name) == 2 and entry.is_dir(): split_contents(entry.path) elif entry.name != "index.toml": print(f"EXTRANEOUS entry looking for shelves: {entry.path}") # Finalize by updating the index version with open(os.path.join(path, "index.toml"), "wt") as file: rtoml.dump(INTO_VERSION, file) def traverse(path): if is_index(path): migrate(path) else: # keep looking for nested indexes with os.scandir(path) as iterate: for child in iterate: if child.is_dir(): traverse(child.path) traverse(os.getcwd()) alire-1.2.1/src/000077500000000000000000000000001430264165500134045ustar00rootroot00000000000000alire-1.2.1/src/alire/000077500000000000000000000000001430264165500145005ustar00rootroot00000000000000alire-1.2.1/src/alire/README.md000066400000000000000000000000321430264165500157520ustar00rootroot00000000000000Common core functionality alire-1.2.1/src/alire/alire-conditional.adb000066400000000000000000000046161430264165500205540ustar00rootroot00000000000000package body Alire.Conditional is ------------------------- -- Available_From_TOML -- ------------------------- function Available_From_TOML (From : TOML_Adapters.Key_Queue) return For_Available.Tree is begin if From.Unwrap.Is_Null or else From.Unwrap.Keys'Length = 0 then return For_Available.Empty; else return For_Available.New_Value (Available' (Is_Available => From.Checked_Pop (TOML_Keys.Available, TOML.TOML_Boolean).As_Boolean)); end if; end Available_From_TOML; -------------------- -- Deps_From_TOML -- -------------------- function Deps_From_TOML (From : TOML_Adapters.Key_Queue) return Dependencies is use type Dependencies; begin return Result : Dependencies do for Pair of From.Pop.Iterate_On_Table loop Result := Result and Alire.Dependencies.From_TOML (+Pair.Key, Pair.Value); end loop; end return; end Deps_From_TOML; ------------------ -- Is_Available -- ------------------ function Is_Available (This : Availability; Env : Alire.Properties.Vector) return Boolean is Tree : constant Availability := This. Evaluate (Env); ------------------- -- Eval_Children -- ------------------- function Eval_Children (T : For_Available.Tree) return Boolean is use For_Available; begin if T.Root in Leaf_Node'Class then return T.Value.Is_Available; else return Result : Boolean := True do for Child of T loop case T.Conjunction is when Anded => Result := Result and Eval_Children (Child); when Ored => Result := Result or Eval_Children (Child); end case; end loop; end return; end if; end Eval_Children; begin -- Trivial case out of the way if This.Is_Empty or else Tree.Is_Empty then return True; end if; -- After evaluation, the tree is made of values/vectors that we can -- recursively evaluate. return Eval_Children (For_Available.Tree (Tree)); end Is_Available; end Alire.Conditional; alire-1.2.1/src/alire/alire-conditional.ads000066400000000000000000000130271430264165500205710ustar00rootroot00000000000000with Alire.Conditional_Trees; with Alire.Dependencies.Containers; with Alire.Interfaces; with Alire.Properties; with Alire.TOML_Adapters; with Alire.TOML_Keys; with Semantic_Versioning.Extended; with TOML; package Alire.Conditional with Preelaborate is ------------------ -- Dependencies -- ------------------ package For_Dependencies is new Conditional_Trees (Dependencies.Dependency, Dependencies.TTY_Image); subtype Dependencies is For_Dependencies.Tree; subtype Platform_Dependencies is Conditional.Dependencies with Dynamic_Predicate => Platform_Dependencies.Is_Unconditional; -- A plain tree without conditions (but might have OR nodes) subtype Forbidden_Dependencies is Platform_Dependencies with Dynamic_Predicate => not Forbidden_Dependencies.Contains_ORs; -- A plain tree without conditions or alternatives function New_Dependency (Name : Crate_Name; Version : Semantic_Versioning.Version) return Dependencies; -- Dependency on a exact version function New_Dependency (Name : Crate_Name; Versions : Semantic_Versioning.Extended.Version_Set) return Dependencies; -- Dependency on a version set function New_Dependency (Dep : Alire.Dependencies.Dependency) return Conditional.Dependencies renames For_Dependencies.New_Value; -- Convert a plain dependency into a tree containing a single leaf function Enumerate is new Conditional.For_Dependencies.Enumerate (Alire.Dependencies.Containers.List, Alire.Dependencies.Containers.Append); function No_Dependencies return Dependencies is (For_Dependencies.Empty); function Deps_From_TOML (From : TOML_Adapters.Key_Queue) return Dependencies; -- Expects a wrapped table of crate = version_set pairs: -- depends-on = { crate = version [...] } ---------------- -- Properties -- ---------------- package For_Properties is new Conditional_Trees (Properties.Property'Class, Properties.Image_Classwide); subtype Properties is For_Properties.Tree; subtype Unconditional_Properties is Conditional.Properties with Dynamic_Predicate => Unconditional_Properties.Is_Unconditional; -- A plain list of properties without dynamic expressions. function New_Property (Property : Alire.Properties.Property'Class) return Properties; function Enumerate is new Conditional.For_Properties.Enumerate (Alire.Properties.Vector, Alire.Properties.Append); function No_Properties return Properties is (For_Properties.Empty); -------------------- -- Availability -- -------------------- -- We reuse the conditional trees for availability. This was not possible -- in the general Ada index, but it is now with the more limited case -- expressions. This allows removing the separate hierarchy of code -- that was formerly used only for availability. type Available is new Interfaces.Classifiable and Interfaces.Tomifiable and Interfaces.Yamlable with record Is_Available : Boolean; end record; -- A wrapper on boolean to be able to store it in a conditional tree function Image (This : Available) return String; overriding function Key (This : Available) return String; overriding function To_TOML (This : Available) return TOML.TOML_Value; overriding function To_YAML (This : Available) return String; package For_Available is new Conditional_Trees (Available, Image); type Availability is new For_Available.Tree with null record; -- This is the actual type that encapsulates an expression tree function Available_From_TOML (From : TOML_Adapters.Key_Queue) return For_Available.Tree; -- Expects a single table "available = true/false" function Is_Available (This : Availability; Env : Alire.Properties.Vector) return Boolean; -- Evaluate availability in an environment. In addition to resolving the -- tree for the environment, we then need to traverse the tree evaluating -- the boolean expressions to arrive to a final boolean value. (Formerly -- done via Boolean_Trees). function Available_Default return Availability is (New_Value (Available'(Is_Available => True))); -- Availability default is True unless an expression is given private function New_Dependency (Name : Crate_Name; Version : Semantic_Versioning.Version) return Dependencies is (For_Dependencies.New_Value (Alire.Dependencies.New_Dependency (Name, Version))); function New_Dependency (Name : Crate_Name; Versions : Semantic_Versioning.Extended.Version_Set) return Dependencies is (For_Dependencies.New_Value (Alire.Dependencies.New_Dependency (Name, Versions))); function New_Property (Property : Alire.Properties.Property'Class) return Properties is (For_Properties.New_Value (Property)); function Image (This : Available) return String is (if This.Is_Available then "True" else "False"); overriding function Key (This : Available) return String is (TOML_Keys.Available); overriding function To_TOML (This : Available) return TOML.TOML_Value is (TOML.Create_Boolean (This.Is_Available)); overriding function To_YAML (This : Available) return String is (This.Key & ": " & This.Image); end Alire.Conditional; alire-1.2.1/src/alire/alire-conditional_trees-case_nodes.adb000066400000000000000000000154231430264165500240550ustar00rootroot00000000000000with AAA.Debug; with Alire.TOML_Adapters; with GNAT.IO; package body Alire.Conditional_Trees.Case_Nodes is type Case_Node is new Node with record Cases : Map; end record; overriding function Evaluate (This : Case_Node; Against : Properties.Vector) return Tree'Class; overriding function Flatten (This : Case_Node) return Tree'Class; overriding function Image (This : Case_Node) return String; overriding function Leaf_Count (This : Case_Node) return Positive; overriding procedure Print (This : Case_Node; Prefix : String; Verbose : Boolean; Sorted : Boolean); overriding procedure Recursive_Traversal (This : in out Case_Node; Apply : access procedure (Value : in out Values)); overriding procedure To_TOML (This : Case_Node; Parent : TOML.TOML_Value); overriding function To_YAML (This : Case_Node) return String; ------------------ -- Contains_ORs -- ------------------ overriding function Contains_ORs (This : Case_Node) return Boolean is (False); -------------------- -- Is_Conditional -- -------------------- overriding function Is_Conditional (This : Case_Node) return Boolean is (True); -------------------- -- Image_One_Line -- -------------------- function Image_One_Line (This : Map) return String is Result : UString; use UStrings; Keys : constant Case_Maps.Key_Array := This.Keys (Ada_Like => True, Exclude_Others => False); begin for I in Keys'Range loop Append (Result, String'( TOML_Adapters.Adafy (+Keys (I)) & " => " & This.Element (+Keys (I)).Image_One_Line)); if I /= Keys'Last then Append (Result, ", "); end if; end loop; return +Result; end Image_One_Line; ----------- -- Image -- ----------- overriding function Image (This : Case_Node) return String is ("(case " & This.Cases.Base.Name & " is " & Image_One_Line (This.Cases) & ")"); ----------- -- Print -- ----------- overriding procedure Print (This : Case_Node; Prefix : String; Verbose : Boolean; Sorted : Boolean) is use GNAT.IO; Tab : constant String := " "; begin Put_Line (Prefix & "case " & This.Cases.Base.Name & " is"); for Key of This.Cases.Keys (Ada_Like => True, Exclude_Others => False) loop Put_Line (Prefix & Tab & "when " & TOML_Adapters.Adafy (+Key) & " => " & (if not Verbose then This.Cases.Element (+Key).Image_One_Line else "")); if Verbose then Print (This.Cases.Element (+Key), Prefix & Tab & Tab, Verbose, Sorted); end if; end loop; end Print; -------------- -- Evaluate -- -------------- overriding function Evaluate (This : Case_Node; Against : Properties.Vector) return Tree'Class is Var_Seen : Boolean := False; Val_Seen : Boolean := False; begin return Eval : Tree := Empty do for Prop of Against loop -- Mark that we have seen a property with a value for this case if Prop.Key = This.Cases.Base.Key then Var_Seen := True; end if; for Value of This.Cases.Keys (Ada_Like => False, Exclude_Others => True) loop if Expressions.Satisfies (Property => Prop, Var_Key => This.Cases.Base.Key, Value => +Value) then Val_Seen := True; -- We take one of the explicit branches Eval.Append (This.Cases.Element (+Value).Evaluate (Against)); end if; end loop; end loop; -- Use others clause? if Var_Seen then if not Val_Seen and then This.Cases.Has_Others then Eval.Append (This.Cases.Other.Evaluate (Against)); end if; else Trace.Warning ("Missing variable in environment: " & This.Cases.Base.Key & "; 'other' expressions discarded"); -- Not sure if this may happen and what we should do in that case; -- take the others branch or drop it as if the var was NaN Trace.Debug (AAA.Debug.Stack_Trace); end if; end return; end Evaluate; ---------------- -- Leaf_Count -- ---------------- overriding function Leaf_Count (This : Case_Node) return Positive is function Count (This : Tree) return Natural renames Leaf_Count; begin return This.Cases.Size (Count'Access); end Leaf_Count; ------------- -- Flatten -- ------------- overriding function Flatten (This : Case_Node) return Tree'Class is Flat : Tree; begin for Key of This.Cases.Keys (Exclude_Others => True, Ada_Like => False) loop if not This.Cases.Element (+Key).Is_Empty then Flat := Flat and Tree (This.Cases.Element (+Key).Root.Flatten); end if; end loop; if This.Cases.Has_Others then if not This.Cases.Other.Is_Empty then Flat := Flat and Tree (This.Cases.Other.Root.Flatten); end if; end if; return Flat; end Flatten; ------------------------- -- Recursive_Traversal -- ------------------------- overriding procedure Recursive_Traversal (This : in out Case_Node; Apply : access procedure (Value : in out Values)) is ----------------- -- Local_Apply -- ----------------- procedure Local_Apply (Value : in out Tree) is begin Value.Visit_All (Apply); end Local_Apply; begin This.Cases.Visit_All (Local_Apply'Access); end Recursive_Traversal; ------------- -- To_TOML -- ------------- overriding procedure To_TOML (This : Case_Node; Parent : TOML.TOML_Value) is begin raise Unimplemented; -- Not yet needed, unless we implement full-fledged case exports end To_TOML; ------------- -- To_YAML -- ------------- overriding function To_YAML (This : Case_Node) return String is begin raise Unimplemented; -- Not yet needed, unless we implement full-fledged case exports return ""; end To_YAML; -------------- -- New_Case -- -------------- function New_Case (Cases : Map) return Tree is (To_Tree (Case_Node'(Cases => Cases))); end Alire.Conditional_Trees.Case_Nodes; alire-1.2.1/src/alire/alire-conditional_trees-case_nodes.ads000066400000000000000000000012361430264165500240730ustar00rootroot00000000000000with Alire.Expressions.Maps; private generic package Alire.Conditional_Trees.Case_Nodes with Preelaborate is -- NOTE: this package must be instantiated at library level -- This package provides the case-holding nodes in a conditional tree. -- Since clients retrieve such nodes as trees (New_Case below), the whole -- new Node class can be hidden in the body. package Case_Maps is new Expressions.Maps (Tree); -- Every case value points to a subtree subtype Map is Case_Maps.Map; function New_Case (Cases : Map) return Tree; -- Wrap an expression map as a case node for the conditional tree end Alire.Conditional_Trees.Case_Nodes; alire-1.2.1/src/alire/alire-conditional_trees-toml_load.adb000066400000000000000000000145511430264165500237250ustar00rootroot00000000000000with AAA.Strings; with Alire.Conditional_Trees.Case_Nodes; with Alire.Errors; with Alire.TOML_Keys; package body Alire.Conditional_Trees.TOML_Load is Others_Key : String renames TOML_Keys.Case_Others; package Case_Nodes is new Conditional_Trees.Case_Nodes; ---------- -- Load -- ---------- function Load (From : TOML_Adapters.Key_Queue; Loader : not null Static_Loader; Resolve : Boolean; Strict : Boolean) return Tree is use TOML; ------------------ -- Process_Case -- ------------------ -- Resolve a single case expression, creating a case node. For the -- leaves, it may recursively call Load. function Process_Case (Parent : TOML_Adapters.Key_Queue; Root_Key : String; Case_Key : String; Case_Val : TOML_Value) return Tree is use AAA.Strings; --------------------- -- Process_Entries -- --------------------- function Process_Entries (Case_Table : TOML_Adapters.Key_Queue) return Tree is Var : constant Expressions.Variable := Expressions.From (Key => Head (Tail (Case_Key, '('), ')')); Map : Case_Nodes.Map := Case_Nodes.Case_Maps.Empty (Var); -- The map only accepts values matching the Variable begin loop declare Item_Val : TOML_Value; Item_Key : constant String := Case_Table.Pop (Item_Val); Values : constant AAA.Strings.Vector := AAA.Strings.Split (Item_Key, '|', Trim => True); -- A single item may store several cases separated by '|' begin exit when Item_Key = ""; -- Do an initial vetting before loading for Value of Values loop if Value /= Others_Key and then not Map.Base.Is_Valid (Value) then if Strict then Case_Table.Recoverable_Error ("invalid enumeration value: " & Item_Key); else Trace.Debug (Errors.Stack ("unknown enumeration value: " & Item_Key)); end if; end if; end loop; -- Load the value and assign to the appropriate entries declare Branch : constant Tree := Load -- recursively load the branch (From => Case_Table.Descend (Key => Root_Key, Value => Item_Val, Context => Item_Key), Loader => Loader, Resolve => Resolve, Strict => Strict); begin for Value of Values loop Map.Insert (Value, Branch); end loop; end; end; end loop; return Case_Nodes.New_Case (Map); end Process_Entries; begin if Has_Prefix (Case_Key, "case(") and then Case_Key (Case_Key'Last) = ')' then return Process_Entries (Parent.Descend (Case_Val, Case_Key)); else Parent.Checked_Error ("'case(..)' expected; got: " & Case_Key); end if; end Process_Case; -------------------------- -- Process_Nested_Table -- -------------------------- -- Val is a table that holds either values to be directly loaded by the -- static loader, or expressions to be resolved by us prior to loading. function Process_Nested_Table (Key : String; Val : TOML_Value) return Tree is Table : constant TOML_Adapters.Key_Queue := From.Descend (Val, "values"); begin return Result : Tree do -- We need to pop and resolve expressions, and send all the -- remaining keys together to the static loader. loop declare Case_Val : TOML_Value; Case_Key : constant String := Table.Pop_Expr ("case(", Case_Val); begin exit when Case_Key = ""; -- Table contains no more cases Result.Append (Process_Case (From, Key, Case_Key, Case_Val)); end; end loop; -- Finally, process remaining contents as a single static value if Val.Keys'Length > 0 then Result.Append (Loader (From.Descend (Key => Key, Value => Val, Context => Key))); end if; end return; end Process_Nested_Table; begin -- Ensure only one top-level value provided From.Assert (From.Unwrap.Kind = TOML_Table, "Expected a table but got: " & From.Unwrap.Kind'Image); From.Assert (From.Unwrap.Keys'Length = 1, "Expected a single entry in table, but got:" & From.Unwrap.Keys'Length'Img); -- Get the key = ... and process it declare Val : TOML_Value; Key : constant String := From.Pop (Val); begin -- Val might be a dynamic expression, or a value to be processed by -- the static loader. If the value isn't a table, certainly it isn't -- an expression. if Val.Kind /= TOML_Table then return Loader (From.Descend (Key => Key, Value => Val, Context => Key)); else -- See what the Val table holds return Process_Nested_Table (Key, Val); end if; end; end Load; end Alire.Conditional_Trees.TOML_Load; alire-1.2.1/src/alire/alire-conditional_trees-toml_load.ads000066400000000000000000000020741430264165500237430ustar00rootroot00000000000000with Alire.TOML_Adapters; generic package Alire.Conditional_Trees.TOML_Load is -- NOTE: this package must be instantiated at library level type Static_Loader is access function (From : TOML_Adapters.Key_Queue) return Tree; -- A function that receives a table "key = ...", with key being the name of -- the value in the index (e.g., available, depends-on, executables, ...). -- The loaded values are returned already as an (unconditional) tree. function Load (From : TOML_Adapters.Key_Queue; Loader : not null Static_Loader; Resolve : Boolean; Strict : Boolean) return Tree; -- Expects a "key = val" or "key.expr = val" table. Takes care of resolving -- any dynamic expressions. Currently, only 'case()' is understood. When -- resolve, dynamic expressions are resolved; otherwise Checked_Error will -- be raised. When Resolve and Strict, unknown values in cases are not -- allowed. If not Resolve, Strict is ignored. end Alire.Conditional_Trees.TOML_Load; alire-1.2.1/src/alire/alire-conditional_trees.adb000066400000000000000000000437731430264165500217650ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; with Alire.TOML_Adapters; with GNAT.IO; package body Alire.Conditional_Trees is Tab : constant String := " "; --------------------- -- Image_Classwide -- --------------------- function Image_Classwide (This : Node'Class) return String is (This.Image); ------------- -- To_YAML -- ------------- overriding function To_YAML (This : Tree) return String is (if This.Is_Empty then "" else This.Element.To_YAML); overriding function To_YAML (V : Leaf_Node) return String is (V.Value.Constant_Reference.To_YAML); overriding function To_YAML (V : Vector_Node) return String is (Non_Primitive.To_YAML (V.Values)); ----------- -- Image -- ----------- overriding function Image (V : Leaf_Node) return String is (Image (V.Value.Constant_Reference)); ----------------- -- Conjunction -- ----------------- function Conjunction (This : Vector_Node) return Conjunctions is (This.Conjunction); ----------- -- Image -- ----------- overriding function Image (V : Vector_Node) return String is ("(" & (if V.Conjunction = Anded then Non_Primitive.One_Liner_And (V.Values) else Non_Primitive.One_Liner_Or (V.Values)) & ")"); ----------------- -- Conjunction -- ----------------- function Conjunction (This : Tree) return Conjunctions is (Vector_Node'Class (This.Element).Conjunction); ----------------- -- First_Child -- ----------------- function First_Child (This : Tree) return Tree is (if This.Is_Value then This else To_Tree (Vector_Node (This.Root).Values.First_Element)); -------------- -- New_Leaf -- -------------- function New_Leaf (V : Values) return Tree is (To_Holder (Leaf_Node'(Value => Definite_Values.To_Holder (V)))); ----------- -- Empty -- ----------- function Empty return Tree is (Holders.Empty_Holder with null record); -------------- -- Is_Empty -- -------------- overriding function Is_Empty (This : Tree) return Boolean is (Holders.Holder (This).Is_Empty); -------------------- -- Image_One_Line -- -------------------- function Image_One_Line (This : Tree) return String is (if This.Is_Empty then "(empty)" else This.Element.Image); ---------------------------- -- All_But_First_Children -- ---------------------------- function All_But_First_Children (This : Tree) return Tree is begin if This.Is_Value then return Empty; else declare Children : Vectors.Vector := Vector_Node (This.Root).Values; begin Children.Delete_First; return To_Holder (Vector_Node'(This.Conjunction, Children)); end; end if; end All_But_First_Children; ------------- -- Flatten -- ------------- -- Remove redundant and/or subtrees by merging upwards. procedure Flatten (Inner : in out Vector_Node; This : Node'Class; Conj : Conjunctions) is begin if This in Leaf_Node then Inner.Values.Append (This); elsif This in Vector_Node then -- Flatten only if conjunction matches, otherwise just append -- subtree. if Vector_Node (This).Conjunction = Conj then for Child of Vector_Node (This).Values loop Flatten (Inner, Child, Conj); end loop; else Inner.Values.Append (This); end if; else -- Unknown node class, just append subtree: Inner.Values.Append (This); end if; end Flatten; ------------- -- Flatten -- ------------- overriding function Flatten (This : Vector_Node) return Tree'Class is Result : Tree; begin for Child of This.Values loop case This.Conjunction is when Anded => Result := Result and Tree (Child.Flatten); when Ored => Result := Result or Tree (Child.Flatten); end case; end loop; return Result; end Flatten; ---------- -- Join -- ---------- function Join (L, R : Tree; Op : Conjunctions) return Tree is Inner : Vector_Node := (Conjunction => Op, Values => <>); begin if not L.Is_Empty then Flatten (Inner, L.Constant_Reference, Op); end if; if not R.Is_Empty then Flatten (Inner, R.Constant_Reference, Op); end if; if Inner.Values.Is_Empty then return Empty; else -- Convert vector with single value into value if Inner.Values.Length in 1 then return Inner.Values.First_Element.To_Tree; end if; return To_Holder (Inner); end if; end Join; ----------- -- "and" -- ----------- function "and" (L, R : Tree) return Tree is (Join (L, R, Anded)); ---------- -- "or" -- ---------- function "or" (L, R : Tree) return Tree is (Join (L, R, Ored)); ------------ -- Append -- ------------ procedure Append (L : in out Tree; R : Tree) is begin L := L and R; end Append; ---------------- -- Leaf_Count -- ---------------- overriding function Leaf_Count (This : Vector_Node) return Positive is Count : Natural := 0; begin for Child of This.Values loop Count := Count + Child.Leaf_Count; end loop; return Count; end Leaf_Count; ----------------- -- Materialize -- ----------------- function Materialize (This : Tree; Against : Properties.Vector) return Collection is Col : Collection; Pre : constant Tree := This.Evaluate (Against); procedure Visit (Inner : Node'Class) is begin if Inner in Leaf_Node then Append (Col, Leaf_Node (Inner).Value.Constant_Reference); elsif Inner in Vector_Node then if Vector_Node (Inner).Conjunction = Anded then for Child of Vector_Node (Inner).Values loop Visit (Child); end loop; else raise Constraint_Error with "OR trees cannot be materialized as list"; end if; elsif Inner.Is_Conditional then raise Program_Error with "No conditional nodes should remain after tree evaluation"; else raise Program_Error with "Unconditional node of unknown class"; end if; end Visit; begin if not Pre.Is_Empty then Visit (Pre.Constant_Reference); end if; return Col; end Materialize; --------------- -- Enumerate -- --------------- function Enumerate (This : Tree) return Collection is Col : Collection with Warnings => Off; Flat : constant Tree := (if This.Is_Empty then This else Tree (This.Constant_Reference.Flatten)); begin if not Flat.Is_Empty then if Flat.Constant_Reference in Leaf_Node then Append (Col, Leaf_Node (Flat.Constant_Reference.Element.all) .Value.Constant_Reference); elsif Flat.Constant_Reference in Vector_Node then for Child of Vector_Node (Flat.Constant_Reference.Element.all) .Values loop Append (Col, Leaf_Node (Child).Value.Constant_Reference); end loop; else raise Program_Error with "Flattened nodes must be leaves or vectors"; end if; end if; return Col; end Enumerate; ------------- -- As_List -- ------------- function As_List (This : Tree) return Value_Lists.List is function Enumerate is new Conditional_Trees.Enumerate (Value_Lists.List, Value_Lists.Append); begin return Enumerate (This); end As_List; -------------- -- Evaluate -- -------------- overriding function Evaluate (This : Vector_Node; Against : Properties.Vector) return Tree'Class is Result : Vector_Node; begin Result.Conjunction := This.Conjunction; for Child of This.Values loop declare Eval : constant Tree'Class := Child.Evaluate (Against); begin if not Eval.Is_Empty then Result.Values.Append (Eval.Root); end if; end; end loop; return Result.To_Tree and Empty; -- ANDing with empty ensures the vector is flattened. Cosmetic. end Evaluate; -------------- -- Evaluate -- -------------- function Evaluate (This : Tree; Against : Properties.Vector) return Tree is begin if This.Is_Empty then return This; else return Tree (This.Root.Evaluate (Against)); end if; end Evaluate; ------------------ -- Contains_ORs -- ------------------ function Contains_ORs (This : Tree) return Boolean is ((not This.Is_Empty) and then This.Root.Contains_ORs); ---------------------- -- Is_Unconditional -- ---------------------- function Is_Unconditional (This : Tree) return Boolean is (This.Is_Empty or else not This.Root.Is_Conditional); ---------------------- -- Iterate_Children -- ---------------------- procedure Iterate_Children (This : Tree; Visitor : access procedure (CV : Tree)) is begin if not This.Is_Empty then if This.Is_Value then Visitor (This); elsif This.Is_Vector then for Inner of Vector_Node (This.Root).Values loop Visitor (Tree'(To_Holder (Inner))); end loop; else raise Constraint_Error with "Node is not a vector"; end if; end if; end Iterate_Children; ----------- -- Print -- ----------- overriding procedure Print (This : Leaf_Node; Prefix : String; Verbose : Boolean; Sorted : Boolean := False) is pragma Unreferenced (Verbose, Sorted); begin GNAT.IO.Put_Line (Prefix & Image (This.Value.Constant_Reference)); end Print; overriding procedure Print (This : Vector_Node; Prefix : String; Verbose : Boolean; Sorted : Boolean) is package Maps is new Ada.Containers.Indefinite_Ordered_Maps (String, Node'Class); begin if Verbose then case This.Conjunction is when Anded => GNAT.IO.Put_Line (Prefix & "All of:"); when Ored => GNAT.IO.Put_Line (Prefix & "First available of:"); end case; end if; if Sorted then declare Map : Maps.Map; begin for Child of This.Values loop Map.Insert (Child.Image, Child); end loop; for Child of Map loop Print (Child, Prefix & (if Verbose then Tab else ""), Verbose, Sorted); end loop; end; else for Child of This.Values loop Print (Child, Prefix & (if Verbose then Tab else ""), Verbose, Sorted); end loop; end if; end Print; ----------- -- Print -- ----------- procedure Print (This : Tree; Prefix : String := ""; Verbose : Boolean := False; And_Or : Boolean := True; Sorted : Boolean := False) is begin if This.Is_Empty then GNAT.IO.Put_Line (Prefix & "(empty)"); else Print (This.Root, Prefix, And_Or or Verbose, Sorted); end if; end Print; ------------------- -- Tree_TOML_Add -- ------------------- procedure Tree_TOML_Add (Table : TOML.TOML_Value; Key : String; Val : TOML.TOML_Value) is use AAA.Strings; -- Add one property to the parent table. -- Atomic values are automatically converted into arrays, if -- more than one for the same key appears (e.g., executables) -- Table values with same key are merged in a single table (e.g., -- dependencies) -- Array values with same key are consolidated in a single array -- (e.g., actions, which are created as an array of tables). begin -- Get properties given as nested tables out of the way first, by -- getting the top-level key and using the nested table as the -- actual value. if (for some Char of Key => Char = '.') then Tree_TOML_Add (Table, Key => Head (Key, '.'), Val => TOML_Adapters.Create_Table (Tail (Key, '.'), Val)); return; end if; -- Regular processing of a top-level property pragma Assert (Table.Kind = TOML.TOML_Table); if Table.Has (Key) then declare Current : constant TOML.TOML_Value := Table.Get (Key); begin case Current.Kind is when TOML_Table => Table.Set (Key, TOML_Adapters.Merge_Tables (Current, Val)); when TOML_Array => case Val.Kind is when TOML.Atom_Value_Kind | TOML.TOML_Table => Current.Append (Val); when TOML.TOML_Array => -- Consolidate the array into one for I in 1 .. Val.Length loop Current.Append (Val.Item (I)); end loop; end case; when TOML.Atom_Value_Kind => -- Convert to array declare Replace : constant TOML.TOML_Value := TOML.Create_Array; begin Replace.Append (Current); Replace.Append (Val); Table.Set (Key, Replace); end; end case; end; else Table.Set (Key, Val); end if; end Tree_TOML_Add; ------------- -- To_TOML -- ------------- overriding procedure To_TOML (This : Leaf_Node; Parent : TOML.TOML_Value) is begin Tree_TOML_Add (Parent, This.Value.Constant_Reference.Key, This.Value.Constant_Reference.To_TOML); end To_TOML; overriding procedure To_TOML (This : Vector_Node; Parent : TOML.TOML_Value) is begin case This.Conjunction is when Anded => null; when Ored => raise Unimplemented with "Not yet in index specification"; end case; for Child of This.Values loop To_TOML (Child, Parent); end loop; end To_TOML; overriding function To_TOML (This : Tree) return TOML.TOML_Value is Root_Table : constant TOML.TOML_Value := TOML.Create_Table; begin if not This.Is_Empty then This.Root.To_TOML (Root_Table); end if; return Root_Table; end To_TOML; ----------------- -- ITERATORS -- ----------------- type Forward_Iterator is new Iterators.Forward_Iterator with record Children : Vectors.Vector; end record; ----------- -- First -- ----------- overriding function First (Object : Forward_Iterator) return Cursor is (if Object.Children.Is_Empty then Cursor (Vectors.No_Element) else Cursor (Object.Children.First)); ---------- -- Next -- ---------- overriding function Next (This : Cursor) return Cursor is (Cursor (Vectors.Next (Vectors.Cursor (This)))); ---------- -- Next -- ---------- overriding function Next (Object : Forward_Iterator; Position : Cursor) return Cursor is (Next (Position)); ----------------- -- Has_Element -- ----------------- overriding function Has_Element (This : Cursor) return Boolean is (Vectors.Has_Element (Vectors.Cursor (This))); ------------- -- Iterate -- ------------- function Iterate (Container : Tree) return Iterators.Forward_Iterator'Class is begin if Container.Is_Empty then return Forward_Iterator'(others => <>); elsif Container.Constant_Reference in Leaf_Node then return Single : Forward_Iterator do Single.Children.Append (Container.Element); end return; elsif Container.Constant_Reference not in Vector_Node then raise Constraint_Error with "Cannot iterate over non-vector conditional value"; end if; return Forward_Iterator' (Children => Vector_Node (Container.Element).Values); end Iterate; --------------------- -- Indexed_Element -- --------------------- function Indexed_Element (Container : Tree; Pos : Cursor) return Tree is (Tree'(To_Holder (Element (Pos)))); ------------------------- -- Recursive_Traversal -- ------------------------- overriding procedure Recursive_Traversal (This : in out Leaf_Node; Apply : access procedure (Value : in out Values)) is begin Apply (This.Value.Reference); end Recursive_Traversal; ------------------------- -- Recursive_Traversal -- ------------------------- overriding procedure Recursive_Traversal (This : in out Vector_Node; Apply : access procedure (Value : in out Values)) is begin for Node of This.Values loop Node.Recursive_Traversal (Apply); end loop; end Recursive_Traversal; --------------- -- Visit_All -- --------------- procedure Visit_All (This : in out Tree; Apply : access procedure (Value : in out Values)) is begin if This.Is_Empty then return; else This.Reference.Recursive_Traversal (Apply); end if; end Visit_All; end Alire.Conditional_Trees; alire-1.2.1/src/alire/alire-conditional_trees.ads000066400000000000000000000405731430264165500220010ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; use Ada.Containers; with Ada.Iterator_Interfaces; with Alire.Interfaces; with Alire.Properties; with Alire.Utils.YAML; private with Ada.Containers.Indefinite_Holders; private with Ada.Containers.Indefinite_Vectors; with TOML; use all type TOML.Any_Value_Kind; generic type Values (<>) is new Interfaces.Classifiable and Interfaces.Tomifiable and Interfaces.Yamlable with private; with function Image (V : Values) return String; package Alire.Conditional_Trees with Preelaborate is ---------- -- Node -- ---------- -- To allow unforeseeable case nodes, we use classwide nodes in the tree. -- A few of those nodes are already known here and can be used elsewhere, -- like leaf nodes (a single value) and vector nodes (anded/ored subtrees). -- Condition nodes check a single requisite tree as if/then/else. -- Case nodes, defined in the generic child Conditional_Trees.Cases, are a -- more compact alternative to if/then/elif/elif/elif/else trees. type Node is abstract new Interfaces.Yamlable with private; function Contains_ORs (This : Node) return Boolean is abstract; -- A tree/node containing OR nodes requires selection of one of these -- during dependency resolution. function Is_Conditional (This : Node) return Boolean is abstract; -- Recursively say if there are conditional nodes under this one. -- In general, we say a tree is conditional if it contains expressions that -- depend on environment properties. In the old index, those where the -- if/then/else expressions, and in the new index there are case exprs. -- Prior to dependency resolution, a tree must be evaluated using the -- available properties to remove conditional expressions. function Image (This : Node) return String is abstract; -- Single-line image for single-line tree image (used by Available). procedure Print (This : Node; Prefix : String; Verbose : Boolean; Sorted : Boolean) is abstract; -- Multi-line printing to stdout with tabulation (used by Props and -- Deps). Sorting affects only multi-value nodes (vectors, cases) and is -- interesting for dependencies (to show them alphabetically) but not for -- properties (some of them have order, like actions). function Leaf_Count (This : Node) return Positive is abstract; -- Return leaves under this node; for non-leaf nodes, obtain recursively. procedure Recursive_Traversal (This : in out Node; Apply : access procedure (Value : in out Values)) is abstract; -- Enables full traversal with modification of children procedure To_TOML (This : Node; Parent : TOML.TOML_Value) is abstract with Pre'Class => Parent.Kind = TOML.TOML_Table; ---------- -- Tree -- ---------- type Tree is new Interfaces.Tomifiable and Interfaces.Yamlable with private with Default_Iterator => Iterate, Iterator_Element => Tree, Constant_Indexing => Indexed_Element; -- Recursive type that stores values, possibly with case expressions. -- Cases must be satisfied by some environment property or else their -- associated values will be dropped from the tree. This structure is thus -- used to store conditional/dynamic properties and dependencies. -- Iteration is only over direct children, when the tree is AND/OR vector. function Flatten (This : Node) return Tree'Class is abstract with Post'Class => Flatten'Result.Is_Empty or else Flatten'Result.Is_Value or else Flatten'Result.Is_Vector; -- Above Post kept for reference but gnat bugs out during instantiation. -- Recursively merge all subtree elements in a single value or vector. It -- can result in an empty tree if a vector is empty, so it returns a tree. function Root (This : Tree) return Node'Class with Pre => not This.Is_Empty; function Is_Iterable (This : Tree) return Boolean; -- Iterators visit only immediate values (leaves or vectors). Thus, this -- function says if a tree root node is a value or a vector, and can be -- iterated over. function Leaf_Count (This : Tree) return Natural; -- Recursive descent to obtain the leaf count of the tree. generic type Collection is private; with procedure Append (C : in out Collection; V : Values; Count : Count_Type := 1); -- This Append must honor "append" semantics (i.e., don't reorder); -- otherwise actions, that have a user-defined order, would break. function Materialize (This : Tree; Against : Properties.Vector) return Collection with Pre => not This.Contains_ORs; -- Materialize against the given properties, and return as list. NOTE: -- this presumes there are no OR conditions along the tree. In Alire -- context, this is always true for properties and potentially never -- for dependencies (so, for the latter, must be used after dependency -- resolution). generic type Collection is private; with procedure Append (C : in out Collection; V : Values; Count : Count_Type := 1); function Enumerate (This : Tree) return Collection; -- Return all value nodes, regardless of conditions/conjunctions. -- This is used for textual search and has no semantic meaning. function Evaluate (This : Tree; Against : Properties.Vector) return Tree with Post => Evaluate'Result.Is_Unconditional; -- Materialize against the given properties, returning values as an -- unconditional tree. NOTE: the result is unconditional but can still -- contain a mix of AND/OR subtrees. function Is_Empty (This : Tree) return Boolean; function Empty return Tree; function Image_One_Line (This : Tree) return String; -- See corresponding Node.Image_One_Line. function Is_Unconditional (This : Tree) return Boolean; -- Recursively looks for nodes that are not leaves or conjunctions. -- TODO: refactor as Is_Conditional to match the Node one. function Contains_ORs (This : Tree) return Boolean; -- Delayed node primitives that require the Tree type follow -- function Evaluate (This : Node; Against : Properties.Vector) return Tree'Class is abstract with Post'Class => Evaluate'Result.Is_Unconditional; -- Check properties in conditional nodes to return the applicable elements. -- Returns a Tree because it could result in an empty tree. procedure Print (This : Tree; Prefix : String := ""; Verbose : Boolean := False; And_Or : Boolean := True; Sorted : Boolean := False); -- Use And_Or = false when only And can appear, in which case there is no -- need to distinguish and the output is slightly more compact. overriding function To_TOML (This : Tree) return TOML.TOML_Value with Post => To_TOML'Result.Kind = TOML.TOML_Table; -- Every tree element can provide a key under which to be filed -- This is used for key = value leaves and [table] names in non-leaves. overriding function To_YAML (This : Tree) return String; -- The basic known node classes follow. Extra classes for case expressions -- are defined in the Cases child package. This enables having any number -- of environment variables properly typed in the tree, including future -- unforeseen ones. -------------- -- LEAVES -- -------------- type Leaf_Node is new Node with private; -- A leaf node stores a single static value. function New_Leaf (V : Values) return Tree; function New_Value (V : Values) return Tree renames New_Leaf; function Is_Value (This : Tree) return Boolean; function Value (This : Tree) return Values with Pre => This.Root in Leaf_Node; --------------- -- VECTORS -- --------------- type Vector_Node is new Node with private; -- A vector node is a conjunction or disjunction of the list of stored -- child nodes. function "and" (L, R : Tree) return Tree; -- Concatenation function "and" (L : Tree; R : Values) return Tree is ("and" (L, New_Value (R))); procedure Append (L : in out Tree; R : Tree); -- Same as L := L and R; function "or" (L, R : Tree) return Tree; type Conjunctions is (Anded, Ored); function Is_Vector (This : Tree) return Boolean; function Conjunction (This : Tree) return Conjunctions with Pre => This.Root in Vector_Node; procedure Visit_All (This : in out Tree; Apply : access procedure (Value : in out Values)); -- Depth-first recursive traversal of all values, irrespective of node type -- Following iterators/accessors are used during dependency resolution, and -- for that reason they will fail for conditional trees. procedure Iterate_Children (This : Tree; Visitor : access procedure (CV : Tree)) with Pre => This.Root in Leaf_Node or else This.Root in Vector_Node; -- There is "of" notation below, but that one sometimes causes compilation -- bugs when using this package as generic formal. function First_Child (This : Tree) return Tree; -- This, when This is a leaf, or the first child, when a vector. Error -- otherwise. function All_But_First_Children (This : Tree) return Tree; -- Empty, when This is a leaf, or all children but first, when vector. -- Error otherwise. ----------------- -- ITERATORS -- ----------------- -- This iterator works only on Value/Vector nodes and is not recursive. type Cursor is private; function Has_Element (This : Cursor) return Boolean; function Next (This : Cursor) return Cursor; package Iterators is new Ada.Iterator_Interfaces (Cursor, Has_Element); function Iterate (Container : Tree) return Iterators.Forward_Iterator'Class with Pre => Container.Is_Iterable; -- Returns our own iterator. function Indexed_Element (Container : Tree; Pos : Cursor) return Tree; function To_Tree (N : Node'Class) return Tree; package Value_Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Values); function As_List (This : Tree) return Value_Lists.List; -- Default Enumerate implementation. Remember that this does not resolve -- expressions; merely flattens all leaf nodes. private type Node is abstract new Interfaces.Yamlable with null record; function Image_Classwide (This : Node'Class) return String; package Holders is new Ada.Containers.Indefinite_Holders (Node'Class); package Vectors is new Ada.Containers.Indefinite_Vectors (Positive, Node'Class); type Cursor is new Vectors.Cursor; ---------- -- Tree -- ---------- type Tree is new Holders.Holder and Interfaces.Tomifiable and Interfaces.Yamlable with null record; -- Instead of dealing with pointers and finalization, we use this -- class-wide container. At some point it might be more efficient to use -- the Ada.Containers.Indefinite_Multiway_Trees. function To_Tree (N : Node'Class) return Tree is (To_Holder (N)); package Definite_Values is new Ada.Containers.Indefinite_Holders (Values); --------------- -- Leaf Node -- --------------- type Leaf_Node is new Node with record Value : Definite_Values.Holder; end record; overriding function Contains_ORs (This : Leaf_Node) return Boolean; overriding function Evaluate (This : Leaf_Node; Unused : Properties.Vector) return Tree'Class; overriding function Flatten (This : Leaf_Node) return Tree'Class; overriding function Is_Conditional (N : Leaf_Node) return Boolean; overriding function Image (V : Leaf_Node) return String; overriding function Leaf_Count (This : Leaf_Node) return Positive; overriding procedure Print (This : Leaf_Node; Prefix : String; Verbose : Boolean; Sorted : Boolean := False); overriding procedure Recursive_Traversal (This : in out Leaf_Node; Apply : access procedure (Value : in out Values)); overriding procedure To_TOML (This : Leaf_Node; Parent : TOML.TOML_Value); overriding function To_YAML (V : Leaf_Node) return String; function Is_Value (This : Tree) return Boolean is (not This.Is_Empty and then This.Root in Leaf_Node); function Value (This : Tree) return Values is (Leaf_Node (This.Root).Value.Element); overriding function Contains_ORs (This : Leaf_Node) return Boolean is (False); overriding function Evaluate (This : Leaf_Node; Unused : Properties.Vector) return Tree'Class is (New_Leaf (This.Value.Element)); overriding function Flatten (This : Leaf_Node) return Tree'Class is (To_Tree (This)); overriding function Is_Conditional (N : Leaf_Node) return Boolean is (False); overriding function Leaf_Count (This : Leaf_Node) return Positive is (1); ----------------- -- Vector Node -- ----------------- type Vector_Node is new Node with record Conjunction : Conjunctions; Values : Vectors.Vector; end record; overriding function Contains_ORs (This : Vector_Node) return Boolean is (This.Conjunction = Ored or else (for some Child of This.Values => Child.Contains_ORs)); overriding function Is_Conditional (N : Vector_Node) return Boolean is (for some Child of N.Values => Child.Is_Conditional); overriding function Leaf_Count (This : Vector_Node) return Positive; overriding function Evaluate (This : Vector_Node; Against : Properties.Vector) return Tree'Class; overriding function Flatten (This : Vector_Node) return Tree'Class; function Conjunction (This : Vector_Node) return Conjunctions; package Non_Primitive is -- This package is used for internal operations that we do not need to -- be primitive, and to prevent freezing while making these available -- to other primitives below. function One_Liner_And is new Utils.Image_One_Line (Vectors, Vectors.Vector, Image_Classwide, " and ", "(empty condition)"); function One_Liner_Or is new Utils.Image_One_Line (Vectors, Vectors.Vector, Image_Classwide, " or ", "(empty condition)"); function To_YAML is new Utils.YAML.To_YAML (Node'Class, Vectors, Vectors.Vector); end Non_Primitive; overriding function Image (V : Vector_Node) return String; overriding procedure Print (This : Vector_Node; Prefix : String; Verbose : Boolean; Sorted : Boolean); overriding procedure Recursive_Traversal (This : in out Vector_Node; Apply : access procedure (Value : in out Values)); overriding procedure To_TOML (This : Vector_Node; Parent : TOML.TOML_Value); overriding function TO_YAML (V : Vector_Node) return String; function Is_Vector (This : Tree) return Boolean is (not This.Is_Empty and then This.Root in Vector_Node); -- Delayed implementation to avoid freezing: function Is_Iterable (This : Tree) return Boolean is (This.Is_Empty or else This.Is_Value or else This.Is_Vector); function Leaf_Count (This : Tree) return Natural is (if This.Is_Empty then 0 else This.Root.Leaf_Count); function Root (This : Tree) return Node'Class is (This.Element); procedure Tree_TOML_Add (Table : TOML.TOML_Value; Key : String; Val : TOML.TOML_Value); -- For the benefit of node tomification: -- Add one property to the parent table. -- Atomic values are automatically converted into arrays, if -- more than one for the same key appears (e.g., executables) -- Table values with same key are merged in a single table (e.g., -- dependencies) -- Array values with same key are consolidated in a single array -- (e.g., actions, which are created as an array of tables). -- Keys containing one dot are split as nested tables. More than one dot -- is an error. end Alire.Conditional_Trees; alire-1.2.1/src/alire/alire-config-edit.adb000066400000000000000000000166501430264165500204420ustar00rootroot00000000000000with Ada.Text_IO; with Alire.Environment; with Alire.Platforms.Folders; with Alire.Platforms.Current; with Alire.Utils; with CLIC.Config.Edit; with CLIC.Config.Load; package body Alire.Config.Edit is use Ada.Strings.Unbounded; use AAA.Strings; use TOML; type String_Access is access String; Config_Path : String_Access; ----------------- -- Set_Locally -- ----------------- procedure Set_Locally (Key : CLIC.Config.Config_Key; Value : String; Check : CLIC.Config.Check_Import := null) is begin if not CLIC.Config.Edit.Set (Filepath (Local), Key, Value, Check) then Raise_Checked_Error ("Cannot set local config key"); end if; -- Reload after change Load_Config; end Set_Locally; ------------------ -- Set_Globally -- ------------------ procedure Set_Globally (Key : CLIC.Config.Config_Key; Value : String; Check : CLIC.Config.Check_Import := null) is begin if not CLIC.Config.Edit.Set (Filepath (Global), Key, Value, Check) then Raise_Checked_Error ("Cannot set global config key"); end if; -- Reload after change Load_Config; end Set_Globally; --------- -- Set -- --------- procedure Set (Level : Config.Level; Key : CLIC.Config.Config_Key; Value : String; Check : CLIC.Config.Check_Import := null) is begin case Level is when Local => Set_Locally (Key, Value, Check); when Global => Set_Globally (Key, Value, Check); end case; end Set; -------------- -- Filepath -- -------------- function Filepath (Lvl : Level) return Absolute_Path is begin case Lvl is when Global => return Alire.Config.Edit.Path / "config.toml"; when Local => declare Candidate : constant String := Directories.Detect_Root_Path; begin if Candidate /= "" then -- This file cannot have a .toml extension or the root -- detection will not work. return Candidate / "alire" / "config.toml"; else Raise_Checked_Error ("Can only be used in an Alire directory"); end if; end; end case; end Filepath; ---------------- -- Is_Builtin -- ---------------- function Is_Builtin (Key : CLIC.Config.Config_Key) return Boolean is (for some Cfg of Builtins => To_String (Cfg.Key) = Key); --------------------- -- Kind_Of_Builtin -- --------------------- function Kind_Of_Builtin (Key : CLIC.Config.Config_Key) return Builtin_Kind is begin for Ent of Builtins loop if To_String (Ent.Key) = Key then return Ent.Kind; end if; end loop; Raise_Checked_Error ("Kind is only valid for builtin config key"); end Kind_Of_Builtin; ----------------- -- Load_Config -- ----------------- procedure Load_Config is begin DB.Clear; for Lvl in Level loop if Lvl /= Local or else Directories.Detect_Root_Path /= "" then CLIC.Config.Load.From_TOML (C => DB, Origin => Lvl'Img, Path => Filepath (Lvl), Check => Valid_Builtin'Access); end if; end loop; -- Set variables elsewhere Platforms.Current.Disable_Distribution_Detection := DB.Get (Keys.Distribution_Disable_Detection, False); if Platforms.Current.Disable_Distribution_Detection then Trace.Debug ("Distribution detection disabled by configuration"); end if; end Load_Config; ---------- -- Path -- ---------- function Path return Absolute_Path is begin if Config_Path /= null then -- Case with switch (TODO) return Config_Path.all; else return OS_Lib.Getenv (Environment.Config, Platforms.Folders.Config); end if; end Path; -------------- -- Set_Path -- -------------- procedure Set_Path (Path : Absolute_Path) is begin if Config_Path /= null then raise Constraint_Error with "Custom path already set"; else Config_Path := new String'(Path); end if; end Set_Path; ------------------- -- Valid_Builtin -- ------------------- function Valid_Builtin (Key : CLIC.Config.Config_Key; Value : TOML_Value) return Boolean is Result : Boolean := True; begin for Ent of Builtins loop if To_String (Ent.Key) = Key then case Ent.Kind is when Cfg_Int => Result := Value.Kind = TOML_Integer; when Cfg_Float => Result := Value.Kind = TOML_Float; when Cfg_Bool => Result := Value.Kind = TOML_Boolean; when Cfg_String => Result := Value.Kind = TOML_String; when Cfg_Absolute_Path => Result := Value.Kind = TOML_String and then Check_Absolute_Path (Value.As_String); when Cfg_Email => Result := Value.Kind = TOML_String and then Alire.Utils.Could_Be_An_Email (Value.As_String, With_Name => False); when Cfg_GitHub_Login => Result := Value.Kind = TOML_String and then Utils.Is_Valid_GitHub_Username (Value.As_String); end case; exit; end if; end loop; if not Result then Trace.Error ("Invalid value '" & CLIC.Config.Image (Value) & "' for builtin configuration '" & Key & "'. " & Image (Kind_Of_Builtin (Key)) & " expected."); end if; return Result; end Valid_Builtin; ----------- -- Image -- ----------- function Image (Kind : Builtin_Kind) return String is (case Kind is when Cfg_Int => "Integer", when Cfg_Float => "Float", when Cfg_Bool => "Boolean", when Cfg_String => "String", when Cfg_Absolute_Path => "Absolute path", when Cfg_Email => "Email address", when Cfg_GitHub_Login => "GitHub login"); ------------------- -- Builtins_Info -- ------------------- function Builtins_Info return AAA.Strings.Vector is Results : AAA.Strings.Vector; begin for Ent of Builtins loop Results.Append (String'("- " & To_String (Ent.Key) & " [" & Image (Ent.Kind) & "]")); Results.Append (To_String (Ent.Help)); Results.Append (""); end loop; return Results; end Builtins_Info; ------------------------ -- Print_Builtins_Doc -- ------------------------ procedure Print_Builtins_Doc is use Ada.Text_IO; begin for Ent of Builtins loop Put (" - **`" & To_String (Ent.Key) & "`** "); Put_Line ("[" & Image (Ent.Kind) & "]:"); Put_Line (" " & To_String (Ent.Help)); New_Line; end loop; end Print_Builtins_Doc; begin Load_Config; end Alire.Config.Edit; alire-1.2.1/src/alire/alire-config-edit.ads000066400000000000000000000136441430264165500204630ustar00rootroot00000000000000with TOML; with CLIC.Config; with AAA.Strings; with Alire.Directories; package Alire.Config.Edit is -- Shortcuts that use the standard config locations: procedure Set_Locally (Key : CLIC.Config.Config_Key; Value : String; Check : CLIC.Config.Check_Import := null); procedure Set_Globally (Key : CLIC.Config.Config_Key; Value : String; Check : CLIC.Config.Check_Import := null); procedure Set (Level : Config.Level; Key : CLIC.Config.Config_Key; Value : String; Check : CLIC.Config.Check_Import := null); -- To ease the pain with circularities in old GNAT versions, we have also -- here all non-preelaborable things related to config loading. This -- way, querying stays preelaborable. function Path return Absolute_Path; -- The in-use global config folder path. -- In order of decreasing precedence: -- * A manually set path with Set_Path (below) -- * An ALR_CONFIG env given folder -- * Default per-platform path (see alire-platforms-*) procedure Set_Path (Path : Absolute_Path); -- Override global config folder path function Indexes_Directory return Absolute_Path is (Path / "indexes"); function Filepath (Lvl : Level) return Absolute_Path with Pre => Lvl /= Local or else Directories.Detect_Root_Path /= ""; -- Return path of the configuration file corresponding to the given -- configuration level. function Builtins_Info return AAA.Strings.Vector; -- Return a String_Vector with the documentation of builtin configuration -- options in text format. procedure Print_Builtins_Doc; -- Print a Markdown documentation for the built-in configuration options function Valid_Builtin (Key : CLIC.Config.Config_Key; Value : TOML.TOML_Value) return Boolean; -- Check that the combination satisfies builtin rules private procedure Load_Config; -- Clear and reload all configuration. Also set some values elsewhere -- used to break circularities. Bottom line, this procedure must leave -- the program-wide configuration ready. type Builtin_Kind is (Cfg_Int, Cfg_Float, Cfg_Bool, Cfg_String, Cfg_Absolute_Path, Cfg_Email, Cfg_GitHub_Login); type Builtin_Entry is record Key : Ada.Strings.Unbounded.Unbounded_String; Kind : Builtin_Kind; Help : Ada.Strings.Unbounded.Unbounded_String; end record; function Image (Kind : Builtin_Kind) return String; function Is_Builtin (Key : CLIC.Config.Config_Key) return Boolean; function Kind_Of_Builtin (Key : CLIC.Config.Config_Key) return Builtin_Kind with Pre => Is_Builtin (Key); -------------- -- Builtins -- -------------- Builtins : constant array (Natural range <>) of Builtin_Entry := ( (+Keys.Index_Auto_Community, Cfg_Bool, +("When unset (default) or true, the community index will be added " & "automatically when required if no other index is configured.")), (+Keys.User_Name, Cfg_String, +("User full name. Used for the authors and " & "maintainers field of a new crate.")), (+Keys.User_Email, Cfg_Email, +("User email address. Used for the authors and" & " maintainers field of a new crate.")), (+Keys.User_Github_Login, Cfg_GitHub_Login, +("User GitHub login/username. Used to for the maintainers-logins " & "field of a new crate.")), (+Keys.Editor_Cmd, Cfg_String, +("Editor command and arguments for editing crate code (alr edit)." & " The executables and arguments are separated by a single space" & " character. The token ${GPR_FILE} is replaced by" & " a path to the project file to open.")), (+Keys.Msys2_Do_Not_Install, Cfg_Bool, +("If true, Alire will not try to automatically" & " install msys2 system package manager. (Windows only)")), (+Keys.Msys2_Install_Dir, Cfg_Absolute_Path, +("Directory where Alire will detect and/or install" & " msys2 system package manager. (Windows only)")), (+Keys.Msys2_Installer, Cfg_String, +("Filename of the executable msys2 installer, " & "e.g. 'msys2-x86_64-20220319.exe'. (Windows only)")), (+Keys.Msys2_Installer_URL, Cfg_String, +("URL of the executable msys2 installer, " & "e.g. 'https://github.com/msys2/msys2-installer/releases/" & "download/2022-03-19/msys2-x86_64-20220319.exe'. (Windows only)")), (+Keys.Update_Manually, Cfg_Bool, +("If true, Alire will not attempt to update dependencies even after " & "the manifest is manually edited, or when no valid solution has " & "been ever computed. All updates have to be manually requested " & "through `alr update`")), (+Keys.Distribution_Disable_Detection, Cfg_Bool, +("If true, Alire will report an unknown distribution and will not" & " attempt to use the system package manager.")), (+Keys.Solver_Autonarrow, Cfg_Bool, +("If true, `alr with` will replace 'any' dependencies with the" & " appropriate caret/tilde dependency.")), (+Keys.Warning_Caret, Cfg_Bool, +("If true, Alire will warn about the use of caret (^) " & "for pre-1 dependencies.")), (+Keys.Warning_Old_Index, Cfg_Bool, +("When unset (default) or true, a warning will be emitted when " & "using a compatible index with a lower version than the newest" & " known.")), (+Keys.Toolchain_Assistant, Cfg_Bool, +("If true, and assistant to select the default toolchain will run " & "when first needed.")) ); end Alire.Config.Edit; alire-1.2.1/src/alire/alire-config.ads000066400000000000000000000062621430264165500175360ustar00rootroot00000000000000with Alire.OS_Lib; use Alire.OS_Lib.Operators; with AAA.Strings; with CLIC.Config; package Alire.Config with Preelaborate is DB : CLIC.Config.Instance; -- The Alire user configuration database type Level is (Global, Local); -- Ordering is important, as Globals are loaded first and overridden by any -- Local definition loaded later. --------------- -- Built-ins -- --------------- package Keys is use CLIC.Config; -- A few predefined keys that are used in several places. This list is -- not exhaustive. Editor_Cmd : constant Config_Key := "editor.cmd"; Distribution_Disable_Detection : constant Config_Key := "distribution.disable_detection"; -- When set to True, distro will be reported as unknown, and in turn no -- native package manager will be used. Index_Auto_Community : constant Config_Key := "index.auto_community"; -- When unset (default) or true, add the community index if no other -- index is already configured. Solver_Autonarrow : constant Config_Key := "solver.autonarrow"; -- When true, `alr with` will substitute "any" dependencies by the -- appropriate caret/tilde. Toolchain_Assistant : constant Config_Key := "toolchain.assistant"; -- When true (default), on first `Requires_Valid_Session`, the -- assistant to select a gnat compiler and corresponding gprbuild -- will be launched. Toolchain_External : constant Config_Key := "toolchain.external"; -- We use this key to store whether a tool in the toolchain requires -- external detection. It stores a boolean per tool, e.g, for gprbuild: -- toolchain.external.gprbuild Toolchain_Use : constant Config_Key := "toolchain.use"; -- We use this key internally to store the configured tools picked -- up by the user. Not really intended to be set up by users, so -- not listed as a built-in. Each tool is a child of this key, -- e.g.: toolchain.use.gnat, toolchain.use.gprbuild Update_Manually : constant Config_Key := "update-manually-only"; -- Used by `get --only` to flag a workspace to not autoupdate itself -- despite having no solution in the lockfile. User_Email : constant Config_Key := "user.email"; User_Name : constant Config_Key := "user.name"; User_Github_Login : constant Config_Key := "user.github_login"; Warning_Caret : constant Config_Key := "warning.caret"; -- Set to false to disable warnings about caret/tilde use for ^0 deps. Warning_Old_Index : constant Config_Key := "warning.old_index"; -- Warn about old but compatible index in use Msys2_Do_Not_Install : constant Config_Key := "msys2.do_not_install"; Msys2_Install_Dir : constant Config_Key := "msys2.install_dir"; Msys2_Installer : constant Config_Key := "msys2.installer"; Msys2_Installer_URL : constant Config_Key := "msys2.installer_url"; end Keys; -------------- -- Defaults -- -------------- package Defaults is Warning_Old_Index : constant Boolean := True; end Defaults; end Alire.Config; alire-1.2.1/src/alire/alire-containers.ads000066400000000000000000000002761430264165500204350ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Sets; package Alire.Containers is package Crate_Name_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Crate_Name); end Alire.Containers; alire-1.2.1/src/alire/alire-crate_configuration.adb000066400000000000000000000617241430264165500223010ustar00rootroot00000000000000with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Directories; with Ada.Text_IO; with Ada.Containers.Indefinite_Vectors; with AAA.Strings; use AAA.Strings; with Alire_Early_Elaboration; with Alire.Solutions; with Alire.Releases; with Alire.Roots; with Alire.Origins; with Alire.Warnings; with Alire.Config; with Alire.Config.Edit; with Alire.Properties.Build_Profiles; with Alire.Properties.Build_Switches; with Alire.Utils.Switches; use Alire.Utils.Switches; with Alire.Utils.Switches.Knowledge; with Alire.Directories; with Alire.Platforms.Current; with TOML; use TOML; package body Alire.Crate_Configuration is function Builtin_Build_Profile is new Typedef_From_Enum (Alire.Utils.Switches.Profile_Kind, "Build_Profile", Lower_Case => True); use Config_Type_Definition_Holder; -- The Host info types below could be Enums instead of Strings. This would -- have the advantage of providing users the entire list of potential -- values. However, using enums in Ada would have a very high risk of -- breaking the code if future versions of Alire introduce new values -- for the enums. -- -- For instance if a crate has a case statement on Alire_Host_Os without a -- "when others" branch. The same valid code could trigger "error: missing -- case values" on a future version of Alire. This is not acceptable, -- therefore we decide not to use enums here. type Config_Settings_Array is array (Integer range <>) of Config_Setting; --------------- -- Host_Info -- --------------- -- This is a function instead of a constant to avoid creating temporary -- files at elaboration time, which in turn removes some errors when -- running in a non-writable directory. Although we do not cache the result -- here, the individual costly detections are cached at Platforms.Current. function Host_Info return Config_Settings_Array is ((Type_Def => To_Holder (String_Typedef ("Alire_Host_OS")), Value => TOML.Create_String (To_Lower_Case (Alire.Platforms.Current.Operating_System'Img)), Set_By => +"built-in"), (Type_Def => To_Holder (String_Typedef ("Alire_Host_Arch")), Value => TOML.Create_String (To_Lower_Case (Alire.Platforms.Current.Host_Architecture'Img)), Set_By => +"built-in"), (Type_Def => To_Holder (String_Typedef ("Alire_Host_Distro")), Value => TOML.Create_String (To_Lower_Case (Alire.Platforms.Current.Distribution'Img)), Set_By => +"built-in") ); package TIO renames Ada.Text_IO; package Crate_Name_Vect is new Ada.Containers.Indefinite_Vectors (Natural, Crate_Name); ----------------------- -- Make_Release_Vect -- ----------------------- function Make_Release_Vect (Root : in out Alire.Roots.Root) return Crate_Name_Vect.Vector is Result : Crate_Name_Vect.Vector; procedure Filter (This : in out Alire.Roots.Root; Solution : Solutions.Solution; State : Solutions.Dependency_State) is pragma Unreferenced (This, Solution); begin if State.Has_Release and then not State.Is_Provided then Result.Append (State.Crate); end if; end Filter; begin Root.Traverse (Filter'Access); return Result; end Make_Release_Vect; function Is_Reserved_Name (Type_Name : String) return Boolean is (AAA.Strings.Has_Prefix (Type_Name, "alire_") or else Type_Name = "crate_version" or else Type_Name = "crate_name" or else Type_Name = "ada_compiler_switches" or else Type_Name = "c_compiler_switches" or else Type_Name = "ada_linker_switches" or else Type_Name = "c_linker_switches"); -- Return True if Type_Name is reserved for Alire internal use ---------------------------- -- Make_Build_Profile_Map -- ---------------------------- procedure Make_Build_Profile_Map (This : in out Global_Config; Root : in out Alire.Roots.Root; Rel_Vect : Crate_Name_Vect.Vector) is use Properties.Build_Profiles; ----------------- -- Set_Profile -- ----------------- procedure Set_Profile (Crate : Crate_Name; P : Profile_Kind) is begin if This.Profile_Map.Contains (Crate) then This.Profile_Map.Replace (Crate, P); else Raise_Checked_Error ("Unknown crate in build profile: '" & String'(+Crate) & "'"); end if; end Set_Profile; begin -- Populate map with crates in the solution for Crate of Rel_Vect loop This.Profile_Map.Insert (Crate, (if Crate = Root.Name then Root_Build_Profile else Default_Deps_Build_Profile)); end loop; for Prop of Root.Release.On_Platform_Properties (Root.Environment, Properties.Build_Profiles.Variable'Tag) loop declare Prof : constant Properties.Build_Profiles.Variable := Properties.Build_Profiles.Variable (Prop); begin if Prof.Has_Wildcard then -- If wildcard is defined, apply it to all crates declare Wildcard_Profile : constant Profile_Kind := Prof.Wildcard; begin for Cursor in This.Profile_Map.Iterate loop This.Profile_Map.Replace_Element (Cursor, Wildcard_Profile); end loop; end; end if; declare use Properties.Build_Profiles.Profile_Selection_Maps; Sel : constant Profile_Selection_Maps.Map := Prof.Selection; begin for Cursor in Sel.Iterate loop Set_Profile (Key (Cursor), Element (Cursor)); end loop; end; end; end loop; for Cursor in This.Profile_Map.Iterate loop -- Set build_Mode value in configuration variables This.Set_Value (Profile_Maps.Key (Cursor), (Name => +Builtin_Build_Profile.Name, Value => TOML.Create_String (To_Lower_Case (Profile_Maps.Element (Cursor)'Img)))); end loop; end Make_Build_Profile_Map; ----------------------- -- Make_Switches_Map -- ----------------------- procedure Make_Switches_Map (This : in out Global_Config; Root : in out Alire.Roots.Root; Rel_Vect : Crate_Name_Vect.Vector) is begin for Crate of Rel_Vect loop declare Rel : constant Releases.Release := Root.Release (Crate); Profile : constant Profile_Kind := This.Profile_Map.Element (Crate); Config : Alire.Utils.Switches.Switches_Configuration := (case Profile is when Release => Default_Release_Switches, when Validation => Default_Validation_Switches, when Development => Default_Development_Switches); Modif : Properties.Build_Switches.Profile_Modifier; begin -- Get switches modifier from the release for Prop of Rel.On_Platform_Properties (Root.Environment, Properties.Build_Switches.Variable'Tag) loop declare Prof : constant Properties.Build_Switches.Variable := Properties.Build_Switches.Variable (Prop); begin Modif := Prof.Modifier; end; end loop; Properties.Build_Switches.Apply (Config, Modif.Wildcard); case Profile is when Release => Properties.Build_Switches.Apply (Config, Modif.Release); when Validation => Properties.Build_Switches.Apply (Config, Modif.Validation); when Development => Properties.Build_Switches.Apply (Config, Modif.Development); end case; This.Switches_Map.Insert (Rel.Name, Get_List (Config)); end; end loop; end Make_Switches_Map; ---------- -- Load -- ---------- procedure Load (This : in out Global_Config; Root : in out Alire.Roots.Root) is Solution : constant Solutions.Solution := Root.Solution; Rel_Vect : constant Crate_Name_Vect.Vector := Make_Release_Vect (Root); begin if not Solution.Is_Complete then Warnings.Warn_Once ("Generating possibly incomplete configuration" & " because of missing dependencies"); end if; for Crate of Rel_Vect loop This.Load_Definitions (Root, Crate); end loop; Make_Build_Profile_Map (This, Root, Rel_Vect); Make_Switches_Map (This, Root, Rel_Vect); for Create of Rel_Vect loop This.Load_Settings (Root, Create); end loop; Use_Default_Values (This); end Load; --------------------------- -- Generate_Config_Files -- --------------------------- procedure Generate_Config_Files (This : Global_Config; Root : in out Alire.Roots.Root) is use Alire.Directories; use Alire.Origins; Solution : constant Solutions.Solution := Root.Solution; function Get_Config_Entry (Rel : Releases.Release) return Config_Entry is begin for Prop of Rel.On_Platform_Properties (Root.Environment, Config_Entry'Tag) loop return Config_Entry (Prop); end loop; -- No Config_Entry found, return the default Config_Entry declare Ret : Config_Entry; begin return Ret; end; end Get_Config_Entry; begin if not Solution.Is_Complete then Warnings.Warn_Once ("Generating possibly incomplete configuration" & " because of missing dependencies"); end if; Trace.Detail ("Generating crate config files"); Set_Last_Build_Profile (Root_Build_Profile); for Crate of Make_Release_Vect (Root) loop declare Rel : constant Releases.Release := Root.Release (Crate); begin -- We don't create config files for external releases, since they -- are not sources built by Alire. if Rel.Origin.Kind /= Alire.Origins.External then declare Ent : constant Config_Entry := Get_Config_Entry (Rel); Conf_Dir : constant Absolute_Path := Root.Release_Base (Rel.Name) / Ent.Output_Dir; Version_Str : constant String := Rel.Version.Image; begin if not Ent.Disabled then Ada.Directories.Create_Path (Conf_Dir); if Ent.Generate_Ada then This.Generate_Ada_Config (Rel.Name, Conf_Dir / (+Rel.Name & "_config.ads"), Version_Str); end if; if Ent.Generate_GPR then This.Generate_GPR_Config (Rel.Name, Conf_Dir / (+Rel.Name & "_config.gpr"), (if Ent.Auto_GPR_With then Root.Direct_Withs (Rel) else AAA.Strings.Empty_Set), Version_Str); end if; if Ent.Generate_C then This.Generate_C_Config (Rel.Name, Conf_Dir / (+Rel.Name & "_config.h"), Version_Str); end if; end if; end; end if; end; end loop; end Generate_Config_Files; ------------------------- -- Generate_Ada_Config -- ------------------------- procedure Generate_Ada_Config (This : Global_Config; Crate : Crate_Name; Filepath : Absolute_Path; Version : String) is File : TIO.File_Type; Crate_Mixed : constant String := To_Mixed_Case (+Crate); begin TIO.Create (File, TIO.Out_File, Filepath); TIO.Put_Line (File, "-- Configuration for " & (+Crate) & " generated by Alire"); TIO.Put_Line (File, "pragma Restrictions (No_Elaboration_Code);"); TIO.Put_Line (File, "pragma Style_Checks (Off);"); TIO.New_Line (File); TIO.Put_Line (File, "package " & Crate_Mixed & "_Config is"); TIO.Put_Line (File, " pragma Pure;"); TIO.New_Line (File); TIO.Put_Line (File, " Crate_Version : constant String := """ & Version & """;"); TIO.Put_Line (File, " Crate_Name : constant String := """ & (+Crate) & """;"); for Elt of Host_Info loop TIO.New_Line (File); TIO.Put_Line (File, Elt.Type_Def.Element.To_Ada_Declaration (Elt.Value)); end loop; for C in This.Map.Iterate loop declare Elt : constant Config_Maps.Constant_Reference_Type := This.Map.Constant_Reference (C); Type_Def : Config_Type_Definition renames Elt.Type_Def.Element; Key : constant String := To_String (Config_Maps.Key (C)); begin if Elt.Value = TOML.No_TOML_Value then Raise_Checked_Error ("Configuration variable should be set at this point." & " Missing call to Use_Default_Values()?"); end if; if AAA.Strings.Has_Prefix (Key, +Crate & ".") then TIO.New_Line (File); TIO.Put_Line (File, Type_Def.To_Ada_Declaration (Elt.Value)); end if; end; end loop; TIO.New_Line (File); TIO.Put_Line (File, "end " & Crate_Mixed & "_Config;"); TIO.Close (File); end Generate_Ada_Config; --------------------------- -- Pretty_Print_Switches -- --------------------------- procedure Pretty_Print_Switches (File : TIO.File_Type; L : Switch_List; Indent : Natural) is Indent_Str : constant String (1 .. Indent) := (others => ' '); First : Boolean := True; begin Alire.Utils.Switches.Knowledge.Populate; TIO.Put_Line (File, Indent_Str & "("); for Sw of L loop TIO.Put (File, Indent_Str & " "); if not First then TIO.Put (File, ","); else TIO.Put (File, " "); First := False; end if; TIO.Put (File, """" & Sw & """"); declare Info : constant String := Utils.Switches.Knowledge.Get_Info (Sw); begin if Info'Length /= 0 then TIO.Put (File, " -- " & Info); end if; end; TIO.New_Line (File); end loop; TIO.Put_Line (File, Indent_Str & ");"); end Pretty_Print_Switches; ------------------------- -- Generate_GPR_Config -- ------------------------- procedure Generate_GPR_Config (This : Global_Config; Crate : Crate_Name; Filepath : Absolute_Path; Withs : AAA.Strings.Set; Version : String) is File : TIO.File_Type; Crate_Mixed : constant String := To_Mixed_Case (+Crate); begin TIO.Create (File, TIO.Out_File, Filepath); TIO.Put_Line (File, "-- Configuration for " & (+Crate) & " generated by Alire"); for W of Withs loop TIO.Put_Line (File, "with """ & W & """;"); end loop; TIO.Put_Line (File, "abstract project " & Crate_Mixed & "_Config is"); TIO.Put_Line (File, " Crate_Version := """ & Version & """;"); TIO.Put_Line (File, " Crate_Name := """ & (+Crate) & """;"); for Elt of Host_Info loop TIO.New_Line (File); TIO.Put_Line (File, Elt.Type_Def.Element.To_GPR_Declaration (Elt.Value)); end loop; TIO.Put_Line (File, " Ada_Compiler_Switches := External_As_List (""ADAFLAGS"", "" "");" ); TIO.Put_Line (File, " Ada_Compiler_Switches := Ada_Compiler_Switches &"); Pretty_Print_Switches (File, This.Switches_Map.Element (Crate), Indent => 10); for C in This.Map.Iterate loop declare Elt : constant Config_Maps.Constant_Reference_Type := This.Map.Constant_Reference (C); Type_Def : Config_Type_Definition renames Elt.Type_Def.Element; Key : constant String := To_String (Config_Maps.Key (C)); begin if Elt.Value = TOML.No_TOML_Value then Raise_Checked_Error ("Configuration variable should be set at this point." & " Missing call to Use_Default_Values()?"); end if; if AAA.Strings.Has_Prefix (Key, +Crate & ".") then TIO.New_Line (File); TIO.Put_Line (File, Type_Def.To_GPR_Declaration (Elt.Value)); end if; end; end loop; TIO.New_Line (File); TIO.Put_Line (File, "end " & Crate_Mixed & "_Config;"); TIO.Close (File); end Generate_GPR_Config; ----------------------- -- Generate_C_Config -- ----------------------- procedure Generate_C_Config (This : Global_Config; Crate : Crate_Name; Filepath : Absolute_Path; Version : String) is File : TIO.File_Type; Crate_Upper : constant String := To_Upper_Case (+Crate); begin TIO.Create (File, TIO.Out_File, Filepath); TIO.Put_Line (File, "/* Configuration for " & (+Crate) & " generated by Alire */"); TIO.Put_Line (File, "#ifndef " & Crate_Upper & "_CONFIG_H"); TIO.Put_Line (File, "#define " & Crate_Upper & "_CONFIG_H"); TIO.New_Line (File); TIO.Put_Line (File, "#define CRATE_VERSION """ & Version & """"); TIO.Put_Line (File, "#define CRATE_NAME """ & (+Crate) & """"); for Elt of Host_Info loop TIO.New_Line (File); TIO.Put_Line (File, Elt.Type_Def.Element.To_C_Declaration (Elt.Value)); end loop; for C in This.Map.Iterate loop declare Elt : constant Config_Maps.Constant_Reference_Type := This.Map.Constant_Reference (C); Type_Def : Config_Type_Definition renames Elt.Type_Def.Element; Key : constant String := To_String (Config_Maps.Key (C)); begin if Elt.Value = TOML.No_TOML_Value then Raise_Checked_Error ("Configuration variable should be set at this point." & " Missing call to Use_Default_Values()?"); end if; if AAA.Strings.Has_Prefix (Key, +Crate & ".") then TIO.New_Line (File); TIO.Put_Line (File, Type_Def.To_C_Declaration (Elt.Value)); end if; end; end loop; TIO.New_Line (File); TIO.Put_Line (File, "#endif"); TIO.Close (File); end Generate_C_Config; -------------------- -- Add_Definition -- -------------------- procedure Add_Definition (This : in out Global_Config; Crate : Crate_Name; Type_Def : Config_Type_Definition) is Type_Name_Lower : constant String := To_Lower_Case (Type_Def.Name); Name : constant Unbounded_String := +(+Crate & "." & Type_Name_Lower); begin if Is_Reserved_Name (Type_Name_Lower) then Raise_Checked_Error ("Configuration variable name '" & (+Name) & "' is reserved for Alire internal use"); end if; if This.Map.Contains (Name) then Raise_Checked_Error ("Configuration variable '" & (+Name) & "' already defined"); end if; declare Setting : Config_Setting; begin Setting.Type_Def.Replace_Element (Type_Def); Setting.Value := TOML.No_TOML_Value; This.Map.Insert (Name, Setting); end; end Add_Definition; ---------------------- -- Load_Definitions -- ---------------------- procedure Load_Definitions (This : in out Global_Config; Root : in out Roots.Root; Crate : Crate_Name) is Rel : constant Releases.Release := Root.Release (Crate); begin This.Add_Definition (Crate, Builtin_Build_Profile); for Prop of Rel.On_Platform_Properties (Root.Environment, Config_Type_Definition'Tag) loop This.Add_Definition (Crate, Config_Type_Definition (Prop)); end loop; end Load_Definitions; --------------- -- Set_Value -- --------------- procedure Set_Value (This : in out Global_Config; Crate : Crate_Name; Val : Assignment) is Val_Name_Lower : constant String := To_Lower_Case (+Val.Name); Crate_Str : constant String := +Crate; Name : constant Unbounded_String := (+Crate_Str) & "." & Val_Name_Lower; begin -- TODO check if setting configuration of a dependency if not This.Map.Contains (Name) then Raise_Checked_Error ("Unknown configuration variable '" & (+Name) & "'"); end if; declare Ref : constant Config_Maps.Reference_Type := This.Map.Reference (Name); begin if not Valid (Ref.Type_Def.Element, Val.Value) then Raise_Checked_Error ("Invalid value from '" & Crate_Str & "'" & " for type " & Image (Ref.Type_Def.Element)); end if; if Ref.Value /= No_TOML_Value and then Ref.Value /= Val.Value then Raise_Checked_Error ("Conflicting value for configuration variable '" & (+Name) & "' from '" & (+Ref.Set_By) & "' and '" & (+Crate) & "'."); else Ref.Value := Val.Value; Ref.Set_By := +(+Crate); end if; end; end Set_Value; ------------------- -- Load_Settings -- ------------------- procedure Load_Settings (This : in out Global_Config; Root : in out Roots.Root; Crate : Crate_Name) is Rel : constant Releases.Release := Root.Release (Crate); begin for Prop of Rel.On_Platform_Properties (Root.Environment, Config_Value_Assignment'Tag) loop declare List : Config_Value_Assignment renames Config_Value_Assignment (Prop); begin for Elt of List.List loop This.Set_Value (To_Name (+List.Crate), Elt); end loop; end; end loop; end Load_Settings; ------------------------ -- Use_Default_Values -- ------------------------ procedure Use_Default_Values (Conf : in out Global_Config) is begin for C in Conf.Map.Iterate loop declare Elt : constant Config_Maps.Reference_Type := Conf.Map.Reference (C); Key : constant String := To_String (Config_Maps.Key (C)); begin if Elt.Value = TOML.No_TOML_Value then if Elt.Type_Def.Element.Default /= No_TOML_Value then Elt.Value := Elt.Type_Def.Element.Default; Elt.Set_By := +"default value"; else Raise_Checked_Error ("Configuration variable '" & Key & " not set and has no default value."); end if; end if; end; end loop; end Use_Default_Values; ------------------------ -- Last_Build_Profile -- ------------------------ function Last_Build_Profile return Utils.Switches.Profile_Kind is Str : constant String := Config.DB.Get ("last_build_profile", Default_Root_Build_Profile'Img); begin return Profile_Kind'Value (Str); exception when Constraint_Error => return Default_Root_Build_Profile; end Last_Build_Profile; ---------------------------- -- Set_Last_Build_Profile -- ---------------------------- procedure Set_Last_Build_Profile (P : Utils.Switches.Profile_Kind) is begin Config.Edit.Set_Locally ("last_build_profile", P'Img); end Set_Last_Build_Profile; end Alire.Crate_Configuration; alire-1.2.1/src/alire/alire-crate_configuration.ads000066400000000000000000000076501430264165500223200ustar00rootroot00000000000000with TOML; with Alire.Utils.Switches; with Alire.Properties.Configurations; limited with Alire.Roots; private with Ada.Strings.Unbounded; private with Ada.Containers.Hashed_Maps; private with Ada.Strings.Unbounded.Hash; private with Ada.Containers.Indefinite_Holders; private with Ada.Containers.Indefinite_Ordered_Maps; package Alire.Crate_Configuration is Default_Root_Build_Profile : constant Utils.Switches.Profile_Kind := Utils.Switches.Development; Default_Deps_Build_Profile : constant Utils.Switches.Profile_Kind := Utils.Switches.Release; Root_Build_Profile : Utils.Switches.Profile_Kind := Default_Root_Build_Profile; type Global_Config is tagged limited private; procedure Load (This : in out Global_Config; Root : in out Alire.Roots.Root); procedure Generate_Config_Files (This : Global_Config; Root : in out Alire.Roots.Root); procedure Set_Last_Build_Profile (P : Utils.Switches.Profile_Kind); -- Record in local user configuration the last profile used in crate -- configuration. function Last_Build_Profile return Utils.Switches.Profile_Kind; -- Get the last profile used from user configuration private use Alire.Properties.Configurations; use type Alire.Utils.Switches.Profile_Kind; use type Alire.Utils.Switches.Switch_List; package Config_Type_Definition_Holder is new Ada.Containers.Indefinite_Holders (Config_Type_Definition); type Config_Setting is record Type_Def : Config_Type_Definition_Holder.Holder; Value : TOML.TOML_Value; Set_By : Ada.Strings.Unbounded.Unbounded_String; end record; package Config_Maps is new Ada.Containers.Hashed_Maps (Key_Type => Ada.Strings.Unbounded.Unbounded_String, Element_Type => Config_Setting, Hash => Ada.Strings.Unbounded.Hash, Equivalent_Keys => Ada.Strings.Unbounded."="); package Profile_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Alire.Utils.Switches.Profile_Kind); package Switches_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Alire.Utils.Switches.Switch_List); type Global_Config is tagged limited record Map : Config_Maps.Map; Profile_Map : Profile_Maps.Map; Switches_Map : Switches_Maps.Map; end record; procedure Use_Default_Values (Conf : in out Global_Config); -- Use default value for unset variable, raise Checked_Error if a variable -- has no default value. procedure Add_Definition (This : in out Global_Config; Crate : Crate_Name; Type_Def : Config_Type_Definition); procedure Load_Definitions (This : in out Global_Config; Root : in out Roots.Root; Crate : Crate_Name); procedure Set_Value (This : in out Global_Config; Crate : Crate_Name; Val : Assignment); procedure Load_Settings (This : in out Global_Config; Root : in out Roots.Root; Crate : Crate_Name); procedure Generate_Ada_Config (This : Global_Config; Crate : Crate_Name; Filepath : Absolute_Path; Version : String); procedure Generate_GPR_Config (This : Global_Config; Crate : Crate_Name; Filepath : Absolute_Path; Withs : AAA.Strings.Set; Version : String); procedure Generate_C_Config (This : Global_Config; Crate : Crate_Name; Filepath : Absolute_Path; Version : String); end Alire.Crate_Configuration; alire-1.2.1/src/alire/alire-crates-containers.ads000066400000000000000000000003101430264165500217010ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; package Alire.Crates.Containers is package Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Crate); end Alire.Crates.Containers; alire-1.2.1/src/alire/alire-crates.adb000066400000000000000000000213411430264165500175240ustar00rootroot00000000000000with Alire.Index; with Alire.Origins; with Alire.Properties.Labeled; with Alire.Provides; with Alire.TOML_Keys; with Alire.TOML_Load; with Alire.User_Pins.Maps; with Alire.Utils.TTY; with TOML; package body Alire.Crates is ----------------------- -- Naming_Convention -- ----------------------- function Naming_Convention return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Identifiers for crates and indexes must use " & "lowercase alphanumeric characters from the latin " & "alphabet. Underscores can also be used except as " & "the first character.") .New_Line .Append ("Length must be of" & Alire.Min_Name_Length'Img & " to" & Alire.Max_Name_Length'Img & " characters.")); ---------- -- Keys -- ---------- package Keys is new Alire.Releases.Containers.Release_Sets.Generic_Keys (Semantic_Versioning.Version, Alire.Releases.Version, Semantic_Versioning."<"); --------- -- Add -- --------- procedure Add (This : in out Crate; Release : Alire.Releases.Release) is begin This.Releases.Insert (Release); end Add; ---------- -- Base -- ---------- function Base (This : Crate) return Alire.Releases.Release is begin return Alire.Releases.New_Release (Name => This.Name, Version => Semantic_Versioning.Parse ("0"), Origin => Origins.New_Filesystem ("."), Notes => "", Dependencies => Conditional.No_Dependencies, Properties => This.Externals.Properties, Available => Conditional.Empty); end Base; -------------- -- Contains -- -------------- function Contains (This : Crate; Version : Semantic_Versioning.Version) return Boolean is begin return Keys.Contains (Alire.Releases.Containers.Release_Sets.Set (This.Releases), Version); end Contains; --------------- -- Externals -- --------------- function Externals (This : Crate) return Alire.Externals.Lists.List is (This.Externals.Detectors); ----------------------------- -- From_Externals_Manifest -- ----------------------------- function From_Externals_Manifest (From : TOML_Adapters.Key_Queue; Strict : Boolean) return Crate is begin From.Assert_Key (TOML_Keys.Name, TOML.TOML_String); return This : Crate := New_Crate (+From.Unwrap.Get (TOML_Keys.Name).As_String) do This.Load_Externals (From, Strict); end return; end From_Externals_Manifest; -------------------- -- Load_Externals -- -------------------- procedure Load_Externals (This : in out Crate; From : TOML_Adapters.Key_Queue; Strict : Boolean; Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing) is -------------------- -- Load_Externals -- -------------------- procedure Load_Externals_Array is TOML_Externals : TOML.TOML_Value; Has_Externals : constant Boolean := From.Pop (TOML_Keys.External, TOML_Externals); begin if Has_Externals then if TOML_Externals.Kind not in TOML.TOML_Array then From.Checked_Error ("external entries must be TOML arrays"); else for I in 1 .. TOML_Externals.Length loop This.Externals.Detectors.Append (Alire.Externals.From_TOML (From.Descend (TOML_Externals.Item (I), "external index" & I'Img), Strict)); end loop; end if; -- Register any aliased in the detectors for this crate, so we -- know when to detect. Also the trivial equivalence, for the -- benefit of queries in the index. Index.Register_External_Alias (This.Name, This.Name); for Detector of This.Externals.Detectors loop for Alias of Detector.Equivalences loop Index.Register_External_Alias (Provider => This.Name, Providing => Alias); end loop; end loop; end if; end Load_Externals_Array; begin if From.Unwrap.Kind not in TOML.TOML_Table then From.Checked_Error ("top-level section must be a table"); end if; -- Process any external detectors Load_Externals_Array; -- Load the shared section declare Unused_Avail : Conditional.Availability; Unused_Deps : Conditional.Dependencies; Unused_Equiv : Provides.Equivalences; Unused_Pins : User_Pins.Maps.Map; Properties : Conditional.Properties; begin TOML_Load.Load_Crate_Section (Strict => Strict, Section => External_Shared_Section, From => From, Props => Properties, Deps => Unused_Deps, Equiv => Unused_Equiv, Forbids => Unused_Deps, Pins => Unused_Pins, Avail => Unused_Avail); Assert (Unused_Deps.Is_Empty, "Unexpected dependencies in external definition"); Assert (Unused_Pins.Is_Empty, "Unexpected pins in external definition"); Assert (Unused_Avail.Is_Empty, "Unexpected availability in external definition"); case Policy is when Policies.Merge_Priorizing_Existing => if This.Externals.Properties.Is_Empty then This.Externals.Properties := Properties; else Trace.Debug ("Discarding new properties for externals base"); end if; end case; end; From.Report_Extra_Keys; end Load_Externals; --------------------- -- Merge_Externals -- --------------------- procedure Merge_Externals (This : in out Crate; From : Crate; Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing) is use type Alire.Externals.External'Class; begin -- Merge new external detectors case Policy is when Policies.Merge_Priorizing_Existing => if This.Externals.Properties.Is_Empty then This.Externals.Properties := From.Externals.Properties; end if; for Ext of From.Externals.Detectors loop if not (for some Existing of This.Externals.Detectors => Ext = Existing) then This.Externals.Detectors.Append (Ext); end if; end loop; end case; end Merge_Externals; ----------------- -- Description -- ----------------- function Description (This : Crate) return Description_String is Descr : constant Properties.Vector := Properties.Labeled.Filter (Conditional.Enumerate (This.Externals.Properties), Properties.Labeled.Description); begin if not This.Releases.Is_Empty then return This.Releases.Last_Element.Description; elsif not Descr.Is_Empty then return Properties.Labeled.Label (Descr.First_Element).Value; else return "Crate is empty and a description cannot thus be provided"; end if; end Description; --------------------- -- TTY_Description -- --------------------- function TTY_Description (This : Crate) return String is (Utils.TTY.Description (This.Description)); ---------- -- Name -- ---------- function Name (This : Crate) return Crate_Name is (This.Name); -------------- -- TTY_Name -- -------------- function TTY_Name (This : Crate) return String is (Utils.TTY.Name (+This.Name)); --------------- -- New_Crate -- --------------- function New_Crate (Name : Crate_Name) return Crate is (Crate'(Len => Name.Length, Name => Name, Externals => <>, Releases => <>)); -------------- -- Releases -- -------------- function Releases (This : Crate) return Alire.Releases.Containers.Release_Set is (This.Releases); ------------- -- Replace -- ------------- procedure Replace (This : in out Crate; Release : Alire.Releases.Release) is begin Keys.Replace (Alire.Releases.Containers.Release_Sets.Set (This.Releases), Release.Version, Release); end Replace; end Alire.Crates; alire-1.2.1/src/alire/alire-crates.ads000066400000000000000000000102251430264165500175440ustar00rootroot00000000000000with AAA.Strings; with Alire.Conditional; with Alire.Externals.Lists; with Alire.Policies; with Alire.Releases.Containers; with Alire.TOML_Adapters; with Semantic_Versioning; package Alire.Crates is function Naming_Convention return AAA.Strings.Vector; -- Return a description of the naming restrictions on crates/indexes. type Sections is (Index_Release, -- Top-level table, with all info about a release to be -- stored in an index. Local_Release, -- Top-level table, with info for the working copy of a -- release. This allows regular users not dealing with -- packaging to see fewer fields. External_Shared_Section, -- Top-level table, with only info valid for externals External_Private_Section -- Info that can be provided by all external definitions, -- but already in their private [[external]] entry. ); type Crate (<>) is tagged private; -- A complete crate with its releases and external definitions. function New_Crate (Name : Crate_Name) return Crate; function Name (This : Crate) return Crate_Name; function TTY_Name (This : Crate) return String; procedure Add (This : in out Crate; Release : Releases.Release) with Pre => not This.Contains (Release.Version) or else raise Checked_Error with "Crate already contains given release: " & Semantic_Versioning.Image (Release.Version); function Base (This : Crate) return Releases.Release with Pre => not This.Externals.Is_Empty; -- Returns a release sharing only this crate mandatory properties (see -- Alire.Properties.Labeled.Mandatory) that can be used as template for -- new releases in this crate (e.g., by externally detected releases). function Contains (This : Crate; Version : Semantic_Versioning.Version) return Boolean; function Description (This : Crate) return Description_String; -- Will return the last release description, or the one in the external -- base properties, or a message saying the crate is totally empty. function TTY_Description (This : Crate) return String; function Externals (This : Crate) return Alire.Externals.Lists.List; function From_Externals_Manifest (From : TOML_Adapters.Key_Queue; Strict : Boolean) return Crate; -- Load a manifest containing only external definitions for a crate procedure Load_Externals (This : in out Crate; From : TOML_Adapters.Key_Queue; Strict : Boolean; Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing); -- Load externals detectors into an existing crate procedure Merge_Externals (This : in out Crate; From : Crate; Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing); -- Merge external definitions from both crates, applying some index merging -- policy. function Releases (This : Crate) return Releases.Containers.Release_Set; procedure Replace (This : in out Crate; Release : Alire.Releases.Release) with Pre => This.Contains (Release.Version) or else raise Checked_Error with "Crate does not contain given release: " & Semantic_Versioning.Image (Release.Version); private type External_Data is record Properties : Conditional.Properties; -- Properties that are defined with external definitions, used as -- base of any detected release (description, etc). This will be -- empty for crates without external definitions. Detectors : Alire.Externals.Lists.List; -- External detectors defined for the crate end record; type Crate (Len : Natural) is tagged record Name : Crate_Name (Len); Externals : External_Data; Releases : Alire.Releases.Containers.Release_Set; end record; end Alire.Crates; alire-1.2.1/src/alire/alire-defaults.ads000066400000000000000000000007661430264165500201030ustar00rootroot00000000000000package Alire.Defaults with Preelaborate is Description : constant String := "Shiny new project"; -- TODO: replace this constant with a function that returns random fortunes Docker_Test_Image : constant String := "alire/gnat:debian-stable"; -- Docker image to be used with `alr test --docker` unless overridden Maintainer : constant String := "your@email.here"; Maintainer_Login : constant String := "github-username"; -- A well-formed GitHub username end Alire.Defaults; alire-1.2.1/src/alire/alire-dependencies-containers.adb000066400000000000000000000025241430264165500230360ustar00rootroot00000000000000package body Alire.Dependencies.Containers is ----------- -- Merge -- ----------- procedure Merge (This : in out Map; Dep : Dependencies.Dependency) is use type Semantic_Versioning.Extended.Version_Set; begin if This.Contains (Dep.Crate) then declare Old : constant Dependencies.Dependency := This (Dep.Crate); begin if Old /= Dep then -- Include should work to replace the dependency, but I'm -- getting a tampering error using it (?) This.Delete (Dep.Crate); This.Insert (Dep.Crate, Dependencies.New_Dependency (Dep.Crate, Old.Versions and Dep.Versions)); end if; end; else This.Insert (Dep.Crate, Dep); end if; end Merge; ------------ -- To_Set -- ------------ function To_Set (This : List) return Sets.Set is begin return Result : Set do for Dep of This loop Result.Include (Dep); -- We include instead of inserting because enumeration of case -- expressions may give the same dependency more than once. end loop; end return; end To_Set; end Alire.Dependencies.Containers; alire-1.2.1/src/alire/alire-dependencies-containers.ads000066400000000000000000000024211430264165500230530ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; with Ada.Containers.Indefinite_Ordered_Maps; with Ada.Containers.Indefinite_Ordered_Sets; with Optional.Values; package Alire.Dependencies.Containers with Preelaborate is package Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Dependencies.Dependency, "<", Dependencies."="); type Map is new Maps.Map with null record; Empty_Map : constant Map; procedure Merge (This : in out Map; Dep : Dependencies.Dependency); -- If the dependency is already in map, create a combined dependency that -- ANDs both. package Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Dependency); type List is new Lists.List with null record; package Optionals is new Optional.Values (Dependency, Image); subtype Optional is Optionals.Optional; package Sets is new Ada.Containers.Indefinite_Ordered_Sets (Dependency, Lexicographical_Sort); subtype Set is Sets.Set; function To_Set (This : List) return Sets.Set; -- For presentation, we prefer dependencies to be shown in order private Empty_Map : constant Map := (Maps.Empty_Map with null record); end Alire.Dependencies.Containers; alire-1.2.1/src/alire/alire-dependencies-diffs.adb000066400000000000000000000044731430264165500217710ustar00rootroot00000000000000with Alire.Utils.Tables; package body Alire.Dependencies.Diffs is ----------- -- Added -- ----------- function Added (This : Diff) return Containers.List is (This.Added); ------------- -- Between -- ------------- function Between (Former, Latter : Containers.List) return Diff is begin return This : Diff do -- Identify new: for Dep of Latter loop if not (for some Old of Former => Dep = Old) then This.Added.Append (Dep); end if; end loop; -- Identify old: for Dep of Former loop if not (for some Novel of Latter => Dep = Novel) then This.Removed.Append (Dep); end if; end loop; end return; end Between; ------------- -- Between -- ------------- function Between (Former, Latter : Conditional.Dependencies) return Diff is (Between (Conditional.Enumerate (Former), Conditional.Enumerate (Latter))); ---------------------- -- Contains_Changes -- ---------------------- function Contains_Changes (This : Diff) return Boolean is (not (This.Added.Is_Empty and then This.Removed.Is_Empty)); ----------- -- Print -- ----------- procedure Print (This : Diff) is Table : Utils.Tables.Table; procedure Summarize (List : Containers.List; Comment : String; Icon : String) is begin for Dep of List loop Table .Append (" " & Icon) .Append (Utils.TTY.Name (+Dep.Crate)) .Append (Utils.TTY.Version (Dep.Versions.Image)) .Append (Comment) .New_Row; end loop; end Summarize; begin if This.Contains_Changes then Summarize (This.Added, "(add)", (if TTY.Color_Enabled then TTY.OK ("✓") else "+")); Summarize (This.Removed, "(remove)", (if TTY.Color_Enabled then TTY.Emph ("✗") else "-")); Table.Print (Info); else Trace.Info (" No changes."); end if; end Print; ------------- -- Removed -- ------------- function Removed (This : Diff) return Containers.List is (This.Removed); end Alire.Dependencies.Diffs; alire-1.2.1/src/alire/alire-dependencies-diffs.ads000066400000000000000000000012001430264165500217730ustar00rootroot00000000000000with Alire.Conditional; with Alire.Dependencies.Containers; package Alire.Dependencies.Diffs is type Diff is tagged private; function Between (Former, Latter : Conditional.Dependencies) return Diff; function Between (Former, Latter : Containers.List) return Diff; function Added (This : Diff) return Containers.List; function Removed (This : Diff) return Containers.List; function Contains_Changes (This : Diff) return Boolean; procedure Print (This : Diff); private type Diff is tagged record Added : Containers.List; Removed : Containers.List; end record; end Alire.Dependencies.Diffs; alire-1.2.1/src/alire/alire-dependencies-graphs.adb000066400000000000000000000145651430264165500221650ustar00rootroot00000000000000with Alire.Directories; with Alire.OS_Lib.Subprocess; with Alire.Paths; with Alire.Utils.Tables; package body Alire.Dependencies.Graphs is ----------------- -- Empty_Graph -- ----------------- function Empty_Graph return Graph is (Dep_Sets.Empty_Set with null record); ------------------- -- From_Instance -- ------------------- function From_Solution (Sol : Solutions.Solution; Env : Properties.Vector) return Graph is begin return Result : Graph do for Rel of Sol.Releases loop Result := Result.Including (Rel, Env); end loop; Result := Result.Filtering_Unused (Sol.Crates); end return; end From_Solution; --------------- -- Including -- --------------- function Including (This : Graph; R : Releases.Release; Env : Properties.Vector) return Graph is begin return Result : Graph := This do for Dep of R.Flat_Dependencies (Env) loop Result.Include (New_Dependency (R.Name, Dep.Crate)); end loop; end return; end Including; ---------------------- -- Filtering_Unused -- ---------------------- function Filtering_Unused (This : Graph; Used : Alire.Containers.Crate_Name_Sets.Set) return Graph is begin return Result : Graph do for Dep of This loop if Used.Contains (+Dep.Dependee) then Result.Include (Dep); end if; end loop; end return; end Filtering_Unused; ---------------------- -- Has_Dependencies -- ---------------------- function Has_Dependencies (This : Graph; Crate : Alire.Crate_Name) return Boolean is begin for Dep of This loop if +Dep.Dependent = Crate then return True; end if; end loop; return False; end Has_Dependencies; ----------- -- Label -- ----------- function Label_Dependee (Dependent : Crate_Name; Dependee : Crate_Name; Solution : Solutions.Solution; For_Plot : Boolean) return String -- Get the proper label in the graph for a crate: milestone for releases, -- dependency for hints. is begin -- For a solved dependency, return "crate=version (original dependency)" -- For an unsolved dependency, return "crate^dependency". In the case of -- For_Plot, omit the (original dependency). if Solution.State (Dependee).Has_Release then if For_Plot then return Solution.State (Dependee).Milestone_Image (Color => False); else return Solution.State (Dependee).Milestone_Image & " (" & TTY.Version (Solution.Dependency (Dependent, Dependee).Versions.Image) & ")"; end if; else if For_Plot then return Solution.Dependency (Dependent, Dependee).Image; else return Solution.Dependency (Dependent, Dependee).TTY_Image; end if; end if; end Label_Dependee; --------------------- -- Label_Dependent -- --------------------- function Label_Dependent (Crate : Crate_Name; Solution : Solutions.Solution; TTY : Boolean := False) return String is (if TTY then Solution.State (Crate).Release.Milestone.TTY_Image else Solution.State (Crate).Release.Milestone.Image); ---------- -- Plot -- ---------- procedure Plot (This : Graph; Solution : Solutions.Solution) is function B (Str : String) return String is ("[ " & Str & " ]"); function Q (Str : String) return String is ("""" & Str & """"); Source : AAA.Strings.Vector; Alt : AAA.Strings.Vector; Filtered : constant Graph := This.Filtering_Unused (Solution.Crates); begin Alt.Append ("graph dependencies {"); for Dep of Filtered loop Alt.Append (Q (Label_Dependent (+Dep.Dependent, Solution)) & " -> " & Q (Label_Dependee (+Dep.Dependent, +Dep.Dependee, Solution, For_Plot => True)) & "; "); Source.Append (B (Label_Dependent (+Dep.Dependent, Solution)) & " -> " & B (Label_Dependee (+Dep.Dependent, +Dep.Dependee, Solution, For_Plot => True))); end loop; Alt.Append (" }"); declare Tmp : Directories.Temp_File; begin Source.Write (Tmp.Filename, Separator => " "); OS_Lib.Subprocess.Checked_Spawn (Paths.Scripts_Graph_Easy, AAA.Strings.Empty_Vector .Append ("--as=boxart") .Append (Tmp.Filename)); end; end Plot; ----------- -- Print -- ----------- procedure Print (This : Graph; Solution : Solutions.Solution; Prefix : String := "") is Table : Alire.Utils.Tables.Table; Filtered : constant Graph := This.Filtering_Unused (Solution.Crates); begin for Dep of Filtered loop Table.Append (Prefix & Label_Dependent (+Dep.Dependent, Solution, TTY => True)); Table.Append ("-->"); Table.Append (Label_Dependee (+Dep.Dependent, +Dep.Dependee, Solution, For_Plot => False)); Table.New_Row; end loop; Table.Print (Always); end Print; ----------------------- -- Removing_Dependee -- ----------------------- function Removing_Dependee (This : Graph; Crate : Alire.Crate_Name) return Graph is begin return Result : Graph do for Dep of This loop if +Dep.Dependee /= Crate then Result.Include (Dep); end if; end loop; end return; end Removing_Dependee; end Alire.Dependencies.Graphs; alire-1.2.1/src/alire/alire-dependencies-graphs.ads000066400000000000000000000043751430264165500222040ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Sets; with Alire.Containers; with Alire.Properties; with Alire.Releases; with Alire.Solutions; package Alire.Dependencies.Graphs is type Graph is tagged private; function Empty_Graph return Graph; function From_Solution (Sol : Solutions.Solution; Env : Properties.Vector) return Graph; function Including (This : Graph; R : Releases.Release; Env : Properties.Vector) return Graph; -- Add a release and ALL its potential direct dependencies (even OR'ed) function Filtering_Unused (This : Graph; Used : Alire.Containers.Crate_Name_Sets.Set) return Graph; -- Remove dependencies that don't appear in the set of used releases function Has_Dependencies (This : Graph; Crate : Alire.Crate_Name) return Boolean; -- Say if Crate has dependencies in the current graph (hence not -- installable yet). function Removing_Dependee (This : Graph; Crate : Alire.Crate_Name) return Graph; -- Remove all dependencies with Crate as the dependee crate procedure Plot (This : Graph; Solution : Solutions.Solution); -- Requires graph-easy in PATH procedure Print (This : Graph; Solution : Solutions.Solution; Prefix : String := ""); -- Print to terminal with the milestone info in Instance private type Dependency (L1, L2 : Natural) is record Dependent : String (1 .. L1); -- Should be crate names but bug Dependee : String (1 .. L2); end record; function "<" (L, R : Dependency) return Boolean is (L.Dependent < R.Dependent or else (L.Dependent = R.Dependent and then L.Dependee < R.Dependee)); function New_Dependency (Dependent, Dependee : Alire.Crate_Name) return Dependency is (Dependent.Length, Dependee.Length, +Dependent, +Dependee); package Dep_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Dependency); type Graph is new Dep_Sets.Set with null record; end Alire.Dependencies.Graphs; alire-1.2.1/src/alire/alire-dependencies-states-maps.adb000066400000000000000000000037511430264165500231350ustar00rootroot00000000000000package body Alire.Dependencies.States.Maps is use TOML; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Map is -- Read from an array of key: -- [[state]] States : constant TOML_Value := From.Unwrap; -- The TOML array begin return This : Map do for I in 1 .. States.Length loop declare Status : constant State := Dependencies.States.From_TOML (From.Descend (States.Item (I), "state " & I'Img)); begin This.Insert (Status.Crate, Status); end; end loop; end return; end From_TOML; --------------- -- Including -- --------------- function Including (Base : Map; State : States.State) return Map is begin return Result : Map := Base do Result.Include (State.Crate, State); end return; end Including; ------------- -- Merging -- ------------- function Merging (Base : Map; Dep : Dependencies.Dependency) return Map is New_Dep : constant State := (if Base.Contains (Dep.Crate) then Base (Dep.Crate).Merging (Dep.Versions) else States.New_State (Dep)); begin return Result : Map := Base do Result.Include (Dep.Crate, New_Dep); end return; end Merging; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Map) return TOML.TOML_Value is -- Stored as an array of individual states: -- [[state]] begin return Arr : constant TOML_Value := Create_Array do for Dep of This loop Arr.Append (Dep.To_TOML); end loop; end return; end To_TOML; end Alire.Dependencies.States.Maps; alire-1.2.1/src/alire/alire-dependencies-states-maps.ads000066400000000000000000000015711430264165500231540ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; package Alire.Dependencies.States.Maps is package State_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, State); type Map is new State_Maps.Map and Interfaces.Tomifiable with null record; function Including (Base : Map; State : States.State) return Map; -- Add or replace a state -- no merging of versions takes place function Merging (Base : Map; Dep : Dependencies.Dependency) return Map; -- When Dep is new in Base, add Dep as Unknown, Unsolved, Unpinned. -- Otherwise, "and" Dep versions without modifying the state. function From_TOML (From : TOML_Adapters.Key_Queue) return Map; overriding function To_TOML (This : Map) return TOML.TOML_Value; end Alire.Dependencies.States.Maps; alire-1.2.1/src/alire/alire-dependencies-states.adb000066400000000000000000000144251430264165500221770ustar00rootroot00000000000000with Alire.Manifest; with Alire.Milestones; with Alire.Origins; with Alire.Roots.Optional; package body Alire.Dependencies.States is overriding function "=" (L, R : Stored_Release) return Boolean is use type Milestones.Milestone; use type Origins.Origin; begin return (L.Is_Empty and then R.Is_Empty) or else (not L.Is_Empty and then not R.Is_Empty and then L.Element.Milestone = R.Element.Milestone and then L.Element.Origin = R.Element.Origin); end "="; ---------------------- -- Optional_Release -- ---------------------- function Optional_Release (Crate : Crate_Name; Workspace : Any_Path) return Stored_Release is Opt_Root : constant Roots.Optional.Root := Roots.Optional.Detect_Root (Workspace); begin if Opt_Root.Is_Valid then if Opt_Root.Value.Release.Name = Crate then return To_Holder (Opt_Root.Value.Release); else Raise_Checked_Error ("crate mismatch: expected " & Crate.TTY_Image & " but found " & Opt_Root.Value.Release.Name.TTY_Image & " at " & TTY.URL (Workspace)); end if; else return (Releases.Containers.Release_Holders.Empty_Holder with null record); end if; end Optional_Release; use TOML; package Keys is Crate : constant String := "crate"; Fulfilment : constant String := "fulfilment"; Link : constant String := "link"; Pin_Version : constant String := "pin_version"; Pinned : constant String := "pinned"; Release : constant String := "release"; Shared : constant String := "shared"; Transitivity : constant String := "transitivity"; Versions : constant String := "versions"; end Keys; -- The output format is plainly each field in State with its value in a -- table: field = "value" --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return State is Crate : constant Crate_Name := +From.Checked_Pop (Keys.Crate, TOML_String).As_String; Versions : constant Semantic_Versioning.Extended.Version_Set := Semantic_Versioning.Extended.Value (From.Checked_Pop (Keys.Versions, TOML_String).As_String); --------------------- -- Load_Fulfilment -- --------------------- function Load_Fulfilment return Fulfillment_Data is Data : Fulfillment_Data (Fulfillments'Value (From.Checked_Pop (Keys.Fulfilment, TOML_String).As_String)); begin -- Load particulars case Data.Fulfillment is when Hinted => null; when Linked => Data.Target := To_Holder (User_Pins.From_TOML (From.Descend (Value => From.Checked_Pop (Keys.Link, TOML_Table), Context => Keys.Link))); Data.Opt_Rel := Optional_Release (From_TOML.Crate, Data.Target.Element.Path); when Missed => null; when Solved => Data.Release := To_Holder (Releases.From_TOML (From.Descend (From.Checked_Pop (Keys.Release, TOML_Table), "release: " & (+Crate)), Manifest.Index, Strict => False)); -- because it may come from elsewhere Data.Shared := From.Checked_Pop (Keys.Shared, TOML_Boolean).As_Boolean; end case; return Data; end Load_Fulfilment; begin return This : State := New_Dependency (Crate, Versions) do -- Transitivity This.Transitivity := Transitivities'Value (From.Checked_Pop (Keys.Transitivity, TOML_String).As_String); -- Pinning declare Data : Pinning_Data (From.Checked_Pop (Keys.Pinned, TOML_Boolean).As_Boolean); begin if Data.Pinned then Data.Version := Semantic_Versioning.Parse (From.Checked_Pop (Keys.Pin_Version, TOML_String).As_String); end if; This.Pinning := Data; end; -- Fulfilling This.Fulfilled := Load_Fulfilment; end return; end From_TOML; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : State) return TOML.TOML_Value is use TOML_Adapters; use AAA.Strings; ------------- -- To_TOML -- ------------- procedure To_TOML (Data : Fulfillment_Data; Table : TOML_Value) is begin Table.Set (Keys.Fulfilment, +To_Lower_Case (This.Fulfilled.Fulfillment'Img)); case Data.Fulfillment is when Hinted => null; when Linked => Table.Set (Keys.Link, Data.Target.Get.To_TOML); when Missed => null; when Solved => Table.Set (Keys.Release, This.Fulfilled.Release.Constant_Reference.To_TOML (Manifest.Index)); Table.Set (Keys.Shared, Create_Boolean (This.Fulfilled.Shared)); end case; end To_TOML; begin return Table : constant TOML_Value := Create_Table do -- Base Table.Set (Keys.Crate, +(+This.Crate)); Table.Set (Keys.Versions, +This.Versions.Image); -- Transitivity Table.Set (Keys.Transitivity, +To_Lower_Case (This.Transitivity'Img)); -- Pinning Table.Set (Keys.Pinned, Create_Boolean (This.Pinning.Pinned)); if This.Pinning.Pinned then Table.Set (Keys.Pin_Version, +This.Pinning.Version.Image); end if; -- Fulfilment To_TOML (This.Fulfilled, Table); end return; end To_TOML; end Alire.Dependencies.States; alire-1.2.1/src/alire/alire-dependencies-states.ads000066400000000000000000000451071430264165500222210ustar00rootroot00000000000000private with AAA.Containers.Indefinite_Holders; with Alire.Releases.Containers; with Alire.TOML_Adapters; with Alire.User_Pins; package Alire.Dependencies.States is -- This type is used to store the state of a dependency post-solving. This -- extra information goes into the lockfile and allows tracking the status -- of special dependencies (pins, links, missing) across solution changes. type Fulfillments is (Missed, -- Version not found, nor external definition Hinted, -- Undetected external Linked, -- Supplied for any version by a local dir Solved); -- Solved with an index release/detected hint type Transitivities is (Unknown, -- Needed by limitations in the solver Direct, -- A dependency of the root release Indirect); -- A dependency introduced transitively subtype Softlink is User_Pins.Pin with Dynamic_Predicate => Softlink.Kind in User_Pins.Kinds_With_Path; type State (<>) is new Dependency with private; ------------------ -- Constructors -- ------------------ function New_State (Base : Dependency) return State; -- Initializes a new Missing, Unknown, Unpinned state. function Hinting (Base : State) return State; -- Change fulfilment to Hinted in copy of Base function Linking (Base : State; Link : Softlink) return State; -- Returns a copy of Base fulfilled by Path function Merging (Base : State; Versions : Semantic_Versioning.Extended.Version_Set) return State; -- Returns a copy of Base with additional anded versions function Missing (Base : State) return State; -- Change fulfilment to Missed in copy of Base function Pinning (Base : State; Version : Semantic_Versioning.Version) return State; -- Sets the pin in a copy of Base function Setting (Base : State; Transitivity : Transitivities) return State; -- Modify transitivity in a copy of Base function Solving (Base : State; Using : Releases.Release; Shared : Boolean := False) return State with Pre => Using.Provides (Base.Crate); -- Uses release to fulfill this dependency in a copy of Base function Unlinking (Base : State) return State; -- Unlinks the crate in a copy of Base, becoming Missed function Unpinning (Base : State) return State; -- Removes the pin in a copy of Base ---------------- -- Attributes -- ---------------- function As_Dependency (This : State) return Dependencies.Dependency; -- Upcast for convenience, equivalent to Dependencies.Dependency (This) function Has_Release (This : State) return Boolean; -- Says if a release can be retrieved for this state (a solved dependency, -- or a linked crate folder with alire context). -- Simple status identification function Is_Direct (This : State) return Boolean; function Is_Hinted (This : State) return Boolean; function Is_Indirect (This : State) return Boolean; function Is_Linked (This : State) return Boolean; function Is_Missing (This : State) return Boolean; function Is_Pinned (This : State) return Boolean; function Is_Provided (This : State) return Boolean; -- True when the release name is different from the dependency crate function Is_Shared (This : State) return Boolean; function Is_User_Pinned (This : State) return Boolean; -- From the POV of users, pinning to version or linking to dir is a pin function Is_Solved (This : State) return Boolean; -- Case-specific info function Fulfilment (This : State) return Fulfillments; function Link (This : State) return Softlink with Pre => This.Is_Linked; function Pin_Version (This : State) return Semantic_Versioning.Version with Pre => This.Is_Pinned; function User_Pin (This : State) return User_Pins.Pin with Pre => This.Is_User_Pinned; function Release (This : State) return Releases.Release with Pre => This.Has_Release; function Transitivity (This : State) return Transitivities; -- Imaging overriding function Image (This : State) return String; function Milestone_Image (This : State; Color : Boolean := True) return String with Pre => This.Has_Release; -- Will use the dep name if it differs from the dependency (due to -- equivalences). overriding function TTY_Image (This : State) return String; ------------------- -- Serialization -- ------------------- function From_TOML (From : TOML_Adapters.Key_Queue) return State; overriding function To_TOML (This : State) return TOML.TOML_Value; private use type Semantic_Versioning.Extended.Version_Set; type Stored_Release is new Releases.Containers.Release_H with null record; -- New type to simplify comparison of optional stored releases overriding function "=" (L, R : Stored_Release) return Boolean; -- Comparing releases directly returns always false due to some internal -- discrepancy not yet clear. For the purposes of comparing solutions, we -- rely on the milestone and origin for solved releases, which is the kind -- of uniqueness we want at this level. -- Helper functions function Optional_Release (Crate : Crate_Name; Workspace : Any_Path) return Stored_Release; -- Detect if Workspace is a valid Alire crate for the given Crate, in which -- case the returned release will be valid. Otherwise it will be empty. If -- the crate found does not match Crate in name, a Checked_Error will be -- raised. -- Base overridings overriding function From_String (Unused_Spec : String) return State is (raise Program_Error with "Not intended for use"); overriding function From_TOML (Unused_Key : String; Unused_Value : TOML.TOML_Value) return State; overriding function New_Dependency (Crate : Crate_Name; Version : Semantic_Versioning.Version) return State; overriding function New_Dependency (Milestone : Milestones.Milestone; Updatable : Boolean := False) return State; -- Create a dependency from a milestone. If Updatable, use the appropriate -- caret/tilde versions set modifier; otherwise depend on the exact -- milestone. -- Helper types overriding function New_Dependency (Crate : Crate_Name; Versions : Semantic_Versioning.Extended.Version_Set) return State; package Link_Holders is new AAA.Containers.Indefinite_Holders (Softlink); type Link_Holder is new Link_Holders.Holder with null record; function Get (This : Link_Holder) return Softlink renames Element; type Fulfillment_Data (Fulfillment : Fulfillments := Missed) is record case Fulfillment is when Linked => Target : Link_Holder; Opt_Rel : Stored_Release; -- This might not be filled-in when Solved => Release : Stored_Release; -- This is always valid Shared : Boolean; -- The release is from shared install when others => null; end case; end record; type Pinning_Data (Pinned : Boolean := False) is record case Pinned is when True => Version : Semantic_Versioning.Version; when False => null; end case; end record; ----------- -- State -- ----------- type State (Name_Len : Natural) is new Dependency (Name_Len) with record Fulfilled : Fulfillment_Data; Pinning : Pinning_Data; Transitivity : Transitivities := Unknown; end record; ------------------- -- As_Dependency -- ------------------- function As_Dependency (This : State) return Dependencies.Dependency is (Dependencies.Dependency (This)); --------------- -- From_TOML -- --------------- overriding function From_TOML (Unused_Key : String; Unused_Value : TOML.TOML_Value) return State is (raise Unimplemented); -- not needed ---------------- -- Fulfilment -- ---------------- function Fulfilment (This : State) return Fulfillments is (This.Fulfilled.Fulfillment); ----------------- -- Has_Release -- ----------------- function Has_Release (This : State) return Boolean is (This.Is_Solved or else (This.Is_Linked and then not This.Fulfilled.Opt_Rel.Is_Empty)); ------------- -- Hinting -- ------------- function Hinting (Base : State) return State is (Base.As_Dependency with Name_Len => Base.Name_Len, Fulfilled => (Fulfillment => Hinted), Pinning => Base.Pinning, Transitivity => Base.Transitivity); ----------- -- Image -- ----------- overriding function Image (This : State) return String is (This.As_Dependency.Image & " (" & AAA.Strings.To_Lower_Case (if This.Transitivity /= Unknown then This.Transitivity'Img & "," else "") & AAA.Strings.To_Lower_Case (This.Fulfilled.Fulfillment'Img) & (if This.Fulfilled.Fulfillment = Linked then "," & This.Fulfilled.Target.Element.Image (User => True) & (if not This.Fulfilled.Target.Element.Is_Broken then "" else ",broken") & (if This.Fulfilled.Target.Element.Is_Remote then ",url=" & This.Fulfilled.Target.Element.URL else "") & (if This.Has_Release then ",release" else "") & (if This.Is_Shared then ",installed" else "") else "") & (if This.Pinning.Pinned then ",pin=" & This.Pinning.Version.Image else "") & ")"); -------- -- Is -- -------- function Is_Direct (This : State) return Boolean is (This.Transitivity = Direct); function Is_Hinted (This : State) return Boolean is (This.Fulfilled.Fulfillment = Hinted); function Is_Indirect (This : State) return Boolean is (This.Transitivity = Indirect); function Is_Linked (This : State) return Boolean is (This.Fulfilled.Fulfillment = Linked); function Is_Missing (This : State) return Boolean is (This.Fulfilled.Fulfillment = Missed); function Is_Pinned (This : State) return Boolean is (This.Pinning.Pinned); function Is_Provided (This : State) return Boolean is (This.Has_Release and then This.Release.Name /= This.Crate); function Is_Shared (This : State) return Boolean is (This.Fulfilled.Fulfillment = Solved and then This.Fulfilled.Shared); function Is_Solved (This : State) return Boolean is (This.Fulfilled.Fulfillment = Solved); function Is_User_Pinned (This : State) return Boolean is (This.Is_Pinned or else This.Is_Linked); ---------- -- Link -- ---------- function Link (This : State) return Softlink is (This.Fulfilled.Target.Get); ------------- -- Linking -- ------------- function Linking (Base : State; Link : Softlink) return State is (Base.As_Dependency with Name_Len => Base.Name_Len, Fulfilled => (Fulfillment => Linked, Target => To_Holder (Link), Opt_Rel => Optional_Release (Base.Crate, Link.Path)), Pinning => Base.Pinning, Transitivity => Base.Transitivity); ------------- -- Merging -- ------------- function Merging (Base : State; Versions : Semantic_Versioning.Extended.Version_Set) return State is (Dependencies.New_Dependency (Base.Crate, Base.Versions and Versions) with Name_Len => Base.Name_Len, Fulfilled => Base.Fulfilled, Pinning => Base.Pinning, Transitivity => Base.Transitivity); --------------------- -- Milestone_Image -- --------------------- function Milestone_Image (This : State; Color : Boolean := True) return String is (if Color then Utils.TTY.Name (This.Crate) & "=" & TTY.Version (This.Release.Version.Image) & (if This.Crate /= This.Release.Name then " (" & CLIC.TTY.Italic (This.Release.Name.As_String) & ")" else "") else (+This.Crate) & "=" & This.Release.Version.Image & (if This.Crate /= This.Release.Name then " (" & This.Release.Name.As_String & ")" else "") ); ------------- -- Missing -- ------------- function Missing (Base : State) return State is (Base.As_Dependency with Name_Len => Base.Name_Len, Fulfilled => (Fulfillment => Missed), Pinning => Base.Pinning, Transitivity => Base.Transitivity); -------------------- -- New_Dependency -- -------------------- overriding function New_Dependency (Crate : Crate_Name; Version : Semantic_Versioning.Version) return State is (New_State (Dependencies.New_Dependency (Crate, Version))); -------------------- -- New_Dependency -- -------------------- overriding function New_Dependency (Crate : Crate_Name; Versions : Semantic_Versioning.Extended.Version_Set) return State is (New_State (Dependencies.New_Dependency (Crate, Versions))); -------------------- -- New_Dependency -- -------------------- overriding function New_Dependency (Milestone : Milestones.Milestone; Updatable : Boolean := False) return State is (New_State (if Updatable then Dependencies.New_Dependency (Milestone.Crate, Semantic_Versioning.Updatable (Milestone.Version)) else Dependencies.New_Dependency (Milestone.Crate, Milestone.Version))); --------------- -- New_State -- --------------- function New_State (Base : Dependency) return State is (State'(Base with Name_Len => Base.Crate.Name'Length, others => <>)); ----------------- -- Pin_Version -- ----------------- function Pin_Version (This : State) return Semantic_Versioning.Version is (This.Pinning.Version); ------------- -- Pinning -- ------------- function Pinning (Base : State; Version : Semantic_Versioning.Version) return State is (Base.As_Dependency with Name_Len => Base.Name_Len, Fulfilled => Base.Fulfilled, Pinning => (Pinned => True, Version => Version), Transitivity => Base.Transitivity); ------------- -- Release -- ------------- function Release (This : State) return Releases.Release is (if This.Is_Solved then This.Fulfilled.Release.Element elsif This.Is_Linked then This.Fulfilled.Opt_Rel.Element else raise Program_Error with "dependency has no release: " & This.Crate.TTY_Image); ------------- -- Setting -- ------------- function Setting (Base : State; Transitivity : Transitivities) return State is (Base.As_Dependency with Name_Len => Base.Name_Len, Fulfilled => Base.Fulfilled, Pinning => Base.Pinning, Transitivity => Transitivity); ------------- -- Solving -- ------------- function Solving (Base : State; Using : Releases.Release; Shared : Boolean := False) return State is (Base.As_Dependency with Name_Len => Base.Name_Len, Fulfilled => (Fulfillment => Solved, Release => To_Holder (Using), Shared => Shared), Pinning => Base.Pinning, Transitivity => Base.Transitivity); ------------------ -- Transitivity -- ------------------ function Transitivity (This : State) return Transitivities is (This.Transitivity); --------------- -- TTY_Image -- --------------- overriding function TTY_Image (This : State) return String is (This.As_Dependency.TTY_Image & " (" & AAA.Strings.To_Lower_Case (if This.Transitivity /= Unknown then This.Transitivity'Img & "," else "") & AAA.Strings.To_Lower_Case (case This.Fulfilled.Fulfillment is when Missed => TTY.Error (This.Fulfilled.Fulfillment'Img), when Hinted => TTY.Warn (This.Fulfilled.Fulfillment'Img), when others => This.Fulfilled.Fulfillment'Img) & (if This.Fulfilled.Fulfillment = Linked then "," & This.Fulfilled.Target.Element.Image (User => True) & (if not This.Fulfilled.Target.Element.Is_Broken then "" else "," & TTY.Error ("broken")) & (if This.Has_Release then "," & TTY.OK ("release") else "") & (if This.Is_Shared then "," & TTY.Emph ("installed") else "") else "") & (if This.Pinning.Pinned then "," & TTY.Emph ("pin") & "=" & TTY.Version (This.Pinning.Version.Image) else "") & ")"); --------------- -- Unlinking -- --------------- function Unlinking (Base : State) return State is (Base.As_Dependency with Name_Len => Base.Name_Len, Fulfilled => (Fulfillment => Missed), Pinning => Base.Pinning, Transitivity => Base.Transitivity); --------------- -- Unpinning -- --------------- function Unpinning (Base : State) return State is (Base.As_Dependency with Name_Len => Base.Name_Len, Fulfilled => Base.Fulfilled, Pinning => (Pinned => False), Transitivity => Base.Transitivity); -------------- -- User_Pin -- -------------- function User_Pin (This : State) return User_Pins.Pin is (if This.Is_Linked then This.Link else User_Pins.New_Version (This.Pin_Version)); end Alire.Dependencies.States; alire-1.2.1/src/alire/alire-dependencies.adb000066400000000000000000000045301430264165500206720ustar00rootroot00000000000000with Ada.Strings.Fixed; with Ada.Strings.Maps; with Alire.TOML_Adapters; with Semantic_Versioning; package body Alire.Dependencies is package Semver renames Semantic_Versioning; ----------------- -- From_String -- ----------------- function From_String (Spec : String) return Dependency is -- Locate and identify the version operator use Ada.Strings; use Ada.Strings.Fixed; use Ada.Strings.Maps; Op_Pos : constant Natural := Index (Spec, To_Set ("*=^~<>/("), Inside); Name : constant String := (if Op_Pos > Spec'First then Spec (Spec'First .. Op_Pos - 1) else Spec); Result : constant Semver.Extended.Result := (if Op_Pos > Spec'First then Semver.Extended.Parse (Spec (Op_Pos .. Spec'Last)) else Semver.Extended.Parse ("*")); begin if Result.Valid then return New_Dependency (+Name, Result.Set); else Raise_Checked_Error ("Invalid version set expression: " & Spec (Op_Pos .. Spec'Last)); end if; exception when Alire.Checked_Error => raise; when E : others => Log_Exception (E); Raise_Checked_Error ("A crate/version string was invalid"); end From_String; --------------- -- From_TOML -- --------------- function From_TOML (Key : String; Value : TOML.TOML_Value) return Dependency is package SV renames Semantic_Versioning; Version_Str : constant String := Value.As_String; EVS : constant SV.Extended.Version_Set := SV.Extended.Value (Version_Str); begin return New_Dependency (+AAA.Strings.To_Lower_Case (Key), EVS); -- TODO: if no operator appears the version, this results in strict -- match. Rust, for example, assumes caret (^) in this case. Do we want -- to do the same? exception when SV.Malformed_Input => raise Checked_Error with "version set invalid: " & Version_Str; end From_TOML; ------------- -- To_TOML -- ------------- overriding function To_TOML (Dep : Dependency) return TOML.TOML_Value is use TOML_Adapters; begin return +Dep.Versions.Image; end To_TOML; end Alire.Dependencies; alire-1.2.1/src/alire/alire-dependencies.ads000066400000000000000000000114351430264165500207150ustar00rootroot00000000000000with Alire.Interfaces; with Alire.Milestones; with Alire.Utils; with Semantic_Versioning.Basic; with Semantic_Versioning.Extended; with TOML; use all type TOML.Any_Value_Kind; private with Alire.Utils.TTY; package Alire.Dependencies with Preelaborate is -- A single dependency is a crate name plus a version set type Dependency (<>) is new Interfaces.Classifiable -- since the crate name is the key and Interfaces.Colorable and Interfaces.Tomifiable and Interfaces.Yamlable with private; function New_Dependency (Crate : Crate_Name; Versions : Semantic_Versioning.Extended.Version_Set) return Dependency; function New_Dependency (Crate : Crate_Name; Version : Semantic_Versioning.Version) return Dependency; function New_Dependency (Milestone : Milestones.Milestone; Updatable : Boolean := False) return Dependency; -- Return either an exact crate=version or a safely upgradable crate^1.x -- dependency for the given milestone. function From_String (Spec : String) return Dependency; -- Intended to parse command-line dependencies given as crate[subset]: -- alr^1.0, alr=1.0, alr~0.7, etc. If no subset is specified, Any version -- is returned. May raise Checked_Error if parsing cannot succeed. function Crate (Dep : Dependency) return Crate_Name; function Versions (Dep : Dependency) return Semantic_Versioning.Extended.Version_Set; function Image (Dep : Dependency) return String; -- Standard-style version image, e.g. "make^3.1" function Manifest_Image (Dep : Dependency) return String; -- Returns a line describing the dependency as it would appear in the -- manifest, e.g.: my_crate = "^3.2.1" overriding function TTY_Image (Dep : Dependency) return String; overriding function Key (Dep : Dependency) return String; function From_TOML (Key : String; Value : TOML.TOML_Value) return Dependency with Pre => (Key'Length >= Min_Name_Length or else raise Checked_Error with "dependency name too short") and then (Value.Kind = TOML.TOML_String or else raise Checked_Error with "dependency version must be a string"); -- May raise Checked_Error with stored Alire.Errors. overriding function To_TOML (Dep : Dependency) return TOML.TOML_Value; -- Creates the RHS of the "crate = 'version'" overriding function To_YAML (Dep : Dependency) return String; function Lexicographical_Sort (L, R : Dependency) return Boolean; -- By name and then version set image private type Dependency (Name_Len : Natural) is new Interfaces.Classifiable and Interfaces.Colorable and Interfaces.Tomifiable and Interfaces.Yamlable with record Crate : Crate_Name (Name_Len); Versions : Semantic_Versioning.Extended.Version_Set; end record; function New_Dependency (Crate : Crate_Name; Versions : Semantic_Versioning.Extended.Version_Set) return Dependency is (Crate.Name'Length, Crate, Versions); function New_Dependency (Crate : Crate_Name; Version : Semantic_Versioning.Version) return Dependency is (New_Dependency (Crate, Semantic_Versioning.Extended.To_Extended (Semantic_Versioning.Basic.Exactly (Version)))); function New_Dependency (Milestone : Milestones.Milestone; Updatable : Boolean := False) return Dependency is (if Updatable then New_Dependency (Milestone.Crate, Semantic_Versioning.Updatable (Milestone.Version)) else New_Dependency (Milestone.Crate, Milestone.Version)); function Crate (Dep : Dependency) return Crate_Name is (Dep.Crate); function Versions (Dep : Dependency) return Semantic_Versioning.Extended.Version_Set is (Dep.Versions); function Image (Dep : Dependency) return String is ((+Dep.Crate) & Dep.Versions.Image); function Manifest_Image (Dep : Dependency) return String is ((+Dep.Crate) & " = " & '"' & Dep.Versions.Image & '"'); overriding function TTY_Image (Dep : Dependency) return String is (Utils.TTY.Name (+Dep.Crate) & TTY.Version (Dep.Versions.Image)); overriding function To_YAML (Dep : Dependency) return String is ("{crate: """ & AAA.Strings.To_Lower_Case (+Dep.Crate) & """, version: """ & Dep.Versions.Image & """}"); overriding function Key (Dep : Dependency) return String is (+Dep.Crate); function Lexicographical_Sort (L, R : Dependency) return Boolean is (L.Crate < R.Crate or else (L.Crate = R.Crate and then L.Versions.Image < R.Versions.Image)); end Alire.Dependencies; alire-1.2.1/src/alire/alire-directories.adb000066400000000000000000000512701430264165500205630ustar00rootroot00000000000000with AAA.Directories; with Ada.Exceptions; with Ada.Numerics.Discrete_Random; with Ada.Unchecked_Deallocation; with Alire.Errors; with Alire.OS_Lib.Subprocess; with Alire.Paths; with Alire.Platforms.Current; with GNATCOLL.VFS; with SI_Units.Binary; package body Alire.Directories is package Adirs renames Ada.Directories; ------------------- -- Temp_Registry -- ------------------- -- To be able to remove temp files when we are forcibly interrupted, we -- keep track of them here. Calling Delete_Temporaries will do the cleanup -- (as file ops are blocking and cannot be done in a protected). protected Temp_Registry is procedure Add (Path : Absolute_Path); -- Add a path to a temporary procedure Del (Path : Absolute_Path); -- Remove a path to a temporary function Get return AAA.Strings.Set; -- Retrieve all current temporaries private Registry : AAA.Strings.Set; end Temp_Registry; protected body Temp_Registry is --------- -- Add -- --------- procedure Add (Path : Absolute_Path) is begin Registry.Include (Path); end Add; --------- -- Del -- --------- procedure Del (Path : Absolute_Path) is begin Registry.Exclude (Path); end Del; --------- -- Get -- --------- function Get return AAA.Strings.Set is (Registry); end Temp_Registry; ------------------------ -- Backup_If_Existing -- ------------------------ procedure Backup_If_Existing (File : Any_Path; Base_Dir : Any_Path := "") is use Ada.Directories; Dst : constant String := (if Base_Dir /= "" then Base_Dir / Simple_Name (File) & ".prev" else File & ".prev"); begin if Exists (File) then if not Exists (Base_Dir) then Create_Directory (Base_Dir); end if; Trace.Debug ("Backing up " & File & " with base dir: " & Base_Dir); Copy_File (File, Dst, "mode=overwrite"); end if; end Backup_If_Existing; ---------- -- Copy -- ---------- procedure Copy (Src_Folder, Dst_Parent_Folder : String; Excluding : String := "") is use Ada.Directories; Search : Search_Type; Item : Directory_Entry_Type; begin Start_Search (Search, Src_Folder, "*"); while More_Entries (Search) loop Get_Next_Entry (Search, Item); if Simple_Name (Item) /= Excluding then -- Recurse for subdirectories if Kind (Item) = Directory and then Simple_Name (Item) /= "." and then Simple_Name (Item) /= ".." then declare Subfolder : constant String := Compose (Dst_Parent_Folder, Simple_Name (Item)); begin if not Exists (Subfolder) then Ada.Directories.Create_Directory (Subfolder); end if; Copy (Full_Name (Item), Subfolder, Excluding); end; -- Copy for files elsif Kind (Item) = Ordinary_File then Copy_File (Full_Name (Item), Compose (Dst_Parent_Folder, Simple_Name (Item))); end if; end if; end loop; End_Search (Search); end Copy; ----------------- -- Create_Tree -- ----------------- procedure Create_Tree (Path : Any_Path) is use GNATCOLL.VFS; begin Make_Dir (Create (+Path)); end Create_Tree; ------------------------ -- Delete_Temporaries -- ------------------------ procedure Delete_Temporaries is Paths : constant AAA.Strings.Set := Temp_Registry.Get; begin if Paths.Is_Empty then Trace.Debug ("No temporaries to remove"); else for Path of Paths loop begin Force_Delete (Path); exception when E : others => Trace.Debug ("Could not delete temporary " & Path & ": " & Errors.Get (E)); Log_Exception (E); -- As this is used during final cleanup, any exception here -- is logged but not raised. Maybe this can happen for open -- files? end; end loop; end if; end Delete_Temporaries; ----------------- -- Delete_Tree -- ----------------- procedure Delete_Tree (Path : Any_Path) is begin Ensure_Deletable (Path); Ada.Directories.Delete_Tree (Path); end Delete_Tree; ---------------------- -- Detect_Root_Path -- ---------------------- function Detect_Root_Path (Starting_At : Absolute_Path := Current) return String is use Ada.Directories; --------------------------- -- Find_Candidate_Folder -- --------------------------- function Find_Candidate_Folder (Path : Any_Path) return Any_Path is begin Trace.Debug ("Looking for alire metadata at: " & Path); if Exists (Path / Paths.Crate_File_Name) and then Kind (Path / Paths.Crate_File_Name) = Ordinary_File then return Path; else return Find_Candidate_Folder (Containing_Directory (Path)); end if; exception when Use_Error => Trace.Debug ("Root directory reached without finding alire metadata"); return ""; -- There's no containing folder (hence we're at root) end Find_Candidate_Folder; begin return Find_Candidate_Folder (Starting_At); end Detect_Root_Path; ---------------------- -- Ensure_Deletable -- ---------------------- procedure Ensure_Deletable (Path : Any_Path) is use Ada.Directories; begin if Exists (Path) and then Kind (Path) = Directory and then Platforms.Current.Operating_System in Platforms.Windows then Trace.Debug ("Forcing writability of dir " & Path); OS_Lib.Subprocess.Checked_Spawn ("attrib", AAA.Strings.Empty_Vector .Append ("-R") -- Remove read-only .Append ("/D") -- On dirs .Append ("/S") -- Recursively .Append (Path & "\*")); end if; end Ensure_Deletable; ------------------ -- Force_Delete -- ------------------ procedure Force_Delete (Path : Any_Path) is use Ada.Directories; use GNATCOLL.VFS; Success : Boolean := False; begin if Exists (Path) then if Kind (Path) = Ordinary_File then Trace.Debug ("Deleting file " & Path & "..."); Delete_File (Path); elsif Kind (Path) = Directory then Trace.Debug ("Deleting temporary folder " & Path & "..."); Ensure_Deletable (Path); -- Ada.Directories fails when there are softlinks in a tree, so we -- use GNATCOLL instead. GNATCOLL.VFS.Remove_Dir (Create (+Path), Recursive => True, Success => Success); if not Success then raise Program_Error with Errors.Set ("Could not delete: " & TTY.URL (Path)); end if; end if; end if; end Force_Delete; ---------------------- -- Find_Files_Under -- ---------------------- function Find_Files_Under (Folder : String; Name : String; Max_Depth : Natural := Natural'Last) return AAA.Strings.Vector is Found : AAA.Strings.Vector; procedure Locate (Folder : String; Current_Depth : Natural; Max_Depth : Natural) is use Ada.Directories; Search : Search_Type; begin Start_Search (Search, Folder, "", Filter => (Ordinary_File => True, Directory => True, others => False)); while More_Entries (Search) loop declare Current : Directory_Entry_Type; begin Get_Next_Entry (Search, Current); if Kind (Current) = Directory then if Simple_Name (Current) /= "." and then Simple_Name (Current) /= ".." and then Current_Depth < Max_Depth then Locate (Folder / Simple_Name (Current), Current_Depth + 1, Max_Depth); end if; elsif Kind (Current) = Ordinary_File and then Simple_Name (Current) = Simple_Name (Name) then Found.Append (Folder / Name); end if; end; end loop; End_Search (Search); end Locate; use Ada.Directories; begin if Exists (Folder) and then Kind (Folder) = Directory then Locate (Folder, 0, Max_Depth); end if; return Found; end Find_Files_Under; ------------------------ -- Find_Relative_Path -- ------------------------ function Find_Relative_Path (Parent : Any_Path; Child : Any_Path) return Any_Path is begin return AAA.Directories.Relative_Path (Parent, Child); end Find_Relative_Path; ---------------------- -- Find_Single_File -- ---------------------- function Find_Single_File (Path : String; Extension : String) return String is use Ada.Directories; Search : Search_Type; File : Directory_Entry_Type; begin Start_Search (Search => Search, Directory => Path, Pattern => "*" & Extension, Filter => (Ordinary_File => True, others => False)); if More_Entries (Search) then Get_Next_Entry (Search, File); return Name : constant String := (if More_Entries (Search) then "" else Full_Name (File)) do End_Search (Search); end return; else End_Search (Search); return ""; end if; exception when Name_Error => Trace.Debug ("Search path does not exist: " & Path); return ""; end Find_Single_File; ---------------- -- Initialize -- ---------------- overriding procedure Initialize (This : in out Guard) is use Ada.Strings.Unbounded; begin This.Original := To_Unbounded_String (Current); if This.Enter /= null and then This.Enter.all /= Ada.Directories.Current_Directory and then This.Enter.all /= "" then Trace.Debug ("Entering folder: " & This.Enter.all); Ada.Directories.Set_Directory (This.Enter.all); end if; end Initialize; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Guard) is use Ada.Directories; use Ada.Exceptions; use Ada.Strings.Unbounded; procedure Free is new Ada.Unchecked_Deallocation (String, Destination); Freeable : Destination := This.Enter; begin if This.Enter /= null and then Current_Directory /= To_String (This.Original) then Log ("Going back to folder: " & To_String (This.Original), Debug); Ada.Directories.Set_Directory (To_String (This.Original)); end if; Free (Freeable); exception when E : others => Trace.Debug ("FG.Finalize: unexpected exception: " & Exception_Name (E) & ": " & Exception_Message (E) & " -- " & Exception_Information (E)); end Finalize; ---------------- -- TEMP FILES -- ---------------- function Temp_Name (Length : Positive := 8) return String is subtype Valid_Character is Character range 'a' .. 'z'; package Char_Random is new Ada.Numerics.Discrete_Random (Valid_Character); Gen : Char_Random.Generator; begin Char_Random.Reset (Gen); return Result : String (1 .. Length + 4) do Result (1 .. 4) := "alr-"; Result (Length + 1 .. Result'Last) := ".tmp"; for I in 5 .. Length loop Result (I) := Char_Random.Random (Gen); end loop; end return; end Temp_Name; ---------------- -- Initialize -- ---------------- overriding procedure Initialize (This : in out Temp_File) is Simple_Name : constant String := Temp_Name; begin -- Try to use our alire folder to hide temporaries; return an absolute -- path in any case to avoid problems with the user of the tmp file -- changing working directory. if Ada.Directories.Exists (Paths.Working_Folder_Inside_Root) then -- Create tmp folder if not existing if not Ada.Directories.Exists (Paths.Working_Folder_Inside_Root / Paths.Temp_Folder_Inside_Working_Folder) then Ada.Directories.Create_Path (Paths.Working_Folder_Inside_Root / Paths.Temp_Folder_Inside_Working_Folder); end if; This.Name := +Ada.Directories.Full_Name (Paths.Working_Folder_Inside_Root / Paths.Temp_Folder_Inside_Working_Folder / Simple_Name); else This.Name := +Ada.Directories.Full_Name (Simple_Name); end if; Temp_Registry.Add (+This.Name); end Initialize; -------------- -- Filename -- -------------- function Filename (This : Temp_File) return Absolute_Path is (+This.Name); ---------- -- Keep -- ---------- procedure Keep (This : in out Temp_File) is begin This.Keep := True; Temp_Registry.Del (+This.Name); end Keep; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Temp_File) is use Ada.Directories; begin if This.Keep then return; end if; -- We are deleting it here, so remove from "live" temp files registry Temp_Registry.Del (+This.Name); -- Force writability of folder when in Windows, as some tools (e.g. git) -- that create read-only files will cause a Use_Error Ensure_Deletable (This.Filename); if Exists (This.Filename) then if Kind (This.Filename) = Ordinary_File then Trace.Debug ("Deleting temporary file " & This.Filename & "..."); Delete_File (This.Filename); elsif Kind (This.Filename) = Directory then Trace.Debug ("Deleting temporary folder " & This.Filename & "..."); Delete_Tree (This.Filename); end if; end if; -- Remove temp dir if empty to keep things tidy, and avoid modifying -- lots of tests. if Ada.Directories.Simple_Name (Parent (This.Filename)) = Paths.Temp_Folder_Inside_Working_Folder then AAA.Directories.Remove_Folder_If_Empty (Parent (This.Filename)); end if; exception when E : others => Log_Exception (E); raise; end Finalize; ------------------- -- Traverse_Tree -- ------------------- procedure Traverse_Tree (Start : Relative_Path; Doing : access procedure (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean); Recurse : Boolean := False) is use Ada.Directories; procedure Go_Down (Item : Directory_Entry_Type) is Stop : Boolean := False; begin if Simple_Name (Item) /= "." and then Simple_Name (Item) /= ".." then Doing (Item, Stop); if Stop then return; end if; if Recurse and then Kind (Item) = Directory then Traverse_Tree (Start / Simple_Name (Item), Doing, Recurse); end if; end if; end Go_Down; begin Trace.Debug ("Traversing folder: " & Start); Search (Start, "", (Directory => True, Ordinary_File => True, others => False), Go_Down'Access); end Traverse_Tree; --------------- -- Tree_Size -- --------------- function Tree_Size (Path : Any_Path) return Ada.Directories.File_Size is use Ada.Directories; Result : File_Size := 0; ---------------- -- Accumulate -- ---------------- procedure Accumulate (Item : Directory_Entry_Type; Stop : in out Boolean) is begin Stop := False; if Kind (Item) = Ordinary_File then Result := Result + Size (Item); end if; end Accumulate; begin if not Ada.Directories.Exists (Path) then return 0; end if; case Ada.Directories.Kind (Path) is when Ordinary_File => return Ada.Directories.Size (Path); when Directory => Traverse_Tree (Path, Doing => Accumulate'Access, Recurse => True); return Result; when others => return 0; end case; end Tree_Size; --------------- -- TTY_Image -- --------------- function TTY_Image (Size : Ada.Directories.File_Size) return String is type Modular_File_Size is mod 2 ** Ada.Directories.File_Size'Size; function Image is new SI_Units.Binary.Image (Item => Modular_File_Size, Default_Aft => 1, Unit => "B"); begin return TTY.Emph (Image (Modular_File_Size (Size))); end TTY_Image; --------------- -- With_Name -- --------------- function With_Name (Name : Any_Path) return Temp_File is begin return Temp : constant Temp_File := (Temp_File'(Ada.Finalization.Limited_Controlled with Keep => <>, Name => +Adirs.Full_Name (Name))) do Temp_Registry.Add (+Temp.Name); end return; end With_Name; ------------ -- In_Dir -- ------------ function In_Dir (Dir : Directory_Path; Name : File_Path := "") return Temp_File is begin return Temp : constant Temp_File := With_Name (Dir / (if Name /= "" then Name else Temp_Name)); end In_Dir; -------------- -- REPLACER -- -------------- ------------------- -- Editable_Name -- ------------------- function Editable_Name (This : Replacer) return Any_Path is (This.Temp_Copy.Filename); --------------------- -- New_Replacement -- --------------------- function New_Replacement (File : Any_Path; Backup : Boolean := True; Backup_Dir : Any_Path := "") return Replacer is begin return This : constant Replacer := (Length => File'Length, Backup_Len => Backup_Dir'Length, Original => File, Backup => Backup, Backup_Dir => Backup_Dir, Temp_Copy => <>) do Ada.Directories.Copy_File (File, This.Temp_Copy.Filename); end return; end New_Replacement; ------------- -- Replace -- ------------- procedure Replace (This : in out Replacer) is begin -- Copy around, so never ceases to be a valid manifest in place if This.Backup then Backup_If_Existing (This.Original, This.Backup_Dir); end if; Ada.Directories.Copy_File (This.Editable_Name, This.Original); -- The temporary copy will be cleaned up by This.Temp_Copy finalization end Replace; ----------- -- Touch -- ----------- procedure Touch (File : File_Path) is use GNAT.OS_Lib; Success : Boolean := False; begin if Is_Regular_File (File) then Set_File_Last_Modify_Time_Stamp (File, Current_Time); elsif Ada.Directories.Exists (File) then Raise_Checked_Error ("Can't touch non-regular file: " & File); else Close (Create_File (File, Binary), Success); if not Success then Raise_Checked_Error ("Could not touch new file: " & File); end if; end if; end Touch; end Alire.Directories; alire-1.2.1/src/alire/alire-directories.ads000066400000000000000000000211421430264165500205770ustar00rootroot00000000000000with Ada.Directories; with AAA.Strings; with Alire.OS_Lib; private with Ada.Finalization; package Alire.Directories is function "/" (L, R : String) return String renames OS_Lib."/"; -- Package to enable easy use of "/" package Operators is function "/" (L, R : String) return String renames OS_Lib."/"; end Operators; procedure Backup_If_Existing (File : Any_Path; Base_Dir : Any_Path := ""); -- If File exists, copy to file.prev. If Base_Dir /= "", it is instead -- copied to Base_Dir / Simple_Name (file) & ".prev" procedure Copy (Src_Folder, Dst_Parent_Folder : String; Excluding : String := ""); -- Copies a folder contents to within another existing location. That is, -- equivalent to "cp -r src/* dst/". Excluding may be a single name that -- will not be copied (if file) or recursed into (if folder). function Current return String renames Ada.Directories.Current_Directory; function Parent (Path : Any_Path) return String renames Ada.Directories.Containing_Directory; function Detect_Root_Path (Starting_At : Absolute_Path := Current) return String; -- Return either the valid enclosing root folder, or "" procedure Create_Tree (Path : Any_Path); -- Create Path and all necessary intermediate folders procedure Delete_Tree (Path : Any_Path); -- Equivalent to Ensure_Deletable + Ada.Directories.Delete_Tree procedure Ensure_Deletable (Path : Any_Path); -- In Windows, git checkouts are created with read-only file that do not -- sit well with Ada.Directories.Delete_Tree. procedure Force_Delete (Path : Any_Path); -- Calls Ensure_Deletable and then Adirs.Delete_Tree function Find_Files_Under (Folder : String; Name : String; Max_Depth : Natural := Natural'Last) return AAA.Strings.Vector; -- Recursively search for a file -- Depth 0 means given folder only -- Returns all instances found function Find_Relative_Path (Parent : Any_Path; Child : Any_Path) return Any_Path; -- Given two paths, find the minimal relative path from Parent up to Child. -- May still return an absolute path if Child is not in the same drive -- (Windows) as Parent. function Find_Relative_Path_To (Path : Any_Path) return Any_Path; -- Same as Find_Relative_Path (Parent => Current, Child => Path) function Find_Single_File (Path : String; Extension : String) return String; -- Finds a single file in a folder with the given extension and return its -- absolute path. If more than one, or none, returns "". procedure Touch (File : File_Path); -- If the file exists, update last edition time; otherwise create it. If -- File denotes anything else than a regular file, raise. procedure Traverse_Tree (Start : Relative_Path; Doing : access procedure (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean); Recurse : Boolean := False); -- Traverse all items in a folder, optionally recursively If recursively, -- the directory entry is passed before entering it "." and ".." are -- ignored. If Stop is set to True, traversal will not continue. function Tree_Size (Path : Any_Path) return Ada.Directories.File_Size; -- Size of files under a given point, in bytes. Will return 0 for an -- invalid path or an special file. function TTY_Image (Size : Ada.Directories.File_Size) return String; -- Obtain a human-readable and colorized representation of a file size ---------------- -- GUARD TYPE -- ---------------- -- This type simplifies staying in a folder during the life of a scope. -- Once the scope ends, the current folder is set back to the one it was. type Destination is access String; Stay : constant Destination; type Guard (Enter : Destination := Stay) is limited private; -- use this type in conjunction with Enter_Folder to ensure that the CWD is -- modified and restored when creating/destroying the Folder_Guard. function Enter (Path : String) return Destination is (new String'(Path)); function Stay_In_Current return Destination is (Stay); -- This whole mess of accesses and leaks is due to a bug in the -- in-place initialization of limited --------------------- -- Temporary files -- --------------------- procedure Delete_Temporaries; -- For user forced Ctrl-C interruptions, this will attempt to delete any -- currently existing temporaries. function Temp_Name (Length : Positive := 8) return String with Pre => Length >= 5; -- Return a filename such as "alr-sdrv.tmp". Length refers to the name -- without .tmp. The alr- prefix is fixed. -- TEMP_FILE: obtain a temporary name with optional cleanup type Temp_File is tagged limited private; -- A RAII scoped type to manage a temporary file name. -- Creates an instance with a unique file name. This does nothing on disk. -- The user is responsible for using the temp file name as they see fit. -- The file is deleted once an object of this type goes out of scope. -- If the file/folder was never created on disk nothing will happen. function Filename (This : Temp_File) return Absolute_Path; -- The filename is a random sequence of 8 characters + ".tmp" procedure Keep (This : in out Temp_File); -- If Keep is called, the file/dir will not be erased on finalization. This -- allows creating a temporary that will be deleted in case of failure but -- kept in case of success. function With_Name (Name : Any_Path) return Temp_File; -- Allows initializing the tmp file with a desired name. function In_Dir (Dir : Directory_Path; Name : File_Path := "") return Temp_File; -- Allows initializing the location of the temp file, and optionally the -- name. -- REPLACER: Modify a file "in place" in a safe way (keeping old copy) type Replacer (<>) is tagged limited private; -- A scoped type to ensure that a file is updated and replaced without -- trouble. In case of failure, the original file remains untouched. So -- what happens is: 1) A copy to a temp file is made. 2) This file is -- modified and can be tested as the client sees fit. 3) If the new file is -- proper, the old one is renamed to .prev and the new one takes its place. function New_Replacement (File : Any_Path; Backup : Boolean := True; Backup_Dir : Any_Path := "") return Replacer; -- Receives a file to be modified, and prepares a copy in a temporary. If -- Backup, once the replacement is performed, the original file is kept as -- ".prev". Backup_Dir works as in Alire.Directories.Backup_If_Existing function Editable_Name (This : Replacer) return Any_Path; -- Obtain the editable copy procedure Replace (This : in out Replacer); -- Replace the original file with the edited copy. If this procedure is not -- called, on going out of scope the Replacer will remove the temporary and -- the original file remains untouched. private ------------ -- Guards -- ------------ Stay : constant Destination := null; type Guard (Enter : Destination := Stay) is new Ada.Finalization.Limited_Controlled with record Original : UString; end record; overriding procedure Initialize (This : in out Guard); overriding procedure Finalize (This : in out Guard); ---------------- -- Temp files -- ---------------- type Temp_File is new Ada.Finalization.Limited_Controlled with record Keep : Boolean := False; Name : Unbounded_Absolute_Path; end record; overriding procedure Initialize (This : in out Temp_File); overriding procedure Finalize (This : in out Temp_File); type Replacer (Length, Backup_Len : Natural) is tagged limited record Original : Any_Path (1 .. Length); Temp_Copy : Temp_File; Backup : Boolean := True; Backup_Dir : Any_Path (1 .. Backup_Len); end record; --------------------------- -- Find_Relative_Path_To -- --------------------------- function Find_Relative_Path_To (Path : Any_Path) return Any_Path is (Find_Relative_Path (Current, Path)); end Alire.Directories; alire-1.2.1/src/alire/alire-environment-formatting.adb000066400000000000000000000052701430264165500227620ustar00rootroot00000000000000with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Alire.Platforms.Current; package body Alire.Environment.Formatting is ---------------- -- Find_Start -- ---------------- function Find_Start (Str : Unbounded_String; From : Positive) return Natural is Loc : Natural := From; begin loop Loc := Index (Str, "${", Loc); exit when Loc = 0; -- Check for escape character before the pattern if Loc = 1 or else Element (Str, Loc - 1) /= '\' then return Loc; else -- Pattern found but with an escape character Loc := Loc + 2; end if; end loop; return Loc; end Find_Start; -------------- -- Find_End -- -------------- function Find_End (Str : Unbounded_String; From : Positive) return Natural is begin -- There is not possible escape character between the start and -- the end of the formatting pattern. return Index (Str, "}", From); end Find_End; ------------ -- Format -- ------------ function Format (Release_Dir : Any_Path; Value : String) return String is ------------- -- Replace -- ------------- procedure Replace (Str : in out Unbounded_String; From, To : Positive) is Id : constant String := Slice (Str, From + 2, To - 1); begin if Id = "DISTRIB_ROOT" then Replace_Slice (Str, From, To, Platforms.Current.Distribution_Root); elsif Id = "CRATE_ROOT" then Replace_Slice (Str, From, To, Release_Dir); elsif Id = "_ALIRE_TEST_" then -- This is used to test the env var formatting feature Replace_Slice (Str, From, To, "TEST"); else raise Unknown_Formatting_Key; end if; end Replace; Result : Unbounded_String := To_Unbounded_String (Value); From : Natural := 1; To : Natural; begin loop From := Find_Start (Result, From); if From = 0 then -- All patterns are replaced, if any exit; end if; To := Find_End (Result, From); if To = 0 then -- All patterns are replaced, if any exit; end if; -- A pattern is found Replace (Result, From, To); -- Start again from the beginning of the string From := 1; end loop; return To_String (Result); end Format; end Alire.Environment.Formatting; alire-1.2.1/src/alire/alire-environment-formatting.ads000066400000000000000000000004701430264165500230000ustar00rootroot00000000000000package Alire.Environment.Formatting is function Format (Release_Dir : Any_Path; Value : String) return String; -- Format the environment variable value with ${} replacement patterns Unknown_Formatting_Key : exception; end Alire.Environment.Formatting; alire-1.2.1/src/alire/alire-environment.adb000066400000000000000000000310161430264165500206070ustar00rootroot00000000000000with GNAT.OS_Lib; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Alire_Early_Elaboration; with Alire.Environment.Formatting; with Alire.Errors; with Alire.Properties.Environment; use Alire.Properties.Environment; with Alire.OS_Lib; with Alire.GPR; with Alire.Properties.Scenarios; with Alire.Releases; with Alire.Roots.Editable; with Alire.Solutions; with Alire.Toolchains.Solutions; with Alire.Utils.TTY; with Alire.Platforms.Current; with GNAT.IO; package body Alire.Environment is --------------------- -- Already_Defines -- --------------------- function Already_Defines (Existing, Value : String) return Boolean -- Check that Value is a path-delimited identical value in Existing is (for some Part of AAA.Strings.Vector' (AAA.Strings.Split (Existing, GNAT.OS_Lib.Path_Separator)) => Part = Value); --------- -- Add -- --------- procedure Add (This : in out Context; Name : String; Action : Env_Action) is begin if not This.Actions.Contains (+Name) then declare Empty_Vect : Action_Vectors.Vector; begin This.Actions.Include (+Name, Empty_Vect); end; end if; This.Actions.Reference (+Name).Append (Action); end Add; --------- -- Set -- --------- procedure Set (This : in out Context; Name, Value, Origin : String) is Action : constant Env_Action := (Set, +Value, +Origin); begin This.Add (Name, Action); end Set; ------------ -- Append -- ------------ procedure Append (This : in out Context; Name, Value, Origin : String) is Action : constant Env_Action := (Append, +Value, +Origin); begin This.Add (Name, Action); end Append; ------------- -- Prepend -- ------------- procedure Prepend (This : in out Context; Name, Value, Origin : String) is Action : constant Env_Action := (Prepend, +Value, +Origin); begin This.Add (Name, Action); end Prepend; ---------- -- Load -- ---------- Already_Warned : Boolean := False; procedure Load (This : in out Context; Root : in out Alire.Roots.Root) is Solution : constant Solutions.Solution := Toolchains.Solutions.Add_Toolchain (Root.Solution); Tool_Root : Roots.Editable.Root := Roots.Editable.New_Root (Root); -- We use a copy of the base root to add the toolchain elements that -- might be missing from its solution begin Tool_Root.Set (Solution); -- Load platform environment Alire.Platforms.Current.Load_Environment (This); -- Warnings when setting up an incomplete environment if not Solution.Is_Complete then Trace.Debug ("Generating possibly incomplete environment" & " because of missing dependencies"); -- Normally we would generate a warning, but since that will pollute -- the output making it unusable, for once we write directly to -- stderr (unless quiet is in effect): if not Alire_Early_Elaboration.Switch_Q and then not Already_Warned then Already_Warned := True; GNAT.IO.Put_Line (GNAT.IO.Standard_Error, TTY.Warn ("warn:") & " Generating possibly incomplete environment" & " because of missing dependencies"); end if; end if; -- Project paths for all releases in the solution, implicitly defined by -- supplied project files. declare Sorted_Paths : constant AAA.Strings.Set := Tool_Root.Current.Project_Paths; begin if not Sorted_Paths.Is_Empty then for Path of reverse Sorted_Paths loop -- Reverse should not matter as our paths shouldn't overlap, -- but at least is nicer for user inspection to respect -- alphabetical order. This.Prepend ("GPR_PROJECT_PATH", Path, "crates"); end loop; end if; end; -- Custom definitions provided by each release for Rel of Solution.Releases.Including (Root.Release) loop This.Load (Root => Tool_Root, Crate => Rel.Name); end loop; This.Set ("ALIRE", "True", "Alire"); end Load; ---------- -- Load -- ---------- procedure Load (This : in out Context; Root : in out Roots.Editable.Root; Crate : Crate_Name) is Env : constant Properties.Vector := Root.Current.Environment; Rel : constant Releases.Release := Root.Current.Release (Crate); Origin : constant String := Rel.Name_Str; Release_Base : constant String := Root.Current.Release_Base (Rel.Name); begin Trace.Debug ("Loading environment for crate " & Alire.Utils.TTY.Name (Crate) & " release: " & Rel.Milestone.TTY_Image); -- Environment variables defined in the crate manifest for Act of Rel.Environment (Env) loop Trace.Debug ("Processing env entry: " & Act.Name & " of type " & Act.Action'Image & " with value " & Act.Value); begin declare Value : constant String := Formatting.Format (Release_Base, Act.Value); begin case Act.Action is when Properties.Environment.Set => This.Set (Act.Name, Value, Origin & " (env)"); when Properties.Environment.Append => This.Append (Act.Name, Value, Origin & " (env)"); when Properties.Environment.Prepend => This.Prepend (Act.Name, Value, Origin & " (env)"); end case; end; exception when Formatting.Unknown_Formatting_Key => Raise_Checked_Error ("Unknown environment variable formatting key in var '" & Act.Name & " of '" & Origin & "'"); end; end loop; -- Environment variables for GPR external scenario variables for Property of Rel.On_Platform_Properties (Env) loop if Property in Alire.Properties.Scenarios.Property'Class then declare use all type Alire.GPR.Variable_Kinds; Variable : constant Alire.GPR.Variable := Alire.Properties.Scenarios.Property (Property).Value; begin if Variable.Kind = External then This.Set (Variable.Name, Variable.External_Value, Origin & " (gpr ext)"); end if; end; end if; end loop; -- Set the crate PREFIX location for access to resources This.Set (AAA.Strings.To_Upper_Case (+Rel.Name) & "_ALIRE_PREFIX", Release_Base, "Crate prefix for resources location"); end Load; ----------------- -- Print_Shell -- ----------------- procedure Print_Shell (This : Context; Kind : Platforms.Shells) is begin -- TODO: PowerShell or CMD version for Windows. Is it possible to detect -- the kind of shell we are running in? for Elt of This.Compile loop case Kind is when Platforms.Unix => Trace.Always (To_String ("export " & Elt.Key & "=""" & Elt.Value & """")); when Platforms.PowerShell => Trace.Always (To_String ("$env:" & Elt.Key & " = """ & Elt.Value & """")); when Platforms.WinCmd => Trace.Always (To_String ("set " & Elt.Key & "=" & Elt.Value)); end case; end loop; end Print_Shell; ------------------- -- Print_Details -- ------------------- procedure Print_Details (This : Context) is begin for C in This.Actions.Iterate loop declare Key : constant String := To_String (Action_Maps.Key (C)); begin Trace.Always (" - variable: '" & Key & "'"); for Act of This.Actions (C) loop case Act.Kind is when Properties.Environment.Set => Trace.Always (" - Set to '" & To_String (Act.Value) & "' by '" & To_String (Act.Origin) & "'"); when Properties.Environment.Append => Trace.Always (" - Appended with '" & To_String (Act.Value) & "' by '" & To_String (Act.Origin) & "'"); when Properties.Environment.Prepend => Trace.Always (" - Prepended with '" & To_String (Act.Value) & "' by '" & To_String (Act.Origin) & "'"); end case; end loop; end; end loop; end Print_Details; ------------- -- Compile -- ------------- function Compile (Key : Unbounded_String; Vect : Action_Vectors.Vector) return Var is Separator : constant Character := GNAT.OS_Lib.Path_Separator; Value : Unbounded_String := +OS_Lib.Getenv (+Key); -- Pre-existing value, and new value when no conflict begin for Act of Vect loop -- Print some helpful details to inspect a conflict case Act.Kind is when Properties.Environment.Set => Trace.Detail (+("Env: " & Act.Origin & " sets '" & Act.Value & "' to '" & Key & "'")); when Properties.Environment.Append => Trace.Detail (+("Env: " & Act.Origin & " appends '" & Act.Value & "' to '" & Key & "'")); when Properties.Environment.Prepend => Trace.Detail (+("Env: " & Act.Origin & " prepends '" & Act.Value & "' to '" & Key & "'")); end case; if Length (Value) = 0 then Value := Act.Value; else case Act.Kind is when Properties.Environment.Set => if Value = Act.Value then Trace.Debug ("Skipping identical key value: " & (+Key) & "=" & (+Value)); -- We can silently ignore the attempt to set to the same -- value. This is not ideal, but is more flexible for the -- cases where we may end exporting the same environment -- twice. Long-term, something like Boost.Process would be -- more robust to call subprocesses without pilfering our -- own environment. else Raise_Checked_Error (Errors.Wrap ("Trying to set an already defined environment " & "variable", (+Key) & " is already defined as '" & (+Value) & "' but new value is '" & (+Act.Value) & "'")); end if; when Properties.Environment.Append => if Already_Defines (+Value, +Act.Value) then Trace.Debug ("Skipping identical key value: " & (+Key) & "=" & (+Value)); else Value := Value & Separator & Act.Value; end if; when Properties.Environment.Prepend => if Already_Defines (+Value, +Act.Value) then Trace.Debug ("Skipping identical key value: " & (+Key) & "=" & (+Value)); else Value := Act.Value & Separator & Value; end if; end case; end if; end loop; return (Key => Key, Value => Value); end Compile; ------------- -- Compile -- ------------- function Compile (This : Context) return Var_Array is Result : Var_Array (1 .. Natural (This.Actions.Length)); Index : Natural := Result'First; begin for C in This.Actions.Iterate loop Result (Index) := Compile (Action_Maps.Key (C), This.Actions (C)); Index := Index + 1; end loop; -- Sort results for predictable output Sort (Result); return Result; end Compile; ------------ -- Export -- ------------ procedure Export (This : Context) is begin for Var of This.Compile loop OS_Lib.Setenv (+Var.Key, +Var.Value); end loop; end Export; end Alire.Environment; alire-1.2.1/src/alire/alire-environment.ads000066400000000000000000000067361430264165500206430ustar00rootroot00000000000000with Ada.Strings.Unbounded; with Alire.Properties; with Alire.Platforms; limited with Alire.Roots.Editable; private with Ada.Strings.Unbounded.Hash; private with Ada.Containers.Vectors; private with Ada.Containers.Hashed_Maps; private with Alire.Properties.Environment; private with Ada.Containers.Generic_Array_Sort; package Alire.Environment is Config : constant String := "ALR_CONFIG"; -- Folder where current alr will look for configuration Source : constant String := "ALR_SOURCE"; -- Folder that overrides where alr sources are checked out -- Intended to help developers by pointing it to their sources type Context is tagged limited private; procedure Set (This : in out Context; Name, Value, Origin : String); -- Set a variable in the context procedure Append (This : in out Context; Name, Value, Origin : String); -- Append a value to a variable in the context procedure Prepend (This : in out Context; Name, Value, Origin : String); -- Prepend a value to a variable in the context procedure Load (This : in out Context; Root : in out Alire.Roots.Root); -- Load the environment variables of a releases found in the workspace -- Solution (GPR_PROJECT_PATH and custom variables) in the context. procedure Export (This : Context); -- Export the environment variables built from the variables previously -- loaded and defined in the context. procedure Print_Shell (This : Context; Kind : Platforms.Shells); -- Print the shell commands that can be used to export the environment -- variables. procedure Print_Details (This : Context); -- Print details about the environment context. What are the variables -- definitions and their origin. private type Var is record Key : Ada.Strings.Unbounded.Unbounded_String; Value : Ada.Strings.Unbounded.Unbounded_String; end record; function "<" (Left, Right : Var) return Boolean is (Ada.Strings.Unbounded."<" (Left.Key, Right.Key)); type Var_Array is array (Natural range <>) of Var; procedure Sort is new Ada.Containers.Generic_Array_Sort (Index_Type => Natural, Element_Type => Var, Array_Type => Var_Array); function Compile (This : Context) return Var_Array; -- Return an array of environment variable key/value built from the -- variables previously loaded and defined in the context. type Env_Action is record Kind : Alire.Properties.Environment.Actions; Value : Ada.Strings.Unbounded.Unbounded_String; Origin : Ada.Strings.Unbounded.Unbounded_String; end record; package Action_Vectors is new Ada.Containers.Vectors (Index_Type => Natural, Element_Type => Env_Action); package Action_Maps is new Ada.Containers.Hashed_Maps (Key_Type => Ada.Strings.Unbounded.Unbounded_String, Element_Type => Action_Vectors.Vector, Hash => Ada.Strings.Unbounded.Hash, Equivalent_Keys => Ada.Strings.Unbounded."=", "=" => Action_Vectors."="); type Context is tagged limited record Actions : Action_Maps.Map; end record; procedure Add (This : in out Context; Name : String; Action : Env_Action); procedure Load (This : in out Context; Root : in out Roots.Editable.Root; Crate : Crate_Name); -- Load the environment variables of a release (GPR_PROJECT_PATH and custom -- variables) in the context. end Alire.Environment; alire-1.2.1/src/alire/alire-errors.adb000066400000000000000000000113111430264165500175530ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; with Ada.Containers.Indefinite_Ordered_Maps; package body Alire.Errors is use AAA.Strings; -- Internally, an error is stored with a unique id, which is an integer. -- The exception message gets replaced with this integer. As long as the -- exception handler uses Errors.Get, the user should never get to see -- this meaningless Id. package String_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Positive, String); function To_Int (Id : Unique_Id) return Integer is (Integer'Value (AAA.Strings.Tail (String (Id), ':'))); ----------- -- Store -- ----------- protected Store is procedure Set (Text : String; Id : out Positive); function Get (Id : Unique_Id) return String; procedure Clear (Id : Unique_Id); private Next : Positive := 1; Store : String_Maps.Map; end Store; protected body Store is --------- -- Set -- --------- procedure Set (Text : String; Id : out Positive) is begin Id := Next; Next := Next + 1; Store.Insert (Id, Text); end Set; --------- -- Get -- --------- function Get (Id : Unique_Id) return String is (Store (To_Int (Id))); ----------- -- Clear -- ----------- procedure Clear (Id : Unique_Id) is begin Store.Delete (To_Int (Id)); end Clear; end Store; --------- -- Set -- --------- function Set (Text : String) return String is Id : Positive; begin -- When we store an error, we do so with the current error stack Store.Set (Stack (Text), Id); return Id_Marker & Trim (Id'Img); end Set; --------- -- Get -- --------- function Get (Id : Unique_Id; Clear : Boolean := True) return String is begin return Text : constant String := Store.Get (Id) do if Clear then Store.Clear (Id); end if; end return; end Get; --------- -- Get -- --------- function Get (Ex : Ada.Exceptions.Exception_Occurrence; Clear : Boolean := True) return Outcome is (Outcome_Failure (Get (Ex, Clear))); --------- -- Get -- --------- function Get (Ex : Ada.Exceptions.Exception_Occurrence; Clear : Boolean := True) return String is use Ada.Exceptions; Msg : constant String := Exception_Message (Ex); begin if Is_Error_Id (Msg) then return Get (Unique_Id (Msg), Clear); else return Msg; end if; end Get; ------------------ -- Pretty_Print -- ------------------ procedure Pretty_Print (Error : String) is Lines : constant AAA.Strings.Vector := Split (Error, ASCII.LF); begin for I in Lines.First_Index .. Lines.Last_Index loop declare Line : constant String := Trim (Lines (I)); begin Trace.Error ((if I > Lines.First_Index then " " else "") -- Indentation & Line -- The error proper & (if I < Lines.Last_Index and then Line (Line'Last) /= ':' then ":" else "") -- Trailing ':' except for last line ); end; end loop; end Pretty_Print; ---------- -- Wrap -- ---------- function Wrap (Upper, Lower : String) return String is (Upper & ASCII.LF & Lower); -------------------- -- ERROR STACKING -- -------------------- package String_Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (String); Error_Stack : String_Lists.List; ---------- -- Open -- ---------- function Open (Text : String) return Scope is begin Error_Stack.Append (Text); return (Ada.Finalization.Limited_Controlled with null record); end Open; ---------- -- Open -- ---------- procedure Open (Text : String) is begin Error_Stack.Append (Text); end Open; ----------- -- Close -- ----------- procedure Close is begin Error_Stack.Delete_Last; end Close; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Scope) is pragma Unreferenced (This); begin Close; end Finalize; ----------- -- Stack -- ----------- function Stack (Text : String) return String is Msg : UString; use UStrings; begin for Item of Error_Stack loop Append (Msg, Item & ASCII.LF); end loop; return +Msg & Text; end Stack; end Alire.Errors; alire-1.2.1/src/alire/alire-errors.ads000066400000000000000000000104551430264165500176040ustar00rootroot00000000000000with Ada.Exceptions; private with Ada.Finalization; package Alire.Errors with Preelaborate is -- This package is reentrant and thread-safe. -- Supporting types to ensure an exception message doesn't get truncated. -- Intended usage is to raise with a Set: -- raise My_Exception with Errors.Set ("The sky is falling!"); -- And later report it with Get: -- when E : My_Exception => -- Put_Line (Errors.Get (E)); -- Or, when returning a failed Outcome: -- when E : My_Exception => -- return Errors.Get (E); -- If an error for an exception is not found, the exception own message -- is returned. This way, using this package is transparent and opt-in: -- handlers will either report the proper error, when it exists, or the -- exception message as usual, when it doesn't. type Unique_Id is new String with Dynamic_Predicate => Is_Error_Id (String (Unique_Id)); function Is_Error_Id (Str : String) return Boolean; -- Says if a string actually stores an error id. Used to double check that -- Get functions receive an Id and not another unrelated string by mistake, -- since that would silently return the same string as the error text. function Set (Text : String) return String with Post => Is_Error_Id (Set'Result); -- Stores an error and receives a unique code to later retrieve it. -- The Id is returned as String so it can be directly used as the -- error message in a raise, e.g.: -- raise Checked_Error with Errors.Set (Very_Long_Message); function Get (Id : Unique_Id; Clear : Boolean := True) return String; -- Direct retrieval from Id. If Clear the error is removed from memory. function Get (Ex : Ada.Exceptions.Exception_Occurrence; Clear : Boolean := True) return Outcome with Post => not Get'Result.Success; -- Wrap the error stored for Ex into a failed Outcome. If there was no -- error stored for Ex, its exception message is used instead. function Get (Ex : Ada.Exceptions.Exception_Occurrence; Clear : Boolean := True) return String; -- Returns the error for Ex if it exists, or defaults to Exception_Message. -- The stored error is cleared. procedure Pretty_Print (Error : String); -- Split Error at LFs to prefix each sub-error in a new line with the -- appropriate tracing prefix. Also, from the second line on, messages are -- indented. This way, several top-level errors are easier to distinguish. -- Finally, ':' is appended to every line but the last one if not already -- in the text. function Wrap (Upper, Lower : String) return String; -- Compose a more general (Upper) error with a more detailed error (Lower). -- These are later apt for pretty printing. Even if not pretty printed, -- these merely show in two lines. function Set (Wrapper : String; Wrapped : Ada.Exceptions.Exception_Occurrence) return String is (Set (Wrap (Wrapper, Get (Wrapped)))) with Post => Is_Error_Id (Set'Result); -- Convenience to concatenate two error messages: a new wrapping text and -- an existing error within a exception being wrapped. ----------- -- Scope -- ----------- type Scope (<>) is limited private; -- A type to create a stack of error information. When Errors.Set is used, -- the whole error stack is stored. Manages scope closing automatically. function Open (Text : String) return Scope; -- Push a new message into the error stack procedure Open (Text : String); -- Manually open a scope; used to blend seamlessly the TOML_Adapters. -- Should not be used otherwise. procedure Close; -- As for Open; don't use manually. function Stack (Text : String) return String; -- Return current error stack, plus Text as the latest error private Id_Marker : constant String := "alire-stored-error:"; type Scope is new Ada.Finalization.Limited_Controlled with null record; overriding procedure Finalize (This : in out Scope); ----------------- -- Is_Error_Id -- ----------------- function Is_Error_Id (Str : String) return Boolean is (Str'Length > Id_Marker'Length and then Str (Str'First .. Str'First + Id_Marker'Length - 1) = Id_Marker); end Alire.Errors; alire-1.2.1/src/alire/alire-expressions-enums.adb000066400000000000000000000013621430264165500217530ustar00rootroot00000000000000with AAA.Strings; package body Alire.Expressions.Enums is type Enum_Values is new Expressions.Values with record Values : AAA.Strings.Set; end record; overriding function Is_Valid (This : Enum_Values; Image : String) return Boolean is (This.Values.Contains (TOML_Adapters.Tomify (Image))); begin declare Values : Enum_Values; begin for Enum_Value in Ada_Enum'Range loop Values.Values.Insert (TOML_Adapters.Tomify (Enum_Value'Image)); end loop; Trace.Debug ("Registering variable for expressions: " & Key); Expressions.Register (Var_Key => Key, Var_Name => Name, Var_Values => Values); end; end Alire.Expressions.Enums; alire-1.2.1/src/alire/alire-expressions-enums.ads000066400000000000000000000007261430264165500217770ustar00rootroot00000000000000with Alire.TOML_Adapters; generic Key : String; -- The TOML key used in the index for this enum Name : String := TOML_Adapters.Adafy (Key); -- An Ada-like name, overridable type Ada_Enum is (<>); package Alire.Expressions.Enums with Elaborate_Body is -- Declares a pseudotype that encapsulates an actual Ada enumeration. By -- instancing this package the type becomes recognizable by the index -- loading functions. end Alire.Expressions.Enums; alire-1.2.1/src/alire/alire-expressions-maps.adb000066400000000000000000000043621430264165500215670ustar00rootroot00000000000000package body Alire.Expressions.Maps is ------------ -- Insert -- ------------ procedure Insert (M : in out Map; V : String; E : Elements) is begin if V = TOML_Keys.Case_Others or else V = "others" then M.Set_Others (E); else if not M.Base.Is_Valid (V) and then Force then Trace.Debug ("Storing unknown value '" & V & "' for enumeration '" & Key (M.Base) & "'"); end if; M.Entries.Insert (V, E); end if; end Insert; ---------- -- Keys -- ---------- function Keys (M : Map; Ada_Like : Boolean; Exclude_Others : Boolean) return Key_Array is Pos : Positive := 1; Result : Key_Array (1 .. Natural (M.Entries.Length) + 1); begin for I in M.Entries.Iterate loop Result (Pos) := +Maps.Key (I); Pos := Pos + 1; end loop; if M.Has_Others then if Ada_Like then Result (Result'Last) := +"others"; else Result (Result'Last) := +TOML_Keys.Case_Others; end if; end if; if Exclude_Others or else not M.Has_Others then return Result (Result'First .. Result'Last - 1); else return Result; end if; end Keys; ---------------- -- Set_Others -- ---------------- procedure Set_Others (M : in out Map; E : Elements) is begin M.Other.Insert (TOML_Keys.Case_Others, E); end Set_Others; ---------- -- Size -- ---------- function Size (M : Map; Count : access function (E : Elements) return Natural) return Natural is begin return Total : Natural := 0 do for Elem of M.Entries loop Total := Total + Count (Elem); end loop; end return; end Size; --------------- -- Visit_All -- --------------- procedure Visit_All (M : in out Map; Apply : access procedure (E : in out Elements)) is begin for Elem of M.Entries loop Apply (Elem); end loop; for Elem of M.Other loop Apply (Elem); end loop; end Visit_All; end Alire.Expressions.Maps; alire-1.2.1/src/alire/alire-expressions-maps.ads000066400000000000000000000077641430264165500216210ustar00rootroot00000000000000private with Ada.Containers.Indefinite_Ordered_Maps; with Alire.Errors; generic type Elements (<>) is private; package Alire.Expressions.Maps with Preelaborate is type Map is tagged private; -- The main operation we need in our index expressions is to look up a -- value from the Variable and get the associated value (a dependency, -- a property...). These Maps replace the old arrays over a real enum. function Empty (V : Variable) return Map; -- Initialize a map for a particular type, containing no mapping function Base (M : Map) return Variable; -- Retrieve the type for which this Map was declared function Contains (M : Map; V : String) return Boolean; function Element (M : Map; V : String) return Elements; -- Get an element from the map. If the key V is not in the map, return the -- Other value. If no Other has been set, raise Checked_Error. Conditions -- not given in contract form due to bug in older GNATs. type Key_Array is array (Positive range <>) of UString; function Keys (M : Map; Ada_Like : Boolean; Exclude_Others : Boolean) return Key_Array; -- Lazy solution to avoid full-fledged iteration. We don't expect to -- have more than a few keys anyway. When Ada_Like, "..." is returned as -- "others" instead. When Exclude_Others, only explicit keys are returned. function Other (M : Map) return Elements with Pre => M.Has_Others; -- Retrieve the default value for this map function Has_Others (M : Map) return Boolean; -- Say if a default has been set for this map procedure Insert (M : in out Map; V : String; E : Elements) with Post => M.Element (V) = E; -- Store the mapping V -> E in M. Will fail if the value is already stored. -- If V = "..." or "others", M.Set_Others is called internally. function Size (M : Map; Count : access function (E : Elements) return Natural) return Natural; -- Count how many elements are in the map, with custom Count function (as -- elements may require recursive counting). procedure Set_Others (M : in out Map; E : Elements) with Post => M.Other = E; -- Set the default mapping for this map procedure Visit_All (M : in out Map; Apply : access procedure (E : in out Elements)); -- Visits all elements in the map, including the others value private package Maps is new Ada.Containers.Indefinite_Ordered_Maps (String, Elements); type Map is tagged record Valid : Boolean := False; Base : Variable; Entries : Maps.Map; Other : Maps.Map; -- At most one element, key irrelevant end record; ---------- -- Base -- ---------- function Base (M : Map) return Variable is (if M.Valid then M.Base else raise Checked_Error with "Map is uninitialized"); ----------- -- Empty -- ----------- function Empty (V : Variable) return Map is (Valid => True, Base => V, Entries => <>, Other => <>); -------------- -- Contains -- -------------- function Contains (M : Map; V : String) return Boolean is (M.Entries.Contains (V)); ------------- -- Element -- ------------- function Element (M : Map; V : String) return Elements is (if M.Contains (V) then M.Entries (V) elsif M.Has_Others then Other (M) else raise Checked_Error with Errors.Set ("Map for " & Name (M.Base) & " does not have a value for " & V)); ----------- -- Other -- ----------- function Other (M : Map) return Elements is (if M.Other.Is_Empty then raise Checked_Error with Errors.Set ("default value in case not set") else M.Other.First_Element); ---------------- -- Has_Others -- ---------------- function Has_Others (M : Map) return Boolean is (not M.Other.Is_Empty); end Alire.Expressions.Maps; alire-1.2.1/src/alire/alire-expressions.adb000066400000000000000000000042751430264165500206340ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; with Alire.Errors; with Alire.TOML_Adapters; with Alire.Utils; package body Alire.Expressions is package Key_Variable_Maps is new Ada.Containers.Indefinite_Ordered_Maps (String, Variable); package Variable_Value_Maps is new Ada.Containers.Indefinite_Ordered_Maps (String, Values'Class); Variables : Key_Variable_Maps.Map; Variable_Values : Variable_Value_Maps.Map; -- Stores values for all types that have been declared. Indexed by the -- Variable key. function Key_Variables_Image is new Utils.Image_Keys_One_Line (Key_Variable_Maps); ---------- -- From -- ---------- function From (Key : String) return Variable is (if not Variables.Contains (Key) then raise Checked_Error with Errors.Set ("Expression variable '" & Key & "' is unknown (" & Key_Variables_Image (Variables) & ")") else Variables (Key)); -------------- -- Is_Valid -- -------------- function Is_Valid (This : Variable; Value : String) return Boolean is (if not Variable_Values.Contains (Key (This)) then raise Checked_Error with Errors.Set ("Expression variable '" & Key (This) & "' is unknown (" & Key_Variables_Image (Variables) & ")") else Variable_Values (Key (This)).Is_Valid (Value)); ----------------------- -- Register_Variable -- ----------------------- procedure Register (Var_Key : String; Var_Name : String; Var_Values : Values'Class) is begin Variables.Insert (Var_Key, Variable'(Key => +Var_Key, Name => +Var_Name)); Variable_Values.Insert (Var_Key, Var_Values); end Register; --------------- -- Satisfies -- --------------- function Satisfies (Property : Properties.Property'Class; Var_Key : String; Value : String) return Boolean is (Property.Key = Var_Key and then Variables.Contains (Var_Key) and then From (Var_Key).Is_Valid (Value) and then TOML_Adapters.Tomify (Property.Image) = TOML_Adapters.Tomify (Value)); end Alire.Expressions; alire-1.2.1/src/alire/alire-expressions.ads000066400000000000000000000053461430264165500206550ustar00rootroot00000000000000with Alire.Properties; with Alire.TOML_Keys; package Alire.Expressions with Preelaborate is -- Support for the distinct enums/types that may appear in a case -- expression. This was originally done with proper Ada enumerations, for -- the old Ada index that exposed these types to users. Now, by using these -- pseudotypes we may remove all the nightmarish instantiations and have a -- much simpler to maintain/understand code base. type Variable is tagged private; -- A Variable is a set of values belonging to a category. E.g., -- Operating_System is formed by (Linux, Windows. MacOS). Currently, only -- enums are supported, but to allow cases on configuration variables -- other types may be added in the future. function From (Key : String) return Variable; -- Retrieve a previously declared type by its TOML key function Is_Valid (This : Variable; Value : String) return Boolean; -- Says if Value is among the values in This function Key (This : Variable) return String; -- The key that is used in TOML files for this variable function Name (This : Variable) return String; -- The Ada-like name of this variable function Satisfies (Property : Properties.Property'Class; Var_Key : String; Value : String) return Boolean with Pre => Value /= TOML_Keys.Case_Others and then Value /= "others"; -- Say if a property is satisfied by the value, which must match the -- Variable and property type (keys must match). Doesn't accept defaults. private -- Internally, the Variable is registered in a private storage (see -- Variables map in body), whereas the Variable type simply stores the -- key to access its declared values. This way it isn't onerous to store -- instances in every case node in the index. Incidentally, this makes the -- whole thing thread-unsafe. type Variable is tagged record Key : UString; Name : UString; end record; ------------ -- Values -- ------------ type Values is interface; -- Stores the valid representations for a Variable function Is_Valid (V : Values; Image : String) return Boolean is abstract; -- Say if a value, given as its string image, matches a value of a type procedure Register (Var_Key : String; Var_Name : String; Var_Values : Values'Class); -- Makes Alire aware of the existence of a variable usable in expressions --------- -- Key -- --------- function Key (This : Variable) return String is (+This.Key); ---------- -- Name -- ---------- function Name (This : Variable) return String is (+This.Name); end Alire.Expressions; alire-1.2.1/src/alire/alire-externals-from_output.adb000066400000000000000000000120031430264165500226240ustar00rootroot00000000000000with AAA.Strings; use AAA.Strings; with Alire.Directories; with Alire.Index; with Alire.Origins; with Alire.OS_Lib.Subprocess; with Alire.Paths; with Alire.Releases; with Alire.TOML_Keys; with Semantic_Versioning; with TOML; package body Alire.Externals.From_Output is ------------ -- Detect -- ------------ overriding function Detect (This : External; Name : Crate_Name) return Releases.Containers.Release_Set is use Directories.Operators; Location : GNAT.OS_Lib.String_Access := GNAT.OS_Lib.Locate_Exec_On_Path (This.Command.First_Element); begin if Location in null then Trace.Debug ("External not detected because executable is not in PATH: " & This.Command.First_Element); return (Releases.Containers.Release_Sets.Empty_Set with null record); elsif Contains (Location.all, Paths.Working_Folder_Inside_Root / Paths.Cache_Folder_Inside_Working_Folder / Paths.Deps_Folder_Inside_Cache_Folder) then Trace.Debug ("External skipped because executable is deployed by Alire: " & Location.all); return (Releases.Containers.Release_Sets.Empty_Set with null record); else GNAT.OS_Lib.Free (Location); end if; declare use GNAT.Regpat; Matches : Match_Array (1 .. Match_Count'Last); Lines : AAA.Strings.Vector; Status : constant Integer := OS_Lib.Subprocess.Unchecked_Spawn_And_Capture (This.Command.First_Element, This.Command.Tail, Lines); Output : constant String := Lines.Flatten ("" & ASCII.LF); -- ASCII.LF is used by Regpat for new lines begin if Status /= 0 then Trace.Debug ("External command [" & This.Command.First_Element & "] erred with code: " & AAA.Strings.Trim (Status'Image)); return Releases.Containers.Empty_Release_Set; end if; return Releases : Alire.Releases.Containers.Release_Set do Trace.Debug ("Looking for external in version string: " & Output); Match (This.Regexp, Output, Matches); for I in Matches'Range loop if Matches (I) /= No_Match then declare Version : constant String := Output (Matches (I).First .. Matches (I).Last); Path : constant Any_Path := OS_Lib.Subprocess.Locate_In_Path (This.Command.First_Element); begin Trace.Debug ("Identified external from version: " & Version); Releases.Insert (Index.Crate (Name).Base .Retagging (Semantic_Versioning.Parse (Version)) .Providing (This.Provides) .Replacing (Origins.New_External ("path " & Path)) .Replacing (Notes => "Detected at " -- length is 12 & Shorten (String (Path), Max_Description_Length - 12))); end; end if; end loop; end return; end; end Detect; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return External is Regexp : constant String := From.Checked_Pop (TOML_Keys.Version_Regexp, TOML.TOML_String).As_String; use GNAT.Regpat; begin From.Assert_Key (TOML_Keys.Version_Cmd, TOML.TOML_Array); if From.Unwrap.Get (TOML_Keys.Version_Cmd).Length = 0 then From.Checked_Error ("version command cannot be empty"); end if; return This : External do This.Regstr := +Regexp; This.Command := TOML_Adapters.To_Vector (From.Checked_Pop (TOML_Keys.Version_Cmd, TOML.TOML_Array)); Compile (This.Regexp, Regexp, Single_Line + Multiple_Lines); Trace.Debug ("Loaded external with regexp: " & Regexp); exception when E : GNAT.Regpat.Expression_Error => Log_Exception (E); From.Checked_Error ("invalid regular expression: " & Regexp); end return; end From_TOML; ----------- -- Image -- ----------- overriding function Image (This : External) return String is (This.Command.Flatten); ------------ -- Detail -- ------------ overriding function Detail (This : External; Unused_Distro : Platforms.Distributions) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector.Append (+This.Regstr)); end Alire.Externals.From_Output; alire-1.2.1/src/alire/alire-externals-from_output.ads000066400000000000000000000023401430264165500226500ustar00rootroot00000000000000private with GNAT.Regpat; package Alire.Externals.From_Output is -- This kind of external runs a command known to provide the tool version, -- which is then extracted with a regular expression. type External is new Externals.External with private; overriding function Detect (This : External; Name : Crate_Name) return Releases.Containers.Release_Set; overriding function Image (This : External) return String; overriding function Detail (This : External; Unused_Distro : Platforms.Distributions) return AAA.Strings.Vector; overriding function Kind (This : External) return String is ("Executable"); function From_TOML (From : TOML_Adapters.Key_Queue) return External; private use type GNAT.Regpat.Program_Size; type External is new Externals.External with record Command : AAA.Strings.Vector; Regexp : GNAT.Regpat.Pattern_Matcher (GNAT.Regpat.Max_Program_Size - 1); -- There's a off-by-one bug when using Max_Program_Size that results in -- freezes/storage errors. Regstr : UString; -- Original regexp for Detail output end record; end Alire.Externals.From_Output; alire-1.2.1/src/alire/alire-externals-from_system.adb000066400000000000000000000140231430264165500226140ustar00rootroot00000000000000with Alire.Conditional_Trees.TOML_Load; with Alire.Index; with Alire.Origins.Deployers.System; with Alire.Platforms.Current; with Alire.Properties.Platform; with Alire.Releases; with Alire.Root; with Alire.TOML_Adapters; package body Alire.Externals.From_System is ------------ -- Detect -- ------------ overriding function Detect (This : External; Name : Crate_Name) return Releases.Containers.Release_Set is package System renames Origins.Deployers.System; begin -- No need to look for anything if the distro is unknown: if not Platforms.Current.Distribution_Is_Known then Trace.Detail ("Cannot look for system packages for crate " & (+Name) & " in unknown distribution"); return (Releases.Containers.Release_Sets.Empty_Set with null record); end if; Trace.Debug ("Looking for system packages that provide crate: " & (+Name)); return Releases : Alire.Releases.Containers.Release_Set do declare Origin : constant Conditional_Packages.Tree := This.Origin.Evaluate (Root.Platform_Properties); begin if Origin.Is_Empty then Trace.Debug ("No system packages for current platform"); else for Candidate of Origin.Value.Packages loop Trace.Detail ("Looking for system package: " & Candidate); declare Detector : constant System.Deployer'Class := System.Platform_Deployer (Candidate); Result : constant System.Version_Outcomes.Outcome := Detector.Detect; begin if Result.Success then Trace.Detail ("Success with system package: " & Candidate); Releases.Insert (Index.Crate (Name).Base .Retagging (Result.Value) .Providing (This.Provides) .Replacing (Origins.New_System (Candidate)) .Replacing (Notes => "Provided by system package: " & Candidate)); end if; end; end loop; end if; end; end return; end Detect; ---------------------- -- From_TOML_Static -- ---------------------- -- Loads a simple origin = [] origin, for reuse in the dynamic expr loader function From_TOML_Static (From : TOML_Adapters.Key_Queue) return Conditional_Packages.Tree is ---------------- -- From_Array -- ---------------- function From_Array (Values : TOML.TOML_Value) return Package_Vector is (Packages => TOML_Adapters.To_Vector (Values)); Value : TOML.TOML_Value; begin if not From.Pop (TOML_Keys.Origin, Value) then From.Checked_Error ("mandatory origin missing"); elsif Value.Kind in TOML.TOML_Array then -- List of possible packages return Conditional_Packages.New_Value (From_Array (Value)); else From.Checked_Error ("origin: expected array of candidate packages"); end if; end From_TOML_Static; --------------- -- From_TOML -- --------------- package Loader is new Conditional_Packages.TOML_Load; function From_TOML (From : TOML_Adapters.Key_Queue) return External is begin return (Externals.External with Origin => Loader.Load (From => -- We detach the 'origin' entry by itself to avoid the -- expression parser to complain about too many entries. From.Descend (Key => TOML_Keys.Origin, Value => From.Pop (TOML_Keys.Origin), Context => TOML_Keys.Origin), Loader => From_TOML_Static'Access, Resolve => True, Strict => False)); end From_TOML; ----------- -- Image -- ----------- overriding function Image (This : External) return String is Candidates : Natural := 0; begin for Packages of This.Origin.As_List loop Candidates := Candidates + Natural (Packages.Packages.Length); end loop; return AAA.Strings.Trim (Candidates'Image) & (if Candidates = 1 then " candidate system package" else " candidate system packages"); end Image; ------------ -- Detail -- ------------ overriding function Detail (This : External; Distro : Platforms.Distributions) return AAA.Strings.Vector is Result : AAA.Strings.Vector; use Alire.Properties; use type Platforms.Distributions; begin for Concrete_Distro in Platforms.Known_Distributions loop -- We show either the requested Distro only, or all distros, which is -- signaled by Distro = Unknown. if Concrete_Distro = Distro or else Distro = Platforms.Distro_Unknown then declare On_Distro : constant Conditional_Packages.Tree := This.Origin.Evaluate (To_Vector (Properties.Platform.Distributions .New_Property (Concrete_Distro))); begin if not On_Distro.Is_Empty then Result.Append (TOML_Adapters.Adafy (Concrete_Distro'Image) & ": " & On_Distro.Image_One_Line); end if; end; end if; end loop; Result.Append ("others: unavailable"); return Result; end Detail; ----------- -- Image -- ----------- function Image (This : Package_Vector) return String is (This.Packages.Flatten (", ")); end Alire.Externals.From_System; alire-1.2.1/src/alire/alire-externals-from_system.ads000066400000000000000000000037461430264165500226470ustar00rootroot00000000000000private with Alire.Conditional_Trees; private with Alire.Interfaces; private with Alire.Platforms; private with Alire.TOML_Keys; private with TOML; package Alire.Externals.From_System is -- A system-provided package, installed via a platform-specific method such -- as apt, yum, etc. that can also inform us about the version. type External is new Externals.External with private; overriding function Detect (This : External; Name : Crate_Name) return Releases.Containers.Release_Set; overriding function Image (This : External) return String; overriding function Detail (This : External; Distro : Platforms.Distributions) return AAA.Strings.Vector; overriding function Kind (This : External) return String is ("System package"); function From_TOML (From : TOML_Adapters.Key_Queue) return External; -- From must point to the table with the keys that describe the external. private -- To reuse the conditional expressions parser we need a bit of boilerplate type Package_Vector is new Interfaces.Classifiable and Interfaces.Tomifiable and Interfaces.Yamlable with record Packages : AAA.Strings.Vector; end record; overriding function Key (This : Package_Vector) return String is (TOML_Keys.Origin); overriding function To_TOML (This : Package_Vector) return TOML.TOML_Value is (raise Unimplemented); -- Not needed overriding function To_YAML (This : Package_Vector) return String is (raise Unimplemented); -- Not needed function Image (This : Package_Vector) return String; package Conditional_Packages is new Conditional_Trees (Package_Vector, Image); type Candidates is array (Platforms.Known_Distributions) of Package_Vector; type External is new Externals.External with record Origin : Conditional_Packages.Tree; end record; end Alire.Externals.From_System; alire-1.2.1/src/alire/alire-externals-lists.adb000066400000000000000000000053501430264165500214060ustar00rootroot00000000000000with Alire.Properties.Labeled; with Alire.TOML_Keys; with Simple_Logging; package body Alire.Externals.Lists is ------------ -- Detect -- ------------ function Detect (This : List; Name : Crate_Name; Env : Properties.Vector) return Releases.Containers.Release_Set is begin -- Avoid the log message if there's nothing to detect if This.Is_Empty then return (Releases.Containers.Release_Sets.Empty_Set with null record); end if; declare Busy : Simple_Logging.Ongoing := Simple_Logging.Activity ("Looking for external crate: " & (+Name)); begin return Detected : Releases.Containers.Release_Set do for External of This loop if External.Available.Is_Available (Env) then Trace.Debug ("Attempting detection of available external: " & (+Name)); Detected.Union (External.Detect (Name)); else Trace.Debug ("Skipping detection of unavailable external: " & (+Name)); end if; Busy.Step; end loop; end return; end; end Detect; ----------- -- Hints -- ----------- function Hints (This : List; Name : Crate_Name; Env : Properties.Vector := Properties.No_Properties) return AAA.Strings.Vector is Hints : Properties.Vector; use type Properties.Vector; begin for External of This loop if Env.Is_Empty then -- Look for all hints, ignoring environment Hints := Hints and Properties.Filter (Conditional.Enumerate (External.Properties), TOML_Keys.Hint); elsif External.Available.Is_Available (Env) and then External.Detect (Name).Is_Empty then -- Look for externals in the platform that don't detect -- anything, so their hinting message is useful. Hints := Hints and Properties.Filter (Conditional.Enumerate (External.Properties.Evaluate (Env)), TOML_Keys.Hint); end if; end loop; return Result : AAA.Strings.Vector do for Hint of Hints loop Result.Append (Properties.Labeled.Label'Class (Hint).Value); end loop; end return; end Hints; ------------- -- To_List -- ------------- function To_List (This : External'Class) return List is begin return L : List do L.Append (This); end return; end To_List; end Alire.Externals.Lists; alire-1.2.1/src/alire/alire-externals-lists.ads000066400000000000000000000021251430264165500214240ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; with Alire.Properties; package Alire.Externals.Lists is -- Since a crate may have different externals, they'll need aggregation package Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (External'Class); type List is new Lists.List with null record; function Detect (This : List; Name : Crate_Name; Env : Properties.Vector) return Releases.Containers.Release_Set; -- Goes over the externals defined in List and, when Available, performs -- their Detect call. function Hints (This : List; Name : Crate_Name; Env : Properties.Vector := Properties.No_Properties) return AAA.Strings.Vector; -- Given an external list, evaluate all that apply under Env platform -- properties and, for those that fail to detect, return their hint -- message if any. If Env is empty, return all hints unconditionally. function To_List (This : External'Class) return List; end Alire.Externals.Lists; alire-1.2.1/src/alire/alire-externals-unindexed.adb000066400000000000000000000012401430264165500222250ustar00rootroot00000000000000with Alire.Externals.Lists; package body Alire.Externals.Unindexed is ------------ -- Detail -- ------------ overriding function Detail (This : External; Unused_Distro : Platforms.Distributions) return AAA.Strings.Vector is Result : AAA.Strings.Vector; begin for Hint of Lists.To_List (This).Hints (+"unused_name") loop Result.Append (Hint); end loop; if Result.Is_Empty then return AAA.Strings.Empty_Vector.Append ("Must be provided by the user"); else return Result; end if; end Detail; end Alire.Externals.Unindexed; alire-1.2.1/src/alire/alire-externals-unindexed.ads000066400000000000000000000015251430264165500222540ustar00rootroot00000000000000package Alire.Externals.Unindexed is -- A do-nothing external that is used to signal a known but unavailable -- crate. type External is new Externals.External with null record; overriding function Detect (This : External; Unused_Name : Crate_Name) return Releases.Containers.Release_Set is (Releases.Containers.Release_Sets.Empty_Set with null record); overriding function Image (This : External) return String is ("Externally provided"); overriding function Detail (This : External; Unused_Distro : Platforms.Distributions) return AAA.Strings.Vector; -- Return all custom hints or else a default message overriding function Kind (This : External) return String is ("Hint"); end Alire.Externals.Unindexed; alire-1.2.1/src/alire/alire-externals.adb000066400000000000000000000103361430264165500202520ustar00rootroot00000000000000with AAA.Enum_Tools; with Alire.Crates; with Alire.Externals.From_Output; with Alire.Externals.From_System; with Alire.Externals.Unindexed; with Alire.Provides; with Alire.TOML_Keys; with Alire.TOML_Load; with Alire.User_Pins.Maps; with TOML; package body Alire.Externals is --------------- -- Available -- --------------- function Available (This : External'Class) return Conditional.Availability is (This.Available); --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue; Strict : Boolean) return External'Class is --------------- -- From_TOML -- --------------- function From_TOML (Kind : Kinds) return External'Class is (case Kind is when Hint => Unindexed.External' (External with null record), when System => From_System.From_TOML (From), when Version_Output => From_Output.From_TOML (From)); ------------------- -- Load_Provides -- ------------------- -- Pops and loads the provides = "crate" special external case procedure Load_Provides (This : in out External'Class; From : TOML_Adapters.Key_Queue) is use TOML; begin This.Provides.Insert (To_Name (From.Checked_Pop (TOML_Keys.Provides, TOML_String).As_String)); end Load_Provides; Kind : TOML.TOML_Value; OK : constant Boolean := From.Pop (TOML_Keys.External_Kind, Kind); -------------- -- Validate -- -------------- procedure Validate is function Is_Valid is new AAA.Enum_Tools.Is_Valid (Kinds); begin if not OK then From.Checked_Error ("missing external kind field"); end if; if Kind.Kind not in TOML.TOML_String then From.Checked_Error ("external kind must be a string, but got a " & Kind.Kind'Img); elsif not Is_Valid (TOML_Adapters.Adafy (Kind.As_String)) then From.Checked_Error ("external kind is invalid: " & Kind.As_String); end if; end Validate; -- These cannot appear in externals: Unused_Deps : Conditional.Dependencies; Unused_Equiv : Provides.Equivalences; Unused_Pins : User_Pins.Maps.Map; begin -- Check TOML types Validate; -- Load specific external part return Ext : External'Class := From_TOML (Kinds'Value (TOML_Adapters.Adafy (Kind.As_String))) do -- Deal with the special provides of an external, which cannot have -- a version as it is yet unknown. if Ext not in Unindexed.External'Class and then From.Contains (TOML_Keys.Provides) then Load_Provides (Ext, From); end if; -- Load common external fields TOML_Load.Load_Crate_Section (Strict => Strict, Section => Crates.External_Private_Section, From => From, Props => Ext.Properties, Deps => Unused_Deps, Equiv => Unused_Equiv, Forbids => Unused_Deps, Pins => Unused_Pins, Avail => Ext.Available); Assert (Unused_Deps.Is_Empty, "Unexpected dependencies in external definition"); Assert (Unused_Pins.Is_Empty, "Unexpected pins in external definition"); From.Report_Extra_Keys; -- Table must be exhausted at this point end return; exception when Checked_Error => raise; when E : others => Log_Exception (E); From.Checked_Error ("invalid external description (see details with -d)"); end From_TOML; ----------------- -- On_Platform -- ----------------- function On_Platform (This : External'Class; Env : Properties.Vector) return External'Class is begin return Ext : External'Class := This do Ext.Available := Ext.Available.Evaluate (Env); Ext.Properties := Ext.Properties.Evaluate (Env); end return; end On_Platform; end Alire.Externals; alire-1.2.1/src/alire/alire-externals.ads000066400000000000000000000063261430264165500202770ustar00rootroot00000000000000with AAA.Strings; with Alire.Conditional; with Alire.Containers; with Alire.Platforms; with Alire.Properties; with Alire.Releases.Containers; with Alire.TOML_Adapters; package Alire.Externals is -- External releases do not have an actual version until detected at -- runtime. Hence, they cannot be catalogued in the index with a known -- version. Instead, they're listed under the 'external' array. type External is abstract tagged private; function Detect (This : External; Name : Crate_Name) return Releases.Containers.Release_Set is abstract; -- Perform detection and return all matching releases. Empty set must be -- returned if nothing can be detected. Checked_Error must be raised if -- detection cannot be performed normally. Caching results is allowed. -- Name is a convenience so Releases can be created without requiring the -- full containing crate reference. function Image (This : External) return String is abstract; -- Short one-liner textual description function Detail (This : External; Distro : Platforms.Distributions) return AAA.Strings.Vector is abstract; -- Detailed longer textual description of specifics. If Distro /= Unknown, -- show only the relevant distro information. function Kind (This : External) return String is abstract; -- Keyword for use in `alr show` and similar displays of information ------------------------- -- Classwide helpers -- ------------------------- function Available (This : External'Class) return Conditional.Availability; type Kinds is (Hint, -- A placeholder for a knowingly-unavailable crate, that -- will hopefully be added in the future. System, -- A installed system package, via apt, yum, etc. Version_Output -- A external that detects the availability of a tool by -- running it to detect its version. ); -- These kinds are used during TOML loading, and exposed in the spec for -- documentation purposes only. function From_TOML (From : TOML_Adapters.Key_Queue; Strict : Boolean) return External'Class; function On_Platform (This : External'Class; Env : Properties.Vector) return External'Class; -- Evaluate Properties and Available fields under the given environment function Equivalences (This : External'Class) return Containers.Crate_Name_Sets.Set; -- An external may have a "provides" for another crate, always matching -- the same version. Used ATM for GNAT compilers, including system ones, -- to provide the "gnat" crate. private type External is abstract tagged record Properties : Conditional.Properties; Provides : Containers.Crate_Name_Sets.Set; Available : Conditional.Availability; end record; ------------------ -- Equivalences -- ------------------ function Equivalences (This : External'Class) return Containers.Crate_Name_Sets.Set is (This.Provides); end Alire.Externals; alire-1.2.1/src/alire/alire-github.adb000066400000000000000000000061111430264165500175230ustar00rootroot00000000000000with Ada.Exceptions; with Alire.Errors; with Alire.Utils.TTY; with Minirest; package body Alire.GitHub is Base_URL : constant URL := "https://api.github.com"; Header_Rate : constant String := "X-Ratelimit-Remaining"; --------- -- "/" -- --------- function "/" (L, R : String) return String is (L & "/" & R); -------------- -- API_Call -- -------------- function API_Call (Proc : String; Args : Minirest.Parameters := Minirest.No_Arguments) return Minirest.Response is use Minirest; Full_URL : constant String := Base_URL & (if Proc (Proc'First) /= '/' then "/" else "") & Proc; begin return This : constant Response := Minirest.Get (Full_URL, Arguments => Args, Headers => "Accept" = "Application/vnd.github.v3.full+json") do if not This.Succeeded then -- Log info about why the API call failed Trace.Debug ("Failed GitHub request to API: " & Utils.TTY.URL (Full_URL)); Trace.Debug ("Status: " & This.Status_Line); Trace.Debug ("Headers: " & This.Raw_Headers.Flatten ((1 => ASCII.LF))); Trace.Debug ("Contents: " & This.Content.Flatten ((1 => ASCII.LF))); -- Raise if API is rate-limiting to avoid misleading failures if This.Headers.Contains (Header_Rate) and then Integer'Value (This.Headers (Header_Rate)) <= 0 then Raise_Checked_Error ("GitHub API rate limit exceeded, please wait for a while" & " before retrying."); end if; end if; end return; exception when E : Minirest.Rest_Error => Log_Exception (E); Raise_Checked_Error (Errors.Wrap ("Error querying GitHub API", Ada.Exceptions.Exception_Message (E))); end API_Call; ------------------- -- Branch_Exists -- ------------------- function Branch_Exists (User : String := Config.DB.Get (Config.Keys.User_Github_Login, Default => ""); Repo : String := Index.Community_Repo_Name; Branch : String := Index.Community_Branch) return Boolean is (API_Call ("repos" / User / Repo / "branches" / Branch).Succeeded); ----------------- -- Repo_Exists -- ----------------- function Repo_Exists (User : String := Config.DB.Get (Config.Keys.User_Github_Login, Default => ""); Repo : String := Index.Community_Repo_Name) return Boolean is (API_Call ("repos" / User / Repo).Succeeded); ----------------- -- User_Exists -- ----------------- function User_Exists (User : String := Config.DB.Get (Config.Keys.User_Github_Login, Default => "")) return Boolean is (API_Call ("users" / User).Succeeded); end Alire.GitHub; alire-1.2.1/src/alire/alire-github.ads000066400000000000000000000016011430264165500175430ustar00rootroot00000000000000with Alire.Config; with Alire.Index; package Alire.GitHub is function Branch_Exists (User : String := Config.DB.Get (Config.Keys.User_Github_Login, Default => ""); Repo : String := Index.Community_Repo_Name; Branch : String := Index.Community_Branch) return Boolean; -- Check that a branch exists in a user's repository function Repo_Exists (User : String := Config.DB.Get (Config.Keys.User_Github_Login, Default => ""); Repo : String := Index.Community_Repo_Name) return Boolean; -- Check that a user has a certain public repo function User_Exists (User : String := Config.DB.Get (Config.Keys.User_Github_Login, Default => "")) return Boolean; -- Check that a user exists in GitHub end Alire.GitHub; alire-1.2.1/src/alire/alire-gpr.adb000066400000000000000000000027561430264165500170440ustar00rootroot00000000000000package body Alire.GPR is ----------- -- Image -- ----------- function Image (V : Variable) return String is function Listify (Vals : Value_Vector) return String; function Listify (Vals : Value_Vector) return String is Head : constant String := Vals.First_Element; Tail : Value_Vector := Vals; begin Tail.Delete_First; return Head & (if Tail.Is_Empty then "" else " | " & Listify (Tail)); end Listify; begin case V.Kind is when Free_String => return V.Name & " := "; when Enumeration => return V.Name & " := " & Listify (V.Values); when External => return V.Name & " := " & V.Value.First_Element; end case; end Image; ------------------ -- Add_Argument -- ------------------ procedure Add_Argument (S : in out Scenario; Var : String; Val : String) is begin S.Append (Var); S.Append (Val); end Add_Argument; --------------------- -- As_Command_Line -- --------------------- function As_Command_Line (S : Scenario) return AAA.Strings.Vector is use AAA.Strings; Result : Vector := Empty_Vector; Cdr : Scenario := S; begin while not Cdr.Is_Empty loop Result.Append (String'("-X" & Cdr (1) & "=" & Cdr (2))); Cdr.Delete_First; Cdr.Delete_First; end loop; return Result; end As_Command_Line; end Alire.GPR; alire-1.2.1/src/alire/alire-gpr.ads000066400000000000000000000063261430264165500170620ustar00rootroot00000000000000with AAA.Strings; package Alire.GPR with Preelaborate is type Variable_Kinds is (Enumeration, Free_String, External); -- Enumeration: Name + all possible values -- Free_String: Name without value -- External : Name=Value type Variable (<>) is tagged private; function Kind (V : Variable) return Variable_Kinds; function Name (V : Variable) return String; function Image (V : Variable) return String; function Free_Variable (Name : String) return Variable; subtype Value is String; type Value_Vector is new AAA.Strings.Vector with null record; function Enum_Variable (Name : String; Values : Value_Vector'Class) return Variable; -- Used to represent a Typed enum with its possible values: -- Name = Value1 | Value2 ... function External_Value (Name : String; Value : String) return Variable; -- Used to represent a pair Name=Value function Values (V : Variable) return Value_Vector'Class with Pre => V.Kind = Enumeration; function External_Value (V : Variable) return String with Pre => V.Kind = External; function "or" (L, R : Value) return Value_Vector; function "or" (L : Value_Vector; R : Value) return Value_Vector; -- A collection of Var=Arg conform a scenario: -- These are used to store -X command-line arguments type Scenario is tagged private; Empty_Scenario : constant Scenario; procedure Add_Argument (S : in out Scenario; Var : String; Val : String); function As_Command_Line (S : Scenario) return AAA.Strings.Vector; -- -Xvar1=val -Xvar2=val ... function Is_Empty (S : Scenario) return Boolean; private type Variable (Kind : Variable_Kinds; Name_Len : Positive) is tagged record Name : String (1 .. Name_Len); case Kind is when Enumeration => Values : Value_Vector; when External => Value : Value_Vector; -- Only one element when Free_String => null; end case; end record; function Kind (V : Variable) return Variable_Kinds is (V.Kind); function Name (V : Variable) return String is (V.Name); function Free_Variable (Name : String) return Variable is (Free_String, Name'Length, Name); function Enum_Variable (Name : String; Values : Value_Vector'Class) return Variable is (Enumeration, Name'Length, Name, Value_Vector (Values)); function External_Value (Name : String; Value : String) return Variable is (External, Name'Length, Name, To_Vector (Value, 1)); function Values (V : Variable) return Value_Vector'Class is (V.Values); function External_Value (V : Variable) return String is (V.Value.First_Element); function "or" (L, R : Value) return Value_Vector is (L & R); function "or" (L : Value_Vector; R : Value) return Value_Vector is (L & R); type Scenario is new AAA.Strings.Vector with null record; overriding function Is_Empty (S : Scenario) return Boolean is (AAA.Strings.Vector (S).Is_Empty); Empty_Scenario : constant Scenario := (AAA.Strings.Vectors.Empty_Vector with null record); end Alire.GPR; alire-1.2.1/src/alire/alire-hashes-common.adb000066400000000000000000000015551430264165500210110ustar00rootroot00000000000000with Ada.Streams.Stream_IO; package body Alire.Hashes.Common is --------------- -- Hash_File -- --------------- function Hash_File (Path : File_Path) return Any_Hash is use Ada.Streams; use Ada.Streams.Stream_IO; Ctxt : Context; File : File_Type; Buff : Stream_Element_Array (1 .. 1024 * 1024); -- 1MiB Last : Stream_Element_Offset; begin Open (File, In_File, Path); while not End_Of_File (File) loop Read (File, Buff, Last); Update (Ctxt, Buff (Buff'First .. Last)); end loop; Close (File); return New_Hash (Kind, Any_Digest (Digest (Ctxt))); exception when others => if Is_Open (File) then Close (File); end if; raise; end Hash_File; begin Hashes.Hash_Functions (Kind) := Hash_File'Access; end Alire.Hashes.Common; alire-1.2.1/src/alire/alire-hashes-common.ads000066400000000000000000000017601430264165500210300ustar00rootroot00000000000000with Ada.Streams; generic Kind : Kinds; -- The Kind to be computed. -- Following types are provided by GNAT.Secure_Hashes.H. Since that is an -- internal unit, we extract here the needed types/subprograms instead of -- getting a package formal. type Context is private; with procedure Update (C : in out Context; Input : Ada.Streams.Stream_Element_Array) is <>; with function Digest (C : Context) return String is <>; package Alire.Hashes.Common is function Hash_File (Path : File_Path) return Any_Hash; -- This function does not need to be visible (it is not used directly), but -- hiding it in the body results in the following error in FSF compilers: -- -- Bind -- [gprbind] alr-main.bexch -- [Ada] alr-main.ali -- -- raised SYSTEM.ASSERTIONS.ASSERT_FAILURE : binde.adb:1117 -- gprbind: invocation of gnatbind failed -- gprbuild: unable to bind alr-main.adb end Alire.Hashes.Common; alire-1.2.1/src/alire/alire-hashes-sha256_impl.ads000066400000000000000000000003501430264165500215630ustar00rootroot00000000000000with Alire.Hashes.Common; with GNAT.SHA256; package Alire.Hashes.SHA256_Impl is new Alire.Hashes.Common (Kind => SHA256, Context => GNAT.SHA256.Context, Update => GNAT.SHA256.Update, Digest => GNAT.SHA256.Digest); alire-1.2.1/src/alire/alire-hashes-sha512_impl.ads000066400000000000000000000003501430264165500215560ustar00rootroot00000000000000with Alire.Hashes.Common; with GNAT.SHA512; package Alire.Hashes.SHA512_Impl is new Alire.Hashes.Common (Kind => SHA512, Context => GNAT.SHA512.Context, Update => GNAT.SHA512.Update, Digest => GNAT.SHA512.Digest); alire-1.2.1/src/alire/alire-hashes.adb000066400000000000000000000005561430264165500175230ustar00rootroot00000000000000package body Alire.Hashes is ------------ -- Digest -- ------------ function Digest (Hash : Any_Hash) return Any_Digest is begin return Any_Digest (Tail (String (Hash), ':')); exception when E : others => Log_Exception (E); Raise_Checked_Error ("Malformed hash: " & String (Hash)); end Digest; end Alire.Hashes; alire-1.2.1/src/alire/alire-hashes.ads000066400000000000000000000065431430264165500175460ustar00rootroot00000000000000with AAA.Strings; use AAA.Strings; package Alire.Hashes with Preelaborate is -- To allow use of various hashes, we expect that any string in the index -- providing a hash has the format: "kind:value" where kind is the hash -- type and value is the actual hash representation emitted by the GNAT.* -- hashing functions. E.g.: "sha1:5c16c1c74ae8236770644b69f2e4cf1ccc88adad" type Kinds is (SHA256, SHA512); -- Recognized hashes that we are able to compute/verify. To add a new kind, -- instance the Alire.Hashes.Common generic and with it in Alire.TOML_Index -- body. Default : constant Kinds := SHA512; -- In the event we introduce several hashes, this default is considered the -- strongest/preferred one for any new hashes to be generated going forward type Any_Digest is new String with Dynamic_Predicate => (for all Char of Any_Digest => Char in 'a' .. 'f' | '0' .. '9'); -- Just the actual hash part, in hexadecimal encoding. type Any_Hash is new String with Dynamic_Predicate => Is_Well_Formed (String (Any_Hash)); -- A string with "kind:digest" format. function New_Hash (Kind : Kinds; Digest : Any_Digest) return Any_Hash; function Digest (Hash : Any_Hash) return Any_Digest; -- Return the actual fingerprint without the kind prefix. function Hash_File (Kind : Kinds; Path : File_Path) return Any_Hash; -- Compute a particular hash kind. May raise usual file exceptions. function Is_Known (Kind_Img : String) return Boolean; -- Check if a string is one of our understood hash types. function Is_Well_Formed (Hash_Img : String) return Boolean; -- Check if a string follows proper syntax ("kind:digest"). function Kind (Hash : Any_Hash) return Kinds; -- Given a well-formed Hash, extract its typed kind. private -------------------- -- Hash_Functions -- -------------------- -- The following function array is initialized by each instance of a -- known hash in child packages. Hash_Functions : array (Kinds) of access function (File : File_Path) return Any_Hash; --------------- -- Hash_File -- --------------- function Hash_File (Kind : Kinds; Path : File_Path) return Any_Hash is (Hash_Functions (Kind) (Path)); -- Dispatch to a particular implementation -------------- -- Is_Known -- -------------- function Is_Known (Kind_Img : String) return Boolean is (for some Kind in Kinds => To_Lower_Case (Kind'Img) = To_Lower_Case (Kind_Img)); -------------------- -- Is_Well_Formed -- -------------------- pragma Warnings (Off, "conjunct"); -- GNAT 12.1 says: -- warning: unused variable "Char" in conjunct [-gnatw.t] -- warning: consider extracting conjunct from quantified expression function Is_Well_Formed (Hash_Img : String) return Boolean is (for some Char of Hash_Img => Char = ':' and then Is_Known (Head (Hash_Img, ':'))); pragma Warnings (On); ---------- -- Kind -- ---------- function Kind (Hash : Any_Hash) return Kinds is (Kinds'Value (Head (String (Hash), ':'))); -------------- -- New_Hash -- -------------- function New_Hash (Kind : Kinds; Digest : Any_Digest) return Any_Hash is (Any_Hash (String'(To_Lower_Case (Kind'Img) & ":" & String (Digest)))); end Alire.Hashes; alire-1.2.1/src/alire/alire-index-search.adb000066400000000000000000000020471430264165500206170ustar00rootroot00000000000000with Alire.Utils.Tables; package body Alire.Index.Search is use AAA.Strings; ------------------ -- Print_Crates -- ------------------ procedure Print_Crates (Substring : String := "") is Table : Utils.Tables.Table; Found : Natural := 0; Lookup : constant String := AAA.Strings.To_Lower_Case (Substring); Busy : Simple_Logging.Ongoing := Simple_Logging.Activity ("Searching"); begin for Crate of Alire.Index.All_Crates.all loop if Lookup = "" or else Contains (To_Lower_Case (+Crate.Name), Lookup) or else Contains (To_Lower_Case (Crate.Description), Lookup) then Found := Found + 1; Table.New_Row; Table.Append (Crate.TTY_Name); Table.Append (Crate.TTY_Description); end if; Busy.Step; end loop; if Found = 0 then Trace.Always ("No hits"); else Table.Print (Always, Separator => " "); end if; end Print_Crates; end Alire.Index.Search; alire-1.2.1/src/alire/alire-index-search.ads000066400000000000000000000004331430264165500206350ustar00rootroot00000000000000package Alire.Index.Search is -- Functions for generating listings of crates/releases procedure Print_Crates (Substring : String := ""); -- Print a list of crates containing Substring in their name/description, -- or all of them when empty. end Alire.Index.Search; alire-1.2.1/src/alire/alire-index.adb000066400000000000000000000213761430264165500173620ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; with Ada.Containers.Indefinite_Ordered_Sets; with Alire.Containers; with Alire.Utils.TTY; package body Alire.Index is package Release_Set_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Releases.Containers.Release_Set, "<", Releases.Containers."="); subtype Release_Alias_Map is Release_Set_Maps.Map; package External_Alias_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Containers.Crate_Name_Sets.Set, "<", Containers.Crate_Name_Sets."="); subtype External_Alias_Map is External_Alias_Maps.Map; use all type Semantic_Versioning.Version; Contents : aliased Alire.Crates.Containers.Maps.Map; -- Regular mapping from crate name to its releases Aliases : Release_Alias_Map; -- Mapping from crate name to any release that satisfies it. Currently, -- releases are duplicated in memory. These two collections could be made -- to share releases via some indirection or pointers. External_Aliases : External_Alias_Map; -- For external crates that provide another crate, we need to be aware -- when external detection is requested. This mapping goes in the direction -- Provided -> Providers. --------- -- Add -- --------- procedure Add (Crate : Crates.Crate; Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing) is begin if Exists (Crate.Name) then declare Old : Crates.Crate := Contents (Crate.Name); begin case Policy is when Policies.Merge_Priorizing_Existing => for Release of Crate.Releases loop if Old.Contains (Release.Version) then Trace.Debug ("Not registering release already indexed: " & Release.Milestone.Image); else Old.Add (Release); end if; end loop; end case; Old.Merge_Externals (Crate, Policy); Contents.Include (Crate.Name, Old); end; else Contents.Insert (Crate.Name, Crate); end if; end Add; --------- -- Add -- --------- procedure Add (Release : Releases.Release; Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing) is ----------------- -- Add_Aliases -- ----------------- procedure Add_Aliases is begin for Mil of Release.Provides loop declare Crate : Releases.Containers.Release_Set := (if Aliases.Contains (Mil.Crate) then Aliases (Mil.Crate) else Releases.Containers.Empty_Release_Set); begin Crate.Include (Release); Aliases.Include (Mil.Crate, Crate); end; end loop; end Add_Aliases; Crate : Crates.Crate := Crates.New_Crate (Release.Name); begin Crate.Add (Release); Add (Crate, Policy); Add_Aliases; end Add; -------------------------- -- Detect_All_Externals -- -------------------------- procedure Detect_All_Externals (Env : Properties.Vector) is begin Trace.Detail ("Detecting external releases..."); for Crate of Contents loop Detect_Externals (Crate.Name, Env); end loop; end Detect_All_Externals; package Name_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Crate_Name); Already_Detected : Name_Sets.Set; ---------------------- -- Detect_Externals -- ---------------------- procedure Detect_Externals (Name : Crate_Name; Env : Properties.Vector) is begin if Already_Detected.Contains (Name) then Trace.Debug ("Not redoing detection of externals for crate " & (+Name)); elsif not External_Aliases.Contains (Name) then Trace.Debug ("Skipping detection for crate without externals: " & Utils.TTY.Name (Name)); else Already_Detected.Insert (Name); Trace.Debug ("Looking for externals for crate: " & (+Name)); for Provider of External_Aliases (Name) loop Trace.Debug ("Detecting via provider " & Utils.TTY.Name (Provider)); for Release of Contents (Provider).Externals.Detect (Provider, Env) loop Trace.Debug ("Adding external: " & Release.Milestone.Image); Add (Release); end loop; end loop; end if; end Detect_Externals; ---------------- -- All_Crates -- ---------------- function All_Crates return access constant Crates.Containers.Maps.Map is (Contents'Access); ----------- -- Crate -- ----------- function Crate (Name : Crate_Name) return Crates.Crate is (Contents (Name)); ----------------- -- Crate_Count -- ----------------- function Crate_Count return Natural is (Natural (Contents.Length)); ------------ -- Exists -- ------------ function Exists (Name : Crate_Name) return Boolean is (Contents.Contains (Name)); ------------ -- Exists -- ------------ function Exists (Name : Crate_Name; Version : Semantic_Versioning.Version) return Boolean is begin if Exists (Name) then for R of Contents (Name).Releases loop if R.Name = Name and then R.Version = Version then return True; end if; end loop; end if; return False; end Exists; ---------- -- Find -- ---------- function Find (Name : Crate_Name; Version : Semantic_Versioning.Version) return Release is begin for R of Contents (Name).Releases loop if R.Name = Name and then R.Version = Version then return R; end if; end loop; raise Checked_Error with "Requested milestone not in index: " & (+Name) & "=" & Semantic_Versioning.Image (Version); end Find; ------------------- -- Has_Externals -- ------------------- function Has_Externals (Name : Crate_Name) return Boolean is (External_Aliases.Contains (Name)); ----------------------------- -- Register_External_Alias -- ----------------------------- procedure Register_External_Alias (Provider : Crate_Name; Providing : Crate_Name) is begin if External_Aliases.Contains (Providing) then External_Aliases (Providing).Include (Provider); else External_Aliases.Insert (Providing, Containers.Crate_Name_Sets.To_Set (Provider)); end if; end Register_External_Alias; ------------------- -- Release_Count -- ------------------- function Release_Count return Natural is begin return Count : Natural := 0 do for Crate of Contents loop Count := Count + Natural (Crate.Releases.Length); end loop; end return; end Release_Count; ------------------------- -- Releases_Satisfying -- ------------------------- function Releases_Satisfying (Dep : Dependencies.Dependency; Env : Properties.Vector; Use_Equivalences : Boolean := True; Available_Only : Boolean := True; With_Origin : Origins.Kinds_Set := (others => True)) return Releases.Containers.Release_Set is Result : Releases.Containers.Release_Set; begin -- Regular crates if Exists (Dep.Crate) then for Release of Crate (Dep.Crate).Releases loop if With_Origin (Release.Origin.Kind) and then Release.Satisfies (Dep) and then (not Available_Only or else Release.Is_Available (Env)) then Result.Insert (Release); end if; end loop; end if; -- And any aliases via Provides if Use_Equivalences and then Aliases.Contains (Dep.Crate) then for Release of Aliases (Dep.Crate) loop if With_Origin (Release.Origin.Kind) and then Release.Satisfies (Dep) and then (not Available_Only or else Release.Is_Available (Env)) then Result.Include (Release); end if; end loop; end if; return Result; end Releases_Satisfying; end Alire.Index; alire-1.2.1/src/alire/alire-index.ads000066400000000000000000000124431430264165500173760ustar00rootroot00000000000000private with Alire_Early_Elaboration; pragma Unreferenced (Alire_Early_Elaboration); with Alire.Crates.Containers; with Alire.Dependencies; with Alire.Origins; with Alire.Policies; with Alire.Properties; with Alire.Releases.Containers; with Semantic_Versioning.Extended; package Alire.Index is Community_Host : constant String := "https://github.com"; Community_Organization : constant String := "alire-project"; Community_Repo_Name : constant String := "alire-index"; Community_Repo : constant URL := "git+" & Community_Host & "/" & Community_Organization & "/" & Community_Repo_Name; -- Default index installed on first run Community_Name : constant Restricted_Name := "community"; -- We have two sets of branches in the alire-index repo: -- devel-x.x.x and stable-x.x.x -- Stable alr use a stable-x.x.x (might be shared across alr versions, if -- no changes to the index format are necessary). The development versions -- of alr may branch out from the latest stable- to a devel- branch for -- breaking changes. subtype Branch_String is String with Dynamic_Predicate => Branch_String (Branch_String'First) /= '-' and then Branch_String (Branch_String'Last) /= '-' and then (for some C of Branch_String => C = '-'); Community_Branch : constant String := "stable-1.2.1"; -- The branch used for the community index. Must be updated when new index -- features are introduced. Min_Compatible_Version : constant String := "1.1"; -- Update as needed in case of backward-incompatible changes Max_Compatible_Version : constant String := AAA.Strings.Tail (Community_Branch, '-'); -- We store here the indexes we are able to load. As long as we do not -- break back compatibility, we can keep on simply updating the minor value Valid_Versions : constant Semantic_Versioning.Extended.Version_Set := Semantic_Versioning.Extended.Value ("^" & Min_Compatible_Version & " & <=" & Max_Compatible_Version); Version : constant Semantic_Versioning.Version := Semantic_Versioning.New_Version (Max_Compatible_Version); -- The index version understood by alire must match the one in the indexes -- being loaded. Branch_Kind : constant String := AAA.Strings.Head (Community_Branch, "-"); subtype Release is Alire.Releases.Release; ------------------------ -- INDEX POPULATION -- ------------------------ procedure Add (Crate : Crates.Crate; Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing); procedure Add (Release : Releases.Release; Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing); procedure Detect_All_Externals (Env : Properties.Vector); -- Goes over the list of crates and applies external detection, indexing -- any found externals. This has effect only the first time it is called. procedure Detect_Externals (Name : Crate_Name; Env : Properties.Vector); -- Add only the externals of this crate. This has effect only the first -- time it is called for a crate. procedure Register_External_Alias (Provider : Crate_Name; Providing : Crate_Name); -- Register that Provider has external detectors for Providing --------------------- -- BASIC QUERIES -- --------------------- function Crate (Name : Crate_Name) return Crates.Crate with Pre => Exists (Name) or else raise Checked_Error with "Requested crate not in index: " & (+Name); function Exists (Name : Crate_Name) return Boolean; function Exists (Name : Crate_Name; Version : Semantic_Versioning.Version) return Boolean; function Has_Externals (Name : Crate_Name) return Boolean; function Releases_Satisfying (Dep : Dependencies.Dependency; Env : Properties.Vector; Use_Equivalences : Boolean := True; Available_Only : Boolean := True; With_Origin : Origins.Kinds_Set := (others => True)) return Releases.Containers.Release_Set; -- Return all releases in the catalog able to provide this dependency, -- also optionally considering their "provides" equivalences, and also -- optionally including unavailable on the platform. function Find (Name : Crate_Name; Version : Semantic_Versioning.Version) return Release with Pre => Exists (Name, Version) or else raise Checked_Error with "Requested milestone not in index: " & (+Name) & "=" & Semantic_Versioning.Image (Version); -- Counts function Crate_Count return Natural; function Release_Count return Natural; -- Direct access. TODO: instead of storing a hidden global catalog, make it -- a proper type to be returned and manipulated via the functions in this -- package. function All_Crates return access constant Crates.Containers.Maps.Map; end Alire.Index; alire-1.2.1/src/alire/alire-index_on_disk-directory.adb000066400000000000000000000020471430264165500230640ustar00rootroot00000000000000package body Alire.Index_On_Disk.Directory is --------------------- -- Index_Directory -- --------------------- overriding function Index_Directory (This : Index) return String is (This.Origin (This.Origin'First + File_Prefix'Length .. This.Origin'Last)); ----------------- -- New_Handler -- ----------------- overriding function New_Handler (From : URL; Name : Restricted_Name; Parent : Any_Path) return Index is begin return Idx : constant Index := Index'(URL_Len => From'Length, Name_Len => Name'Length, Dir_Len => Parent'Length, Origin => From, Name => Name, Parent => Parent, Priority => <>); end New_Handler; end Alire.Index_On_Disk.Directory; alire-1.2.1/src/alire/alire-index_on_disk-directory.ads000066400000000000000000000020511430264165500231000ustar00rootroot00000000000000package Alire.Index_On_Disk.Directory is -- A local index that is taken from a local filesystem path type Index (<>) is new Index_On_Disk.Index with private; overriding function New_Handler (From : URL; Name : Restricted_Name; Parent : Any_Path) return Index with Pre => AAA.Strings.Has_Prefix (From, "file://") and then Check_Absolute_Path (From (From'First + 7 .. From'Last)); -- file:// + absolute path overriding function Add (This : Index) return Outcome is (Outcome_Success); -- Nothing to do because general checks are done in Features.Index.Add overriding function Index_Directory (This : Index) return String; -- A file:// index is already on disk, so we reuse its path overriding function Update (This : Index) return Outcome is (Outcome_Success); -- Nothing to do since the index is on disk, externally managed private type Index is new Index_On_Disk.Index with null record; end Alire.Index_On_Disk.Directory; alire-1.2.1/src/alire/alire-index_on_disk-git.adb000066400000000000000000000026031430264165500216410ustar00rootroot00000000000000with Alire.VCSs.Git; package body Alire.Index_On_Disk.Git is --------- -- Add -- --------- overriding function Add (This : Index) return Outcome is (VCSs.Git.Handler.Clone (VCSs.Repo_And_Commit (This.Origin), This.Index_Directory)); ----------------- -- New_Handler -- ----------------- overriding function New_Handler (Origin : URL; Name : Restricted_Name; Parent : Any_Path) return Index is begin return Idx : constant Index := Index'(URL_Len => Origin'Length, Name_Len => Name'Length, Dir_Len => Parent'Length, Origin => Origin, Name => Name, Parent => Parent, Priority => <>); end New_Handler; ------------ -- Update -- ------------ overriding function Update (This : Index) return Outcome is begin if VCSs.Git.Handler.Is_Detached (This.Index_Directory) then -- Trying to pull from a detached repo is a failure Trace.Detail ("Skipping update of detached index: " & This.Name); return Outcome_Success; else Trace.Detail ("Updating index: " & This.Name); return VCSs.Git.Handler.Update (This.Index_Directory); end if; end Update; end Alire.Index_On_Disk.Git; alire-1.2.1/src/alire/alire-index_on_disk-git.ads000066400000000000000000000014111430264165500216560ustar00rootroot00000000000000package Alire.Index_On_Disk.Git is -- Local management of remote indexes stored in git repositories type Index is new Index_On_Disk.Index with private; overriding function New_Handler (Origin : URL; Name : Restricted_Name; Parent : Any_Path) return Index with Pre => AAA.Strings.Has_Prefix (Origin, "git+"); overriding function Add (This : Index) return Outcome; -- Clones the index repository overriding function Update (This : Index) return Outcome; -- Pulls the repository, unless it had a specific commit on checkout. -- In that case, silently do nothing and return success. private type Index is new Index_On_Disk.Index with null record; end Alire.Index_On_Disk.Git; alire-1.2.1/src/alire/alire-index_on_disk-loading.adb000066400000000000000000000340241430264165500224750ustar00rootroot00000000000000with Ada.Directories; with Alire.Config.Edit; with Alire.Containers; with Alire.Index; with Alire.Platforms.Current; with Alire.Warnings; with GNAT.OS_Lib; with TOML; with TOML.File_IO; package body Alire.Index_On_Disk.Loading is Loaded : Containers.Crate_Name_Sets.Set; -- Avoid reloading individual crates that have been already loaded. This -- presumes there is no change in the index set in use through a run, which -- is currently impossible to do. As the in-memory index makes a similar -- assumption, this is not making worse the current situation. Cached_Set : Set; -- Likewise, avoid detecting time and again the same indexes -- Forward declarations function Load_Index_Metadata (File : String; Value : out TOML.TOML_Value) return Outcome; --------- -- Add -- --------- function Add (Origin : URL; Name : String; Under : Absolute_Path; Before : String := "") return Outcome is Result : Outcome; Indexes : constant Set := Find_All (Under, Result, Cached => False); ----------------------- -- Adjust_Priorities -- ----------------------- function Adjust_Priorities (Result : out Outcome) return Index_On_Disk.Priorities -- Returns the priority the index has to have, and move down the others is Found : Boolean := False; Priority : Index_On_Disk.Priorities := Index_On_Disk.Default_Priority; begin -- Trivial case if not Before if Before = "" then Result := Outcome_Success; if Indexes.Is_Empty then return Index_On_Disk.Default_Priority; else return Indexes.Last_Element.Priority + 1; end if; end if; -- Look for the given index and, when found, -- increase priorities of all after that point for Index of Indexes loop if (not Found) and then Index.Name = Before then Trace.Debug ("Found index inserting priority:" & Index.Priority'Img); Found := True; Priority := Index.Priority; end if; if Found then Trace.Debug ("Demoting index priority of " & Index.Name); declare New_Index : constant Index_On_Disk.Index'Class := Index.With_Priority (Index.Priority + 1); begin Result := New_Index.Write_Metadata (New_Index.Metadata_File); if not Result.Success then return 0; -- Cut it short, value is no longer important end if; end; end if; end loop; if Found then Result := Outcome_Success; else -- Error, given index does not exist Result := Outcome_Failure ("Given before-index does not exist: " & Before); end if; return Priority; end Adjust_Priorities; begin if not Result.Success then return Result; end if; -- Try to avoid some minimal aliasing if Origin (Origin'Last) = '/' then return Add (Origin (Origin'First .. Origin'Last - 1), Name, Under); end if; -- Check that no other index has the same URL for Index of Indexes loop if Index.Origin = Origin then return Outcome_Failure ("Given URL already used by index named: " & Index.Name); end if; end loop; -- Check that no other index has the same name (& hence dir location) for Index of Indexes loop if Index.Name = Name then return Outcome_Failure ("Given name already in use by existing index"); end if; end loop; -- Create handler with proper priority and proceed declare Adjust_Result : Outcome := Outcome_Success; -- Might end unused Priority : constant Index_On_Disk.Priorities := Adjust_Priorities (Adjust_Result); Index : constant Index_On_Disk.Index'Class := Index_On_Disk.New_Handler (Origin, Name, Under, Result, Priority); begin Trace.Debug ("Insertion priority is" & Priority'Img); -- Check that priorities could be adjusted if not Adjust_Result.Success then return Adjust_Result; end if; -- Re-check the URL provides a valid handler: if not Result.Success then return Result; end if; Trace.Debug ("Adding index " & Origin & " at " & Under); Cached_Set.Clear; -- Reset cache so next detection finds the new index return Index.Add_With_Metadata; end; end Add; ---------------------------- -- Add_Or_Reset_Community -- ---------------------------- function Add_Or_Reset_Community return Outcome is Result : Outcome with Warnings => Off; -- Spurious warning to be silenced in Debian stable/Ubuntu LTS GNATs. Indexes : constant Set := Find_All (Config.Edit.Indexes_Directory, Result, Cached => False); use Sets; begin if not Config.DB.Get (Config.Keys.Index_Auto_Community, Default => True) then Warnings.Warn_Once ("Not configuring the community index, disabled via " & Config.Keys.Index_Auto_Community); return Outcome_Success; end if; Trace.Debug ("Resetting community index..."); for I in Indexes.Iterate loop Assert (Result); if Indexes (I).Name = Alire.Index.Community_Name then Trace.Debug ("Index was already set, deleting and re-adding..."); Assert (Indexes (I).Delete); return Add (Origin => Alire.Index.Community_Repo & "#" & Alire.Index.Community_Branch, Name => Alire.Index.Community_Name, Under => Config.Edit.Indexes_Directory, Before => (if Has_Element (Next (I)) then Indexes (Next (I)).Name else "")); end if; end loop; -- If we reach here, the index wasn't configured yet: Cached_Set.Clear; -- Reset cache so next detection finds the new index Trace.Debug ("Index was not set, adding it..."); return Add (Origin => Alire.Index.Community_Repo & "#" & Alire.Index.Community_Branch, Name => Alire.Index.Community_Name, Under => Config.Edit.Indexes_Directory); exception when E : Checked_Error => return Outcome_From_Exception (E); end Add_Or_Reset_Community; ---------------------- -- Drop_Index_Cache -- ---------------------- procedure Drop_Index_Cache is begin Cached_Set.Clear; end Drop_Index_Cache; -------------------- -- Setup_And_Load -- -------------------- procedure Setup_And_Load (From : Absolute_Path; Strict : Boolean; Force : Boolean := False) is Result : Outcome; Indexes : Set; begin if Alire.Index.Crate_Count /= 0 and then not Force then Trace.Detail ("Index already loaded, loading skipped"); return; end if; Indexes := Find_All (From, Result); if not Result.Success then Raise_Checked_Error (Message (Result)); return; end if; if Indexes.Is_Empty then Trace.Detail ("No indexes configured, adding default community index"); declare Outcome : constant Alire.Outcome := Add_Or_Reset_Community; begin if not Outcome.Success then Raise_Checked_Error ("Could not add community index: " & Message (Outcome)); return; end if; end; end if; declare Outcome : constant Alire.Outcome := Load_All (From => Alire.Config.Edit.Indexes_Directory, Strict => Strict); begin if not Outcome.Success then Raise_Checked_Error (Message (Outcome)); end if; end; end Setup_And_Load; -------------- -- Find_All -- -------------- function Find_All (Under : Absolute_Path; Result : out Outcome; Cached : Boolean := True) return Set is package Dirs renames Ada.Directories; Indexes : Set; --------------- -- Check_One -- --------------- procedure Check_One (Dir : Dirs.Directory_Entry_Type) is Metafile : constant String := Dirs.Full_Name (Dir) / Index_On_Disk.Metadata_Filename; Metadata : TOML.TOML_Value; begin -- If we have already found an invalid index, abort if not Result.Success then return; end if; -- Find metadata file if GNAT.OS_Lib.Is_Regular_File (Metafile) then Result := Load_Index_Metadata (Metafile, Metadata); -- Load and verify contents if Result.Success then -- Create the handler for the on-disk index from metadata declare Index : constant Index_On_Disk.Index'Class := Index_On_Disk.New_Handler (From => Metadata, Parent => Under, Result => Result); begin if Result.Success then Indexes.Insert (Index); end if; end; end if; if not Result.Success then Result := Outcome_Failure ("Cannot load metadata from " & Metafile & ": " & Message (Result)); end if; end if; end Check_One; begin Result := Outcome_Success; if Cached and then not Cached_Set.Is_Empty then Trace.Debug ("Reusing cached set of indexes"); return Cached_Set; end if; Trace.Debug ("Looking for indexes at " & Under); if GNAT.OS_Lib.Is_Directory (Under) then Dirs.Search (Directory => Under, Pattern => "*", Filter => (Dirs.Directory => True, others => False), Process => Check_One'Access); end if; if not Result.Success then return Default; end if; Trace.Detail ("Found" & Indexes.Length'Img & " indexes"); Cached_Set := Indexes; return Indexes; end Find_All; ---------- -- Load -- ---------- procedure Load (Crate : Crate_Name; Detect_Externals : Boolean; Strict : Boolean; From : Set := Default; Path : Any_Path := "") is begin -- Use default location if no alternatives given, or find indexes to use if From.Is_Empty and then Path = "" then Load (Crate, Detect_Externals, Strict, From, Config.Edit.Indexes_Directory); return; elsif Path /= "" then declare Result : Outcome; Indexes : constant Set := Find_All (Path, Result); begin Result.Assert; Load (Crate, Detect_Externals, Strict, Indexes, Path => ""); return; end; end if; -- At this point we must have a populated set pragma Assert (not From.Is_Empty); -- Now load if not Loaded.Contains (Crate) then for Index of From loop Index.Load (Crate, Strict); end loop; Loaded.Include (Crate); end if; -- Deal with externals after their detectors are loaded if Detect_Externals then Alire.Index.Detect_Externals (Crate, Platforms.Current.Properties); end if; end Load; -------------- -- Load_All -- -------------- function Load_All (From : Absolute_Path; Strict : Boolean) return Outcome is Result : Outcome; Indexes : constant Set := Find_All (From, Result); begin if not Result.Success then return Result; end if; for Index of Indexes loop declare Result : constant Outcome := Index.Load (Strict); begin if not Result.Success then return Result; end if; end; end loop; return Outcome_Success; end Load_All; ------------------------- -- Load_Index_Metadata -- ------------------------- function Load_Index_Metadata (File : String; Value : out TOML.TOML_Value) return Outcome is Result : constant TOML.Read_Result := TOML.File_IO.Load_File (File); begin if Result.Success then Value := Result.Value; return Outcome_Success; else return Outcome_Failure ((+Result.Message) & " at line" & Result.Location.Line'Img); end if; end Load_Index_Metadata; ---------------- -- Update_All -- ---------------- function Update_All (Under : Absolute_Path) return Outcome is Result : Outcome; Indexes : constant Set := Find_All (Under, Result); begin if not Result.Success then return Result; end if; for Index of Indexes loop declare Result : constant Outcome := Index.Update; begin if Result.Success then Trace.Detail ("Updated successfully: " & Index.Origin); else return Result; end if; end; end loop; return Outcome_Success; end Update_All; end Alire.Index_On_Disk.Loading; alire-1.2.1/src/alire/alire-index_on_disk-loading.ads000066400000000000000000000063141430264165500225170ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Sets; package Alire.Index_On_Disk.Loading is ------------------- -- Index loading -- ------------------- package Sets is new Ada.Containers.Indefinite_Ordered_Sets (Index_On_Disk.Index'Class, Index_On_Disk."<", Index_On_Disk."="); type Set is new Sets.Set with null record; function Default return Set; function Find_All (Under : Absolute_Path; Result : out Outcome; Cached : Boolean := True) return Set; -- Find all indexes available on a disk location. If valid indexes -- are found or none, set Result to Outcome_Success and return the -- corresponding set. If at least one found index is invalid, set Result to -- an outcome failure and return en empty set. If cached, return the last -- known set of indexes. See also Drop_Index_Cache below too. -- -- We abort at the first invalid index as it's likely in this case that -- users misconfigured something, so this helps them notice the issue -- instead of proceeding with default behaviors, such as getting the -- community index. procedure Setup_And_Load (From : Absolute_Path; Strict : Boolean; Force : Boolean := False); -- If there are no crates loaded, load from all configured indexes at the -- configured location. If Force, load even if some crates are already -- loaded. If no index is configured, set up the default community index. function Load_All (From : Absolute_Path; Strict : Boolean) return Outcome; -- Load all indexes available at the given location procedure Load (Crate : Crate_Name; Detect_Externals : Boolean; Strict : Boolean; From : Set := Default; Path : Any_Path := "") with Pre => Path = "" or else From.Is_Empty; -- Load a single crate, optionally detecting its externals. If a set of -- already detected indexes is provided, detection is not reattempted. -- If no path for detection is given, default one is used. -- May raise Checked_Error. Loading twice the same crate is idempotent. function Update_All (Under : Absolute_Path) return Outcome; -- Find and update all indexes at given location function Add (Origin : URL; Name : String; Under : Absolute_Path; Before : String := "") return Outcome; -- Add a new remote index under a folder that possibly contains more -- indexes in child folders. That is, Under is the parent of all indexes -- Index will be set as last one, or before given index name function Add_Or_Reset_Community return Outcome; -- Adds the community index, if not already configured. If configured, -- re-adds it at the required branch by Index.Community_Branch with the -- same priority (i.e., maintaining the relative ordering); procedure Drop_Index_Cache; -- Force detection of indexes on disk on next call to Find_All private function Default return Set is (Sets.Empty_Set with null record); -- Workaround for a visibility bug that manifests in body otherwise end Alire.Index_On_Disk.Loading; alire-1.2.1/src/alire/alire-index_on_disk.adb000066400000000000000000000257641430264165500210750ustar00rootroot00000000000000with Ada.Directories; with Ada.Text_IO; with Alire.Errors; with Alire.Directories; with Alire.Index_On_Disk.Directory; with Alire.Index_On_Disk.Git; with Alire.Index_On_Disk.Loading; with Alire.TOML_Index; with Alire.TOML_Keys; with Alire.VCSs; with GNAT.OS_Lib; with GNATCOLL.VFS; with TOML.File_IO; package body Alire.Index_On_Disk is type Invalid_Index is new Index with null record; -- Dummy index type, used to return a placeholder value in error handling, -- when there is no index to return. -- All operations on it raise Program_Error. overriding function Add (This : Invalid_Index) return Outcome is (raise Program_Error); overriding function New_Handler (Origin : URL; Name : Restricted_Name; Parent : Any_Path) return Invalid_Index; function New_Invalid_Index return Invalid_Index'Class is (Invalid_Index'(URL_Len => 0, Name_Len => 0, Dir_Len => 0, others => <>)); overriding function Update (This : Invalid_Index) return Outcome is (raise Program_Error); ----------------------- -- Add_With_Metadata -- ----------------------- function Add_With_Metadata (This : Index'Class) return Outcome is use GNATCOLL.VFS; Dst : Directories.Temp_File := Directories.With_Name (+Create (+This.Metadata_Directory).Full_Name); begin -- Create containing folder with its metadata Create (+This.Metadata_Directory).Make_Dir; Assert (This.Write_Metadata (This.Metadata_File)); -- Deploy the index contents Assert (This.Add); -- Verify the index Assert (This.Verify); Dst.Keep; return Outcome_Success; exception when E : Checked_Error => return Outcome_From_Exception (E); end Add_With_Metadata; ------------ -- Delete -- ------------ function Delete (This : Index'Class) return Outcome is use Ada.Directories; begin if Exists (This.Metadata_Directory) then if Kind (This.Metadata_Directory) = Ada.Directories.Directory then Delete_Tree (This.Metadata_Directory); Trace.Debug ("Metadata dir deleted: " & This.Metadata_Directory); else return Outcome_Failure ("Expected directory folder is not a folder: " & This.Metadata_Directory); end if; else return Outcome_Failure ("Expected index directory does not exist: " & This.Metadata_Directory); end if; -- Force a reload of cached indexes in any posterior index load Loading.Drop_Index_Cache; return Outcome_Success; exception when E : others => return Outcome_From_Exception (E, "Could not delete index directory"); end Delete; ---------- -- Load -- ---------- function Load (This : Index'Class; Strict : Boolean) return Outcome is begin return Result : Outcome := Outcome_Success do TOML_Index.Load (Index => This, Strict => Strict, Result => Result); end return; exception when E : Checked_Error => return Errors.Get (E); end Load; ---------- -- Load -- ---------- procedure Load (This : Index'Class; Crate : Crate_Name; Strict : Boolean) is begin TOML_Index.Load (This, Crate, Strict); end Load; ---------- -- Name -- ---------- function Name (This : Index'Class) return Restricted_Name is (This.Name); ----------------- -- New_Handler -- ----------------- overriding function New_Handler (Origin : URL; Name : Restricted_Name; Parent : Any_Path) return Invalid_Index is (Invalid_Index (New_Invalid_Index)); ----------------- -- New_Handler -- ----------------- function New_Handler (Origin : URL; Name : String; Parent : Any_Path; Result : out Outcome; Priority : Priorities := Default_Priority) return Index'Class is function Process_Local_Index (Path : String) return Index'Class; -- Check that Path designates a readable directory and create the -- corresponding index handler for it. If something goes wrong, set -- Result to contain the corresponding error message and return -- New_Invalid_Index. ------------------------- -- Process_Local_Index -- ------------------------- function Process_Local_Index (Path : String) return Index'Class is use GNATCOLL.VFS; Dir : constant Virtual_File := Create (+Path); begin if not Dir.Is_Directory then Result := Outcome_Failure ("Not a readable directory"); return New_Invalid_Index; end if; -- Ensure the given path is not one of our own configured indexes if AAA.Strings.Has_Prefix (Path, Parent) then Result := Outcome_Failure ("Given index path is inside Alire configuration path"); return New_Invalid_Index; end if; -- Ensure the created Index wrapper has absolute path Result := Outcome_Success; return Directory.New_Handler (File_Prefix & Ada.Directories.Full_Name (Path), Name, Parent).With_Priority (Priority); end Process_Local_Index; begin if not Is_Valid_Name (Name) then Result := Outcome_Failure (Error_In_Name (Name)); return New_Invalid_Index; end if; -- Warn about http[s]:// URLs being not supported and suggest git+http -- instead. if AAA.Strings.Has_Prefix (Origin, HTTP_Prefix) then Result := Outcome_Failure ("HTTP/HTTPS URLs are not valid index origins. " & "You may want git+" & Origin & " instead."); return New_Invalid_Index; end if; -- Process "file://" URLs and anything that looks like a file name as a -- local index. if AAA.Strings.Has_Prefix (Origin, File_Prefix) then return Process_Local_Index (Origin (Origin'First + File_Prefix'Length .. Origin'Last)); elsif Origin (Origin'First) = '/' or else not AAA.Strings.Contains (Origin, "+") then return Process_Local_Index (Origin); end if; -- Process other paths as VCS's case VCSs.Kind (Origin) is when VCSs.VCS_Git => Result := Outcome_Success; return Index_On_Disk.Git.New_Handler (Origin, Name, Parent) .With_Priority (Priority); when VCSs.VCS_Unknown => Result := Outcome_Failure ("Unknown index kind: " & Origin); return New_Invalid_Index; end case; end New_Handler; ----------------- -- New_Handler -- ----------------- function New_Handler (From : TOML.TOML_Value; Parent : Any_Path; Result : out Outcome) return Index'Class is begin if not From.Has (TOML_Keys.Index_URL) then Result := Outcome_Failure ("Missing URL in index metadata"); return New_Invalid_Index; elsif not From.Has (TOML_Keys.Index_Name) then Result := Outcome_Failure ("Missing Name in index metadata"); return New_Invalid_Index; elsif not From.Has (TOML_Keys.Index_Priority) then Result := Outcome_Failure ("Missing Priority in index metadata"); return New_Invalid_Index; end if; return New_Handler (Origin => From.Get (TOML_Keys.Index_URL).As_String, Name => From.Get (TOML_Keys.Index_Name).As_String, Parent => Parent, Result => Result, Priority => Integer (From.Get (TOML_Keys.Index_Priority).As_Integer)); end New_Handler; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Index) return TOML.TOML_Value is Table : constant TOML.TOML_Value := TOML.Create_Table; begin Table.Set (TOML_Keys.Index_URL, TOML.Create_String (This.Origin)); Table.Set (TOML_Keys.Index_Name, TOML.Create_String (This.Name)); Table.Set (TOML_Keys.Index_Priority, TOML.Create_Integer (TOML.Any_Integer (This.Priority))); return Table; end To_TOML; ------------ -- Verify -- ------------ function Verify (This : Index'Class) return Outcome is use GNAT.OS_Lib; begin if not Is_Directory (This.Metadata_Directory) then return Outcome_Failure ("Metadata folder over index not found: " & This.Metadata_Directory); elsif not Is_Directory (This.Index_Directory) then return Outcome_Failure ("Index folder not found: " & This.Index_Directory); else -- TODO: simply try to load it once the loaded index is not global -- For now, instead, locate index version file: declare Repo_Version_Files : constant AAA.Strings.Vector := Directories.Find_Files_Under (Folder => This.Index_Directory, Name => "index.toml", Max_Depth => 1); begin case Repo_Version_Files.Length is when 0 => return Outcome_Failure ("No index version metadata found in " & This.Index_Directory); when 1 => null; when others => return Outcome_Failure ("Repo contains several version files: " & This.Index_Directory); end case; end; end if; return Outcome_Success; end Verify; ------------------- -- With_Priority -- ------------------- function With_Priority (This : Index'Class; Priority : Priorities) return Index'Class is begin return Wrapper : Index'Class := This do Wrapper.Priority := Priority; end return; end With_Priority; -------------------- -- Write_Metadata -- -------------------- function Write_Metadata (This : Index'Class; Filename : String) return Outcome is use Ada.Text_IO; File : File_Type; begin Create (File, Out_File, Filename); TOML.File_IO.Dump_To_File (This.To_TOML, File); Close (File); return Outcome_Success; exception when E : others => Trace.Debug ("Exception saving index to " & Filename); Log_Exception (E); if Is_Open (File) then Close (File); end if; return Outcome_From_Exception (E); end Write_Metadata; end Alire.Index_On_Disk; alire-1.2.1/src/alire/alire-index_on_disk.ads000066400000000000000000000135201430264165500211010ustar00rootroot00000000000000with Alire.Interfaces; with Alire.OS_Lib; with TOML; package Alire.Index_On_Disk is -- Root abstract type that describes the operations available on a folder -- that contains an index. -- See child packages for actual implementations. -- Some common operations are provided here with classwide parameter. -- Index metadata are stored in the /indexes//index.toml -- Actual index is stored in /indexes//repo -- URLs given to New_Handler functions must be complete, commit optional: -- E.g.: git+https://path/to/server/and/project[#commit] -- E.g.: file:///path/to/local/folder Checkout_Directory : constant String := "repo"; Metadata_Filename : constant String := "index.toml"; File_Prefix : constant String := "file://"; HTTP_Prefix : constant String := "http"; subtype Priorities is Integer; -- Lower is loaded before Default_Priority : constant := 1; type Index (<>) is abstract new Interfaces.Tomifiable with private; pragma Warnings (Off); -- because Post doesn't mention New_Handler'Result function New_Handler (Origin : URL; Name : String; Parent : Any_Path; Result : out Outcome; Priority : Priorities := Default_Priority) return Index'Class with Post => Name in Restricted_Name or not Result.Success; pragma Warnings (On); -- Factory function. -- Name is a user given name used to denote the index (like a git origin). -- Parent is the folder that contains all indexes. -- If not Result.Success, the returned index is invalid and will raise -- Program_Error in all attempted operations. function New_Handler (From : TOML.TOML_Value; Parent : Any_Path; Result : out Outcome) return Index'Class with Pre => From.Kind in TOML.TOML_Table; -- Load from a output Index.To_TOML value function New_Handler (Origin : URL; Name : Restricted_Name; Parent : Any_Path) return Index is abstract; -- Descendants use this function to initialize a URL-specific handler function Add (This : Index) return Outcome is abstract; -- Deploy the index on disk for the first time at //repo. -- This version only writes the actual index contents. function Add_With_Metadata (This : Index'Class) return Outcome; -- Creates destination dir, writes metadata, adds the contents, and -- verifies the result (the whole shebang). function Delete (This : Index'Class) return Outcome; -- Remove index from current configuration and delete its folder function Load (This : Index'Class; Strict : Boolean) return Outcome; -- Loads the actual index contents into the in-memory index procedure Load (This : Index'Class; Crate : Crate_Name; Strict : Boolean); -- Load releases for just one crate from the index function Update (This : Index) return Outcome is abstract; -- If the index allows updating (e.g. git), do it. -- Otherwise, silently do nothing and return success, since at this level -- there is no way to know if an indexed can be updated, and is always -- called. function Verify (This : Index'Class) return Outcome; -- Ascertain if an index is properly populated (metadata, crates); function Write_Metadata (This : Index'Class; Filename : String) return Outcome; -- Write metadata to given file ----------------------- -- Index information -- ----------------------- function Index_Directory (This : Index) return String; -- Returns the actual path in which the index is to be checked out, -- i.e., /indexes///repo function Metadata_Directory (This : Index'Class) return String; -- Returns the parent of the checkout directory function Metadata_File (This : Index'Class) return String; -- Returns the metadata file in the parent of the checkout directory function Name (This : Index'Class) return Restricted_Name; -- Returns the user's given Name for the index function Origin (This : Index) return URL; -- A unique string that describes where to find this index (git, dir...). function Priority (This : Index'Class) return Priorities; --------------- -- Utilities -- --------------- overriding function To_TOML (This : Index) return TOML.TOML_Value; -- Index metadata in TOML format function With_Priority (This : Index'Class; Priority : Priorities) return Index'Class; function "<" (L, R : Index'Class) return Boolean; -- Useful later for collections of indexes private type Index (URL_Len : Natural; Name_Len : Natural; Dir_Len : Natural) is abstract new Interfaces.Tomifiable with record Origin : URL (1 .. URL_Len); Name : Restricted_Name (1 .. Name_Len); Parent : String (1 .. Dir_Len); Priority : Priorities := Default_Priority; -- Lower is better end record; use OS_Lib.Operators; function Index_Directory (This : Index) return String is (This.Parent / This.Name / Checkout_Directory); function Metadata_Directory (This : Index'Class) return String is (This.Parent / This.Name); function Metadata_File (This : Index'Class) return String is (This.Metadata_Directory / Metadata_Filename); function Origin (This : Index) return URL is (This.Origin); function Priority (This : Index'Class) return Priorities is (This.Priority); function "<" (L, R : Index'Class) return Boolean is (L.Priority < R.Priority or else (L.Priority = R.Priority and then L.Origin < R.Origin)); end Alire.Index_On_Disk; alire-1.2.1/src/alire/alire-interfaces.ads000066400000000000000000000032631430264165500204120ustar00rootroot00000000000000with Alire.TOML_Adapters; with TOML; package Alire.Interfaces with Preelaborate is ------------------ -- Classifiable -- ------------------ type Classifiable is limited interface; -- Used to classify properties/dependencies when exporting to TOML function Key (This : Classifiable) return String is abstract; ---------------- -- Imaginable -- ---------------- type Imaginable is limited interface; function Image (This : Imaginable) return String is abstract; --------------- -- Colorable -- --------------- type Colorable is limited interface; -- Types that can be displayed with ANSI colors/formatting function TTY_Image (This : Colorable) return String is abstract; ---------------- -- Tomifiable -- ---------------- type Tomifiable is limited interface; -- Implemented by types that appear in the index -- This can be recursive (trees, arrays...) function To_TOML (This : Tomifiable) return TOML.TOML_Value is abstract; ------------------ -- Detomifiable -- ------------------ type Detomifiable is limited interface; -- Implemented by types that can be loaded from a TOML crate file; -- in particular by complex objects stored as tables. function From_TOML (This : in out Detomifiable; From : TOML_Adapters.Key_Queue) return Outcome is abstract; -- To allow partial load this uses an in out object. -------------- -- Yamlable -- -------------- type Yamlable is limited interface; function To_YAML (This : Yamlable) return String is abstract; -- Return a YAML text representation of the object end Alire.Interfaces; alire-1.2.1/src/alire/alire-licensing.adb000066400000000000000000000010071430264165500202130ustar00rootroot00000000000000package body Alire.Licensing is ----------------- -- From_String -- ----------------- function From_String (Label : String) return Licenses is use Ada.Strings.Unbounded; ULabel : constant Unbounded_String := +Label; begin -- TODO: use a map to do this efficiently. for License in Licenses'Range loop if License_Labels (License) = ULabel then return License; end if; end loop; return Unknown; end From_String; end Alire.Licensing; alire-1.2.1/src/alire/alire-licensing.ads000066400000000000000000000067701430264165500202500ustar00rootroot00000000000000-- Deprecated: This package provides a deprecated version of license -- identification and will be removed in a future release. package Alire.Licensing with Preelaborate is -- From https://github.com/github/choosealicense.com type Licenses is (AFL_3_0, AGPL_3_0, Apache_2_0, Artistic_2_0, BSD_2_Clause, BSD_3_Clause_Clear, BSD_3_Clause, BSL_1_0, CC0_1_0, CC_BY_4_0, CC_BY_SA_4_0, ECL_2_0, EPL_1_0, EPL_2_0, EUPL_1_1, EUPL_1_2, GPL_2_0, GPL_3_0, ISC, LGPL_2_1, LGPL_3_0, LPPL_1_3c, MIT, MPL_2_0, MS_PL, MS_RL, NCSA, OFL_1_1, OSL_3_0, PostgreSQL, Unlicense, WTFPL, Zlib, -- Extra additions GMGPL_2_0, GMGPL_3_0, Public_Domain, Custom, Unknown); function License_Labels (L : Licenses) return String is (case L is when AFL_3_0 => "AFL 3.0", when AGPL_3_0 => "AGPL 3.0", when Apache_2_0 => "Apache 2.0", when Artistic_2_0 => "Artistic 2.0", when BSD_2_Clause => "BSD 2-Clauses", when BSD_3_Clause_Clear => "BSD 3-Clauses Clear", when BSD_3_Clause => "BSD 3-Clauses", when BSL_1_0 => "BSL 1.0", when CC0_1_0 => "CC0 1.0", when CC_BY_4_0 => "CC BY 4.0", when CC_BY_SA_4_0 => "CC BY-SA 4.0", when ECL_2_0 => "ECL 2.0", when EPL_1_0 => "EPL 1.0", when EPL_2_0 => "EPL 2.0", when EUPL_1_1 => "EUPL 1.1", when EUPL_1_2 => "EUPL 1.2", when GPL_2_0 => "GPL 2.0", when GPL_3_0 => "GPL 3.0", when ISC => "ISC", when LGPL_2_1 => "LGPL 2.1", when LGPL_3_0 => "LGPL 3.0", when LPPL_1_3c => "LPPL 1.3c", when MIT => "MIT", when MPL_2_0 => "MPL 2.0", when MS_PL => "MS PL", when MS_RL => "MS RL", when NCSA => "NCSA", when OFL_1_1 => "OFL 1.1", when OSL_3_0 => "OSL 3.0", when PostgreSQL => "PostgreSQL", when Unlicense => "Unlicense", when WTFPL => "WTFPL", when Zlib => "zlib", -- Extra additions when GMGPL_2_0 => "GMGPL 2.0", when GMGPL_3_0 => "GMGPL 3.0", when Public_Domain => "Public Domain", when Custom => "Custom", when Unknown => "Unknown"); function From_String (Label : String) return Licenses; -- Return the Licenses value corresponding to Label (see License_Labels). -- Return Unknown if none matches. end Alire.Licensing; alire-1.2.1/src/alire/alire-lockfiles.adb000066400000000000000000000066341430264165500202260ustar00rootroot00000000000000with Ada.Directories; with Ada.Text_IO; with Alire.Directories; with Alire.Paths; with Alire.TOML_Load; with TOML.File_IO; package body Alire.Lockfiles is use Directories.Operators; ---------- -- Keys -- ---------- package Keys is -- Key used internally for TOML serialization Solution : constant String := "solution"; end Keys; --------------- -- File_Name -- --------------- function File_Name (Root_Dir : Any_Path) return Any_Path is (Root_Dir / Paths.Working_Folder_Inside_Root / Simple_Name); --------------- -- From_TOML -- --------------- overriding function From_TOML (This : in out Contents; From : TOML_Adapters.Key_Queue) return Outcome is begin This.Solution := Solutions.From_TOML (TOML_Adapters.From (From.Checked_Pop (Key => Keys.Solution, Kind => TOML.TOML_Table), Keys.Solution)); From.Report_Extra_Keys; return Outcome_Success; end From_TOML; ---------- -- Read -- ---------- function Read (Filename : Any_Path) return Contents is begin Trace.Debug ("Reading persistent contents from " & Filename); declare Result : constant TOML.Read_Result := TOML.File_IO.Load_File (Filename); begin if Result.Success then return This : Contents do Assert (This.From_TOML (TOML_Adapters.From (Result.Value, Filename & ":"))); end return; else Raise_Checked_Error (TOML_Load.Format_Error (Filename, Result)); end if; end; end Read; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Contents) return TOML.TOML_Value is begin return Table : constant TOML.TOML_Value := TOML.Create_Table do Table.Set (Keys.Solution, This.Solution.To_TOML); end return; end To_TOML; -------------- -- Validity -- -------------- function Validity (File : Any_Path) return Validities is begin if not GNAT.OS_Lib.Is_Read_Accessible_File (File) then return Missing; end if; -- Try to load to assess validity declare Unused : constant Contents := Read (File); begin return Valid; end; exception when E : others => Trace.Debug ("Exception while loading lockfile is: "); Log_Exception (E, Debug); return Invalid; end Validity; ----------- -- Write -- ----------- procedure Write (Contents : Lockfiles.Contents; Filename : Any_Path) is use Ada.Text_IO; File : File_Type; begin Trace.Debug ("Dumping lockfile contents to " & Filename); Directories.Create_Tree (Directories.Parent (Filename)); Create (File, Out_File, Filename); Put_Line (File, "# THIS IS A MACHINE-GENERATED FILE. DO NOT EDIT MANUALLY."); New_Line (File); TOML.File_IO.Dump_To_File (Contents.To_TOML, File); Close (File); exception when others => if Is_Open (File) then Close (File); end if; -- Clean up if Ada.Directories.Exists (Filename) then Ada.Directories.Delete_File (Filename); end if; raise; end Write; end Alire.Lockfiles; alire-1.2.1/src/alire/alire-lockfiles.ads000066400000000000000000000026651430264165500202470ustar00rootroot00000000000000with Alire.Interfaces; with Alire.Solutions; with Alire.TOML_Adapters; with TOML; package Alire.Lockfiles is Simple_Name : constant String := "alire.lock"; type Validities is (Missing, Invalid, Valid); -- The lockfile stores persistent private information read/written by -- Alire and not intended for human tinkering. This currently includes -- the solution for the root dependencies (that itself includes any pin -- overrides). type Contents is new Interfaces.Detomifiable and Interfaces.Tomifiable with record Solution : Solutions.Solution; end record; -- Information that goes in the lockfile function File_Name (Root_Dir : Any_Path) return Any_Path; -- Return the location /path/to/crate/dir/alire.lock, filename included, -- given the root directory where the crate is deployed. function Read (Filename : Any_Path) return Contents; -- Read contents from the given lockfile function Validity (File : Any_Path) return Validities; -- Check if given file is a valid lockfile procedure Write (Contents : Lockfiles.Contents; Filename : Any_Path); -- Write persistent contents to a file overriding function From_TOML (This : in out Contents; From : TOML_Adapters.Key_Queue) return Outcome; overriding function To_TOML (This : Contents) return TOML.TOML_Value; end Alire.Lockfiles; alire-1.2.1/src/alire/alire-manifest.adb000066400000000000000000000053241430264165500200540ustar00rootroot00000000000000with AAA.Strings; with Alire.Paths; with Alire.Releases; with Alire.TOML_Keys; with Alire.Utils.Text_Files; with TOML_Slicer; package body Alire.Manifest is ------------ -- Append -- ------------ procedure Append (Name : Any_Path; Dep : Dependencies.Dependency) is begin Utils.Text_Files.Append_Lines (File => Name, Lines => AAA.Strings.Empty_Vector .Append ("[[" & TOML_Keys.Depends_On & "]]") .Append (Dep.Manifest_Image), Backup => False); -- No need to backup, as this is done already on a copy of the manifest end Append; ------------ -- Append -- ------------ procedure Append (File : Any_Path; Crate : Crate_Name; Pin : User_Pins.Pin) is begin Utils.Text_Files.Append_Lines (File => File, Lines => AAA.Strings.Empty_Vector .Append ("[[" & TOML_Keys.Pins & "]]") .Append (Pin.To_Manifest_Line (Crate)), Backup => False); -- No need to backup as this is done on a copy of the manifest already end Append; -------------- -- Is_Valid -- -------------- function Is_Valid (Name : Any_Path; Source : Sources) return Boolean is begin -- Check we are able to load the manifest file if Releases.From_Manifest (Name, Source, Strict => False).Version_Image /= "" then Trace.Debug ("Checked valid manifest at " & Name); return True; else raise Program_Error with "A release will always have a version"; return False; end if; exception when E : others => Trace.Debug ("Exception trying to load manifest:"); Log_Exception (E); return False; end Is_Valid; ------------ -- Remove -- ------------ procedure Remove (Name : Any_Path; Dep : Crate_Name) is begin TOML_Slicer.Remove_Line_From_Array (File_Name => Name, Array_Name => TOML_Keys.Depends_On, Entry_Name => Dep.As_String, Cleanup => True, Backup => True, Backup_Dir => Paths.Working_Folder_Inside_Root); end Remove; ---------------- -- Remove_Pin -- ---------------- procedure Remove_Pin (File : Any_Path; Pin : Crate_Name) is begin TOML_Slicer.Remove_Line_From_Array (File_Name => File, Array_Name => TOML_Keys.Pins, Entry_Name => Pin.As_String, Cleanup => True, Backup => True, Backup_Dir => Paths.Working_Folder_Inside_Root); end Remove_Pin; end Alire.Manifest; alire-1.2.1/src/alire/alire-manifest.ads000066400000000000000000000022531430264165500200730ustar00rootroot00000000000000with Alire.Dependencies; with Alire.User_Pins; package Alire.Manifest is type Sources is (Index, Local); -- We may have slightly different mandatory fields for a manifest that is -- coming from an index or from a local crate (initialized, pinned...) -- Subprograms for manipulation of the manifest file procedure Append (Name : Any_Path; Dep : Dependencies.Dependency); procedure Remove (Name : Any_Path; Dep : Crate_Name); -- Do a best effort to remove dependencies; if we cannot locate a -- dependency with enough guarantees of not botching the manifest, -- no change will be applied and Checked_Error will be raised. procedure Append (File : Any_Path; Crate : Crate_Name; Pin : User_Pins.Pin); procedure Remove_Pin (File : Any_Path; Pin : Crate_Name); -- As removal of dependencies, but for pins. If the pin is not found, or -- it cannot be safely removed, it will raise. function Is_Valid (Name : Any_Path; Source : Sources) return Boolean; -- Check that the given Name is a loadable manifest end Alire.Manifest; alire-1.2.1/src/alire/alire-milestones-containers.ads000066400000000000000000000005751430264165500226170ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; with Ada.Containers.Indefinite_Ordered_Sets; package Alire.Milestones.Containers with Preelaborate is package Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Milestones.Milestone); package Sets is new Ada.Containers.Indefinite_Ordered_Sets (Milestones.Milestone); end Alire.Milestones.Containers; alire-1.2.1/src/alire/alire-milestones.ads000066400000000000000000000040161430264165500204460ustar00rootroot00000000000000with Alire.Interfaces; with Semantic_Versioning; private with Alire.Utils.TTY; private with Alire.Utils; with AAA.Strings; use AAA.Strings; package Alire.Milestones with Preelaborate is type Milestone (<>) is new Interfaces.Colorable with private; function "<" (L, R : Milestone) return Boolean; function New_Milestone (Name : Crate_Name; Version : Semantic_Versioning.Version) return Milestone; function New_Milestone (Image : String) return Milestone; -- Attempt to parse a valid crate=version milestone function Crate (M : Milestone) return Crate_Name; function Version (M : Milestone) return Semantic_Versioning.Version; function Image (M : Milestone) return String; overriding function TTY_Image (M : Milestone) return String; private type Milestone (Name_Len : Natural) is new Interfaces.Colorable with record Name : Crate_Name (Name_Len); Version : Semantic_Versioning.Version; end record; use all type Semantic_Versioning.Version; function "<" (L, R : Milestone) return Boolean is (L.Name < R.Name or else (L.Name = R.Name and then L.Version < R.Version)); function New_Milestone (Name : Crate_Name; Version : Semantic_Versioning.Version) return Milestone is (Name.Length, Name, Version); function New_Milestone (Image : String) return Milestone is (New_Milestone (Name => To_Name (Head (Image, '=')), Version => Semantic_Versioning.New_Version (Tail (Image, '=')))); function Crate (M : Milestone) return Crate_Name is (M.Name); function Version (M : Milestone) return Semantic_Versioning.Version is (M.Version); function Image (M : Milestone) return String is ((+M.Crate) & "=" & Image (M.Version)); overriding function TTY_Image (M : Milestone) return String is (Utils.TTY.Name (+M.Crate) & "=" & Utils.TTY.Version (Image (M.Version))); end Alire.Milestones; alire-1.2.1/src/alire/alire-optional.ads000066400000000000000000000011721430264165500201110ustar00rootroot00000000000000with Optional.Values; package Alire.Optional with Preelaborate is -- Optional basic types package Absolute_Paths is new Standard.Optional.Values (Alire.Absolute_Path, Absolute_Path_Image); subtype Absolute_Path is Absolute_Paths.Optional; package Crate_Names is new Standard.Optional.Values (Crate_Name, As_String); subtype Crate_Name is Crate_Names.Optional; function String_Image (Str : Standard.String) return Standard.String is (Str); package Strings is new Standard.Optional.Values (String, String_Image); subtype String is Strings.Optional; end Alire.Optional; alire-1.2.1/src/alire/alire-origins-deployers-external.ads000066400000000000000000000007471430264165500235710ustar00rootroot00000000000000package Alire.Origins.Deployers.External is -- External deployer does not deploy anything, as this is something already -- found in the system. type Deployer is new Deployers.Deployer with null record; overriding function Fetch (This : Deployer; Unused_Folder : String) return Outcome is (Outcome_Success); overriding function Deploy (This : Deployer; Unused_Folder : String) return Outcome is (Outcome_Success); end Alire.Origins.Deployers.External; alire-1.2.1/src/alire/alire-origins-deployers-filesystem.adb000066400000000000000000000064631430264165500241130ustar00rootroot00000000000000with GNATCOLL.VFS; with Alire.Directories; with Alire.Errors; with Alire.Origins.Deployers.Source_Archive; package body Alire.Origins.Deployers.Filesystem is ------------------ -- Compute_Hash -- ------------------ overriding function Compute_Hash (This : Deployer; Folder : String; Kind : Hashes.Kinds) return Hashes.Any_Digest is pragma Unreferenced (Folder); use GNATCOLL.VFS; Src : constant Virtual_File := Create (+This.Base.Path); begin if not Src.Is_Regular_File then raise Checked_Error with Errors.Set ("Hashing of non-tarball local crate is unsupported."); end if; return Hashes.Digest (Hashes.Hash_File (Kind, +Src.Full_Name)); end Compute_Hash; ------------ -- Deploy -- ------------ overriding function Deploy (This : Deployer; Folder : String) return Outcome is use GNATCOLL.VFS; Dst : constant Virtual_File := Create (+Folder); Dst_Guard : Directories.Temp_File := Directories.With_Name (+Dst.Full_Name); -- The guard ensures deletion in case of error. --------------------- -- Deploy_From_Dir -- --------------------- function Deploy_From_Dir return Outcome is begin -- Fill contents of destination Alire.Directories.Copy (Src_Folder => This.Base.Path, Dst_Parent_Folder => Folder, Excluding => "alire"); Dst_Guard.Keep; return Outcome_Success; end Deploy_From_Dir; ------------------------- -- Deploy_From_Archive -- ------------------------- function Deploy_From_Archive return Outcome is begin Source_Archive.Unpack (Src_File => This.Base.Path, Dst_Dir => Dst_Guard.Filename, Delete => False, Move_Up => True); Dst_Guard.Keep; return Outcome_Success; end Deploy_From_Archive; Src : constant Virtual_File := Create (+This.Base.Path); begin -- Create destination if not Dst.Is_Directory then Dst.Make_Dir; end if; -- Check source crate existence if Src.Is_Directory then return Deploy_From_Dir; elsif Src.Is_Regular_File then return Deploy_From_Archive; else return Outcome_Failure ("Filesystem crate is neither a folder nor a source archive: " & This.Base.Path); end if; end Deploy; ----------- -- Fetch -- ----------- overriding function Fetch (This : Deployer; Folder : String) return Outcome is (Outcome_Success); -------------------------- -- Is_Valid_Local_Crate -- -------------------------- function Is_Valid_Local_Crate (Path : VFS.Virtual_File) return Boolean is (Path.Is_Directory or else Archive_Format (Path.Display_Base_Name) in Known_Source_Archive_Format); ---------------------- -- Supports_Hashing -- ---------------------- overriding function Supports_Hashing (This : Deployer) return Boolean is use GNATCOLL.VFS; begin return Create (+This.Base.Path).Is_Regular_File; end Supports_Hashing; end Alire.Origins.Deployers.Filesystem; alire-1.2.1/src/alire/alire-origins-deployers-filesystem.ads000066400000000000000000000025511430264165500241260ustar00rootroot00000000000000with Alire.VFS; package Alire.Origins.Deployers.Filesystem is type Deployer is new Deployers.Deployer with null record; overriding function Fetch (This : Deployer; Folder : String) return Outcome; -- Does nothing for this origin kind. overriding function Deploy (This : Deployer; Folder : String) return Outcome; -- For local crates that are folders, this function will: -- * Verify the source path exists -- * Create the destination Folder -- * Copy the source crate into the destination folder -- For local crates that are source archives, this function will: -- * Uncompress the file at the destination directory overriding function Compute_Hash (This : Deployer; Folder : String; Kind : Hashes.Kinds) return Hashes.Any_Digest; -- For dirs: not implemented (the expectation is that the origin is a local -- in-progress crate). -- For files : hash the origin file. overriding function Supports_Hashing (This : Deployer) return Boolean; -- Filesystem origins that point to a tarball must verify it, while ones -- that point to a directory must not. function Is_Valid_Local_Crate (Path : VFS.Virtual_File) return Boolean; -- True if Path is a folder or a file with known source archive extension. end Alire.Origins.Deployers.Filesystem; alire-1.2.1/src/alire/alire-origins-deployers-git.adb000066400000000000000000000007531430264165500225060ustar00rootroot00000000000000with Alire.VCSs.Git; package body Alire.Origins.Deployers.Git is ------------ -- Deploy -- ------------ overriding function Deploy (This : Deployer; Folder : String) return Outcome is begin return VCSs.Git.Handler.Clone (This.Base.URL_With_Commit, Folder); end Deploy; ----------- -- Fetch -- ----------- overriding function Fetch (This : Deployer; Folder : String) return Outcome is (Outcome_Success); end Alire.Origins.Deployers.Git; alire-1.2.1/src/alire/alire-origins-deployers-git.ads000066400000000000000000000005341430264165500225240ustar00rootroot00000000000000package Alire.Origins.Deployers.Git is type Deployer is new Deployers.Deployer with null record; overriding function Fetch (This : Deployer; Folder : String) return Outcome; -- Does nothing for this origin kind. overriding function Deploy (This : Deployer; Folder : String) return Outcome; end Alire.Origins.Deployers.Git; alire-1.2.1/src/alire/alire-origins-deployers-hg.adb000066400000000000000000000007471430264165500223240ustar00rootroot00000000000000with Alire.VCSs.Hg; package body Alire.Origins.Deployers.Hg is ------------ -- Deploy -- ------------ overriding function Deploy (This : Deployer; Folder : String) return Outcome is begin return VCSs.Hg.Handler.Clone (This.Base.URL_With_Commit, Folder); end Deploy; ----------- -- Fetch -- ----------- overriding function Fetch (This : Deployer; Folder : String) return Outcome is (Outcome_Success); end Alire.Origins.Deployers.Hg; alire-1.2.1/src/alire/alire-origins-deployers-hg.ads000066400000000000000000000005321430264165500223350ustar00rootroot00000000000000package Alire.Origins.Deployers.Hg is type Deployer is new Deployers.Deployer with null record; overriding function Fetch (This : Deployer; Folder : String) return Outcome; -- Does nothing for this origin kind. overriding function Deploy (This : Deployer; Folder : String) return Outcome; end Alire.Origins.Deployers.Hg; alire-1.2.1/src/alire/alire-origins-deployers-source_archive.adb000066400000000000000000000220561430264165500247240ustar00rootroot00000000000000with Ada.Directories; with AAA.Strings; use AAA.Strings; with Alire.Errors; with Alire.Directories; with Alire.OS_Lib.Subprocess; with Alire.OS_Lib.Download; with Alire.VFS; with Alire.URI; with Alire.Utils; use Alire.Utils; with Alire.Utils.Tools; with GNATCOLL.OS.Constants; with GNATCOLL.VFS; package body Alire.Origins.Deployers.Source_Archive is package Dirs renames Ada.Directories; procedure Untar (Src_File_Full_Name : Absolute_Path); -- Extract the tar archive at Src_File_Full_Name in the current directory ----------- -- Untar -- ----------- procedure Untar (Src_File_Full_Name : Absolute_Path) is package Subprocess renames Alire.OS_Lib.Subprocess; use type GNATCOLL.OS.OS_Type; Unused : AAA.Strings.Vector; begin -- Make sure tar is installed Utils.Tools.Check_Tool (Utils.Tools.Tar); case GNATCOLL.OS.Constants.OS is when GNATCOLL.OS.Windows => -- On some versions of tar found on Windows, an option is required -- to force e.g. C: to mean a local file location rather than the -- net host C. Unfortunately this not common to all tar on -- Windows, so we first try to untar with the --force-local, and -- if that fails, we retry without --force-local. declare begin -- Try to untar with --force-local Unused := Subprocess.Checked_Spawn_And_Capture ("tar", Empty_Vector & "--force-local" & "-x" & "-f" & Src_File_Full_Name, Err_To_Out => True); exception when E : Checked_Error => Trace.Debug ("tar --force-local failed: " & Errors.Get (E)); -- In case of error, retry without the --force-local option Unused := Subprocess.Checked_Spawn_And_Capture ("tar", Empty_Vector & "-x" & "-f" & Src_File_Full_Name, Err_To_Out => True); end; when GNATCOLL.OS.Unix | GNATCOLL.OS.MacOS => -- On other platforms, just run tar without --force-local Unused := Subprocess.Checked_Spawn_And_Capture ("tar", Empty_Vector & "-x" & "-f" & Src_File_Full_Name, Err_To_Out => True); end case; exception when E : Checked_Error => Trace.Warning ("tar failed: " & Errors.Get (E, Clear => False)); -- Reraise current occurrence raise; end Untar; ------------ -- Deploy -- ------------ overriding function Deploy (This : Deployer; Folder : String) return Outcome is Archive_Name : constant String := This.Base.Archive_Name; Archive_File : constant String := Dirs.Compose (Folder, Archive_Name); begin Trace.Detail ("Deploying source archive " & Archive_Name & " into " & Folder & "..."); Unpack (Src_File => Archive_File, Dst_Dir => Folder, Delete => True, Move_Up => True); return Outcome_Success; end Deploy; ------------------ -- Compute_Hash -- ------------------ overriding function Compute_Hash (This : Deployer; Folder : String; Kind : Hashes.Kinds) return Hashes.Any_Digest is Archive_Name : constant String := Dirs.Simple_Name (This.Base.Archive_Name); Archive_File : constant String := Dirs.Compose (Folder, Archive_Name); begin return Hashes.Digest (Hashes.Hash_File (Kind, Archive_File)); end Compute_Hash; ----------- -- Fetch -- ----------- overriding function Fetch (This : Deployer; Folder : String) return Outcome is begin -- If the file is local, do a simple copy. While curl seems to work in -- linux also for local files, something funny is going on Windows which -- is difficult to pinpoint. if URI.Scheme (This.Base.Archive_URL) in URI.File_Schemes then if not Dirs.Exists (Folder) then Alire.Directories.Create_Tree (Folder); end if; Ada.Directories.Copy_File (URI.Local_Path (This.Base.Archive_URL), Dirs.Compose (Folder, Dirs.Simple_Name (This.Base.Archive_Name))); return Outcome_Success; else return OS_Lib.Download.File (URL => This.Base.Archive_URL, Filename => This.Base.Archive_Name, Folder => Folder); end if; end Fetch; ------------ -- Unpack -- ------------ procedure Unpack (Src_File : String; Dst_Dir : String; Delete : Boolean; Move_Up : Boolean) is ----------------------- -- Check_And_Move_Up -- ----------------------- procedure Check_And_Move_Up is Contents : constant VFS.Virtual_File_Vector := VFS.Read_Dir (VFS.New_Virtual_File (VFS.From_FS (Dst_Dir))); Success : Boolean; begin if Natural (Contents.Length) = 0 then raise Checked_Error with Errors.Set ("No content where a single directory was expected: " & Dst_Dir); end if; if Natural (Contents.Length) /= 1 or else not Contents.First_Element.Is_Directory then raise Checked_Error with Errors.Set ("Unexpected contents where a single directory was expected: " & Dst_Dir); end if; Trace.Debug ("Unpacked crate root detected as: " & Contents.First_Element.Display_Base_Dir_Name); -- Move everything up one level: for File of VFS.Read_Dir (Contents.First_Element) loop declare use type VFS.Virtual_File; New_Name : constant VFS.Virtual_File := Contents.First_Element.Get_Parent / VFS.Simple_Name (File); begin GNATCOLL.VFS.Rename (File => File, Full_Name => New_Name, Success => Success); if not Success then raise Checked_Error with Errors.Set ("Could not rename " & File.Display_Full_Name & " to " & New_Name.Display_Full_Name); end if; end; end loop; -- Delete the folder, that must be empty: Contents.First_Element.Remove_Dir (Success => Success); if not Success then raise Checked_Error with Errors.Set ("Could not remove supposedly empty directory: " & Contents.First_Element.Display_Full_Name); end if; end Check_And_Move_Up; package Subprocess renames Alire.OS_Lib.Subprocess; use GNATCOLL.VFS; begin case Archive_Format (Src_File) is when Tarball => declare -- We had some trouble on Windows with trying to extract a -- tar archive in a specified destination directory (using the -- -C switch). To workaround these issue we now move to the -- destination directory before running tar .. -- .. which means we need to preserve the full name of -- the source file, in case the given name is -- relative. Src_File_Full_Name : constant Absolute_Path := +GNATCOLL.VFS.Full_Name (GNATCOLL.VFS.Create_From_Base (+Src_File)); -- Create the destination directory Dst : constant Virtual_File := Create (+Dst_Dir); Dst_Guard : Directories.Temp_File := Directories.With_Name (+Dst.Full_Name); -- Enter the destination directory, and automatically restore -- the current dir at the end of the scope. Guard : Directories.Guard (Directories.Enter (Dst_Dir)) with Unreferenced; begin Untar (Src_File_Full_Name); -- In case of success we keep the destination folder Dst_Guard.Keep; end; when Zip_Archive => -- Make sure unzip is installed Utils.Tools.Check_Tool (Utils.Tools.Unzip); Subprocess.Checked_Spawn ("unzip", Empty_Vector & "-q" & Src_File & "-d" & Dst_Dir); when Unknown => raise Checked_Error with Errors.Set ("Given packed archive has unknown format: " & Src_File); end case; if Delete then Trace.Debug ("Deleting source archive: " & Src_File); Ada.Directories.Delete_File (Src_File); end if; if Move_Up then Check_And_Move_Up; end if; end Unpack; end Alire.Origins.Deployers.Source_Archive; alire-1.2.1/src/alire/alire-origins-deployers-source_archive.ads000066400000000000000000000020231430264165500247350ustar00rootroot00000000000000package Alire.Origins.Deployers.Source_Archive is type Deployer is new Deployers.Deployer with null record; overriding function Fetch (This : Deployer; Folder : String) return Outcome; overriding function Deploy (This : Deployer; Folder : String) return Outcome; overriding function Compute_Hash (This : Deployer; Folder : String; Kind : Hashes.Kinds) return Hashes.Any_Digest; overriding function Supports_Hashing (This : Deployer) return Boolean is (True); procedure Unpack (Src_File : String; Dst_Dir : String; Delete : Boolean; Move_Up : Boolean); -- Unpack a file in one of the known formats into the destination dir. If -- Delete, remove the Src_File after unpacking. If Move_Up, then if Src -- contains a single root folder, its contents are moved up one level -- into Dst_Dir. Otherwise, Checked_Error is raised. end Alire.Origins.Deployers.Source_Archive; alire-1.2.1/src/alire/alire-origins-deployers-svn.adb000066400000000000000000000007531430264165500225310ustar00rootroot00000000000000with Alire.VCSs.SVN; package body Alire.Origins.Deployers.SVN is ------------ -- Deploy -- ------------ overriding function Deploy (This : Deployer; Folder : String) return Outcome is begin return VCSs.SVN.Handler.Clone (This.Base.URL_With_Commit, Folder); end Deploy; ----------- -- Fetch -- ----------- overriding function Fetch (This : Deployer; Folder : String) return Outcome is (Outcome_Success); end Alire.Origins.Deployers.SVN; alire-1.2.1/src/alire/alire-origins-deployers-svn.ads000066400000000000000000000005341430264165500225470ustar00rootroot00000000000000package Alire.Origins.Deployers.SVN is type Deployer is new Deployers.Deployer with null record; overriding function Fetch (This : Deployer; Folder : String) return Outcome; -- Does nothing for this origin kind. overriding function Deploy (This : Deployer; Folder : String) return Outcome; end Alire.Origins.Deployers.SVN; alire-1.2.1/src/alire/alire-origins-deployers-system-apt.adb000066400000000000000000000066351430264165500240360ustar00rootroot00000000000000with AAA.Strings; use AAA.Strings; with Alire.OS_Lib.Subprocess; with Alire.Errors; package body Alire.Origins.Deployers.System.Apt is package Subprocess renames Alire.OS_Lib.Subprocess; ----------------------- -- Already_Installed -- ----------------------- overriding function Already_Installed (This : Deployer) return Boolean is -- The following call is faster than using apt and the output does not -- depend on the system locale, so we can check the Status line safely. Output : constant AAA.Strings.Vector := Subprocess.Checked_Spawn_And_Capture ("dpkg", Empty_Vector & "-s" & This.Base.Package_Name, Valid_Exit_Codes => (0, 1), -- returned when not found Err_To_Out => True); begin for Line of Output loop if Line = "Status: install ok installed" then return True; end if; end loop; return False; end Already_Installed; ------------ -- Detect -- ------------ overriding function Detect (This : Deployer) return Version_Outcomes.Outcome is -- See www.debian.org/doc/debian-policy/ch-controlfields.html#version Regexp : constant String := "Version: (?:[[:digit:]]:)*([\d\.]+).*"; -- The show command of apt-cache is locale independent, so we can check -- the Version: field safely. Output : constant AAA.Strings.Vector := Subprocess.Checked_Spawn_And_Capture ("apt-cache", Empty_Vector & "-q" & "show" & This.Base.Package_Name, Valid_Exit_Codes => (0, 100), -- Returned when not found Err_To_Out => True); begin for Line of Output loop if Contains (Line, "Version:") then Trace.Debug ("Extracting native version from apt output: " & Line); declare Match : constant String := Utils.First_Match (Regexp, Line); begin if Match /= "" then Trace.Debug ("Candidate version string: " & Match); return Version_Outcomes.New_Result (Semantic_Versioning.Parse (Match, Relaxed => True)); -- Relaxed because some Debian versions have extra version -- pts, e.g. 1.2.3.4 else Trace.Debug ("Unexpected version format, could not identify version"); end if; end; end if; end loop; Trace.Debug ("System deployer could not detect: " & This.Base.Image); return Version_Outcomes.Outcome_Failure ("could not be detected", Report => False); end Detect; ------------- -- Install -- ------------- overriding function Install (This : Deployer) return Outcome is begin Subprocess.Checked_Spawn ("sudo", Empty_Vector & "apt-get" & "install" & "--no-remove" & "-q" & "-q" & "-y" & This.Base.Package_Name); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Install; end Alire.Origins.Deployers.System.Apt; alire-1.2.1/src/alire/alire-origins-deployers-system-apt.ads000066400000000000000000000006311430264165500240450ustar00rootroot00000000000000package Alire.Origins.Deployers.System.Apt is type Deployer is new Deployers.System.Deployer with null record; overriding function Already_Installed (This : Deployer) return Boolean; overriding function Detect (This : Deployer) return Version_Outcomes.Outcome; overriding function Install (This : Deployer) return Outcome; end Alire.Origins.Deployers.System.Apt; alire-1.2.1/src/alire/alire-origins-deployers-system-pacman.adb000066400000000000000000000075361430264165500245120ustar00rootroot00000000000000with AAA.Strings; use AAA.Strings; with Alire.OS_Lib.Subprocess; with Alire.Errors; package body Alire.Origins.Deployers.System.Pacman is package Subprocess renames Alire.OS_Lib.Subprocess; ---------------------- -- Get_Package_Line -- ---------------------- function Get_Package_Line (Package_Name : String) return String is Package_Match : constant String := "^" & Package_Name & "$"; Output : constant AAA.Strings.Vector := Subprocess.Checked_Spawn_And_Capture ("pacman", Empty_Vector & "-Ss" & Package_Match, Valid_Exit_Codes => (0, 1)); -- Returned when not found begin if not Output.Is_Empty then return Output.First_Element; else return ""; end if; end Get_Package_Line; ---------------------- -- Already_Installed -- ----------------------- overriding function Already_Installed (This : Deployer) return Boolean is Pck : String renames This.Base.Package_Name; Output : constant AAA.Strings.Vector := Subprocess.Checked_Spawn_And_Capture ("pacman", Empty_Vector & "-Qq" & This.Base.Package_Name, Valid_Exit_Codes => (0, 1), -- Returned when not found Err_To_Out => True); begin if not Output.Is_Empty and then Output.First_Element = Pck then return True; else Trace.Detail ("Cannot find package '" & Pck & "' in pacman installed list: '" & Output.Flatten & "'"); return False; end if; end Already_Installed; ------------ -- Detect -- ------------ overriding function Detect (This : Deployer) return Version_Outcomes.Outcome is Regexp : constant String := "^.* (?:\d+:)?([\d.]+)-?.*$"; -- repo/pkg opt_epoch:x.x.x.x-release_within_version something_extra -- See https://wiki.archlinux.org/index.php/PKGBUILD#pkgver Package_Line : constant String := Get_Package_Line (This.Base.Package_Name); begin if Package_Line /= "" then Trace.Detail ("Extracting native version from pacman output: " & Package_Line); declare Match : constant String := Utils.First_Match (Regexp, Package_Line); begin if Match /= "" then Trace.Detail ("Candidate version string: " & Match); return Version_Outcomes.New_Result (Semantic_Versioning.Parse (Match, Relaxed => True)); -- Versions in Arch can have more than tree numeric fields, -- which runs amok of semantic versioning. If this happens, -- the 4th and extra fields will go into the build part of -- the version, due to Relaxed parsing. else Trace.Detail ("Unexpected version format, could not identify version"); end if; end; end if; Trace.Debug ("System deployer could not detect: " & This.Base.Image); return Version_Outcomes.Outcome_Failure ("could not be detected", Report => False); end Detect; ------------- -- Install -- ------------- overriding function Install (This : Deployer) return Outcome is begin Subprocess.Checked_Spawn ("pacman", Empty_Vector & "--needed" & "--noconfirm" & "-S" & This.Base.Package_Name); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Install; end Alire.Origins.Deployers.System.Pacman; alire-1.2.1/src/alire/alire-origins-deployers-system-pacman.ads000066400000000000000000000006371430264165500245260ustar00rootroot00000000000000package Alire.Origins.Deployers.System.Pacman is type Deployer is new Deployers.System.Deployer with null record; overriding function Already_Installed (This : Deployer) return Boolean; overriding function Detect (This : Deployer) return Version_Outcomes.Outcome; overriding function Install (This : Deployer) return Outcome; end Alire.Origins.Deployers.System.Pacman; alire-1.2.1/src/alire/alire-origins-deployers-system-rpm_wrappers.adb000066400000000000000000000146221430264165500257660ustar00rootroot00000000000000with AAA.Strings; use AAA.Strings; with Alire.OS_Lib.Subprocess; with Alire.Errors; with Alire.Platforms.Current; package body Alire.Origins.Deployers.System.RPM_Wrappers is package Subprocess renames Alire.OS_Lib.Subprocess; --------------------- -- Wrapper_Command -- --------------------- function Wrapper_Command (This : Deployer) return String is (case This.Wrapper is when Dnf => "dnf", when Yum => "yum"); ------------------------------ -- Package_Name_With_Archit -- ------------------------------ function Package_Name_With_Archit (Name : String) return String is (if Contains (Name, ".") then Name else Name & "." & To_Lower_Case (Platforms.Current.Host_Architecture'Image)); ----------------------- -- Already_Installed -- ----------------------- overriding function Already_Installed (This : Deployer) return Boolean is -- Name of the package narrowed down by architecture, to avoid being -- confused by i386 packages Full_Pkg_Name : constant String := Package_Name_With_Archit (This.Base.Package_Name); Wrapper : constant String := Wrapper_Command (This); Output : constant AAA.Strings.Vector := Subprocess.Checked_Spawn_And_Capture ("rpm", Empty_Vector & "--query" & Full_Pkg_Name, Valid_Exit_Codes => (0, 1), -- Returned when not found Err_To_Out => True); begin if not Output.Is_Empty and then not Contains (Output.First_Element, "not installed") then return True; else Trace.Detail ("Cannot find package '" & Full_Pkg_Name & "' in " & Wrapper & " installed list: '" & Output.Flatten & "'"); return False; end if; end Already_Installed; ------------ -- Detect -- ------------ overriding function Detect (This : Deployer) return Version_Outcomes.Outcome is -- Name of the package narrowed down by architecture, to avoid being -- confused by i386 packages Full_Pkg_Name : constant String := Package_Name_With_Archit (This.Base.Package_Name); -------------------------- -- Detect_Not_Installed -- -------------------------- function Detect_Not_Installed return Version_Outcomes.Outcome is Regexp : constant String := "^" & AAA.Strings.To_Lower_Case (Full_Pkg_Name) & "[^\s]*\s+(?:\d+:)?([0-9.]+)"; -- A line looks like: -- gtk3.x86_64 1:3.24.24-1.fc33 updates Wrapper : constant String := Wrapper_Command (This); Output : constant AAA.Strings.Vector := Subprocess.Checked_Spawn_And_Capture (Wrapper, Empty_Vector & "-y" & "list" & Full_Pkg_Name, Valid_Exit_Codes => (0, 1), -- 1 when not found Err_To_Out => True); begin for Line of Output loop Trace.Debug ("Extracting native version from " & Wrapper & " output: " & Line & " with regex " & Regexp); declare Match : constant String := Utils.First_Match (Regexp, AAA.Strings.To_Lower_Case (Line)); begin if Match /= "" then Trace.Debug ("Candidate version string: " & Match); return Version_Outcomes.New_Result (Semantic_Versioning.Parse (Match, Relaxed => True)); -- Relaxed because some Fedora versions have extra version -- pts, e.g. 5.8-3.fc33 else Trace.Debug ("Unexpected version format, could not identify version"); end if; end; end loop; Trace.Debug ("System deployer could not detect: " & This.Base.Image); return Version_Outcomes.Outcome_Failure ("could not be detected", Report => False); end Detect_Not_Installed; ---------------------- -- Detect_Installed -- ---------------------- -- Return "" if no installed matching version function Detect_Installed return String is Output : constant AAA.Strings.Vector := Subprocess.Checked_Spawn_And_Capture ("rpm", Empty_Vector & "--query" & "--info" & Full_Pkg_Name, Valid_Exit_Codes => (0, 1), -- 1 when not found Err_To_Out => True); begin -- The line we want looks like: -- Version : x.y.z for Line of Output loop if Has_Prefix (Line, "Version ") then return Trim (Tail (Line, ':')); end if; end loop; return ""; end Detect_Installed; begin -- Try first a quick detection declare Result : constant String := Detect_Installed; begin if Result /= "" then Trace.Debug ("Candidate version string: " & Result); return Version_Outcomes.New_Result (Semantic_Versioning.Parse (Result, Relaxed => True)); -- The output format of rpm will not have epoch nor the own fedora -- release trail after '-'. end if; end; -- This is much slower return Detect_Not_Installed; end Detect; ------------- -- Install -- ------------- overriding function Install (This : Deployer) return Outcome is Wrapper : constant String := Wrapper_Command (This); begin Subprocess.Checked_Spawn ("sudo", Empty_Vector & Wrapper & "-y" & "install" & This.Base.Package_Name); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Install; end Alire.Origins.Deployers.System.RPM_Wrappers; alire-1.2.1/src/alire/alire-origins-deployers-system-rpm_wrappers.ads000066400000000000000000000010261430264165500260010ustar00rootroot00000000000000package Alire.Origins.Deployers.System.RPM_Wrappers is type Rpm_Wrapper is (Dnf, Yum); -- Command to execute (dnf, yum) type Deployer is new Deployers.System.Deployer with record Wrapper : Rpm_Wrapper; end record; overriding function Already_Installed (This : Deployer) return Boolean; overriding function Detect (This : Deployer) return Version_Outcomes.Outcome; overriding function Install (This : Deployer) return Outcome; end Alire.Origins.Deployers.System.RPM_Wrappers; alire-1.2.1/src/alire/alire-origins-deployers-system.adb000066400000000000000000000071631430264165500232510ustar00rootroot00000000000000with Alire.Origins.Deployers.System.Apt; with Alire.Origins.Deployers.System.Pacman; with Alire.Origins.Deployers.System.RPM_Wrappers; with Alire.Platforms.Current; with CLIC.User_Input; with GNAT.IO; package body Alire.Origins.Deployers.System is function Query_User (Pkg : String) return Boolean; Always_Install : Boolean := False; ------------ -- Deploy -- ------------ overriding function Deploy (This : Deployer; Folder : String) return Outcome is pragma Unreferenced (Folder); Tool : constant System.Deployer'Class := Platform_Deployer (This.Base); Pkg : constant String := This.Base.Package_Name; begin if Tool.Already_Installed then Trace.Detail (Pkg & " already installed natively"); return Outcome_Success; else if not This.Ask_Permission or else Query_User (Pkg) then return Tool.Install; else -- User rejected the installation return Outcome_Success; end if; end if; exception when others => return Outcome_Failure ("Installation of " & Pkg & " failed"); end Deploy; ---------------- -- Query_User -- ---------------- function Query_User (Pkg : String) return Boolean is use GNAT.IO; use CLIC.User_Input; begin Put_Line ("The system package '" & Pkg & "' is about to be installed."); if Always_Install then return True; end if; Put_Line ("This action might require admin privileges " & "and impact your system installation."); case Query ("Do you want Alire to install this system package?", Valid => (Yes | No | Always => True), Default => Yes) is when Yes => return True; when No => Trace.Warning ("Without this system package " & "the build is likely to fail."); Continue_Or_Abort; return False; when Always => Always_Install := True; return True; end case; end Query_User; ----------------------- -- Platform_Deployer -- ----------------------- function Platform_Deployer (From : Origins.Origin) return Deployer'Class is (case Platforms.Distro_Manager (Platforms.Current.Distribution) is when Platforms.Apt | Platforms.Packager_Unknown => System.Apt.Deployer'(Deployers.Deployer'(Base => From) with others => <>), when Platforms.Pacman => System.Pacman.Deployer'(Deployers.Deployer'(Base => From) with others => <>), when Platforms.Yum => System.RPM_Wrappers.Deployer'(Deployers.Deployer'(Base => From) with Wrapper => System.RPM_Wrappers.Yum, others => <>), when Platforms.Dnf => System.RPM_Wrappers.Deployer'(Deployers.Deployer'(Base => From) with Wrapper => System.RPM_Wrappers.Dnf, others => <>)); -- NOTE: add here other native package managers as they get -- implemented. ------------------------- -- Dont_Ask_Permission -- ------------------------- procedure Dont_Ask_Permission (This : in out Deployer) is begin This.Ask_Permission := False; end Dont_Ask_Permission; end Alire.Origins.Deployers.System; alire-1.2.1/src/alire/alire-origins-deployers-system.ads000066400000000000000000000046051430264165500232700ustar00rootroot00000000000000with Alire.Outcomes.Definite; with Semantic_Versioning; package Alire.Origins.Deployers.System is -- System deployers are a particular case with specific subprograms -- that are abstracted here. Children of this package provide concrete -- implementations for apt, yum, etc. -- The last step of the three in a regular deployer is hijacked to perform -- the actual installation of the system package. type Deployer is abstract new Deployers.Deployer with private; function Already_Installed (This : Deployer) return Boolean is abstract; -- Say if a system package is already installed package Version_Outcomes is new Outcomes.Definite (Semantic_Versioning.Version); overriding function Deploy (This : Deployer; Folder : String) return Outcome; -- We use the last step in a normal deployment to actually dispatch to -- each platform system tool installation process. Here we take advantage -- of the commonality with derived implementations to ask the user first -- for permission once. function Detect (This : Deployer) return Version_Outcomes.Outcome is abstract; -- Try and detect if a Base.Package exists in the system, installed or not overriding function Fetch (This : Deployer; Unused_Folder : String) return Outcome is (Outcome_Success); -- Fetching logic is delegated to the system package manager, we do nothing function Install (This : Deployer) return Outcome is abstract; -- Actually install the package in the system. Specific implementations -- must take care to be conservative about the user installation; e.g., do -- not proceed if that would require removal of already installed packages. -- E.g., apt --no-remove option. procedure Dont_Ask_Permission (This : in out Deployer); -- This procedure tells the deployer not to ask user permission before -- deployment. ------------- -- Factory -- ------------- function Platform_Deployer (From : Origins.Origin) return Deployer'Class with Pre => From.Is_System; function Platform_Deployer (Package_Name : String) return Deployer'Class is (Platform_Deployer (Origins.New_System (Package_Name))); private type Deployer is abstract new Deployers.Deployer with record Ask_Permission : Boolean := True; end record; end Alire.Origins.Deployers.System; alire-1.2.1/src/alire/alire-origins-deployers.adb000066400000000000000000000200231430264165500217150ustar00rootroot00000000000000with Ada.Directories; with Alire.Directories; with Alire.Origins.Deployers.External; with Alire.Origins.Deployers.Filesystem; with Alire.Origins.Deployers.Git; with Alire.Origins.Deployers.Hg; with Alire.Origins.Deployers.Source_Archive; with Alire.Origins.Deployers.System; with Alire.Origins.Deployers.SVN; with GNAT.OS_Lib; package body Alire.Origins.Deployers is ------------------ -- Compute_Hash -- ------------------ function Compute_Hash (This : Deployer; Folder : String; Kind : Hashes.Kinds) return Hashes.Any_Digest is (raise Program_Error with "Should not be called unless overridden"); ------------------ -- New_Deployer -- ------------------ function New_Deployer (From : Origin) return Deployer'Class is begin case From.Kind is when Origins.Binary_Archive => -- We can reuse the Source_Archive.Deployer return Source_Archive.Deployer'(Deployer'(Base => From) with null record); when Origins.External => return External.Deployer'(Deployer'(Base => From) with null record); when Origins.Filesystem => return Filesystem.Deployer'(Deployer'(Base => From) with null record); when Origins.Git => return Git.Deployer'(Deployer'(Base => From) with null record); when Alire.Origins.Hg => return Hg.Deployer'(Deployer'(Base => From) with null record); when Alire.Origins.SVN => return SVN.Deployer'(Deployer'(Base => From) with null record); when Alire.Origins.Source_Archive => return Source_Archive.Deployer'(Deployer'(Base => From) with null record); when Alire.Origins.System => return System.Platform_Deployer (From); end case; end New_Deployer; ------------------ -- Deploy_Steps -- ------------------ function Deploy_Steps (Rel : Releases.Release; Folder : String) return Outcome is use Directories.Operators; ---------------------- -- Create_Info_File -- ---------------------- procedure Create_Info_File is Parent : constant String := Ada.Directories.Containing_Directory (Folder); Location : constant String := Ada.Directories.Simple_Name (Folder); Filename : constant String := Parent / (Rel.Name_Str & "_" & AAA.Strings.Head (AAA.Strings.Head (Rel.Version.Image, '-'), '+') & "_in_" & Location); use GNAT.OS_Lib; Success : Boolean; begin Close (Create_File (Filename, Text), Success); -- This is merely informative, so any error can be silently ignored -- (we do test for this in the thest suite though). if not Success then Trace.Debug ("Creation of info file failed for: " & Filename); end if; end Create_Info_File; From : constant Origin := Rel.Origin; Temp_Dir : Directories.Temp_File := Directories.With_Name ((if Folder /= "" -- Empty for system releases then Ada.Directories.Containing_Directory (Folder) else Directories.Current) / Directories.Temp_Name); -- We use a temporary location to fetch and verify, as otherwise any -- failure before final deployment may result in considering a crate -- already deployed. The_Deployer : constant Deployer'Class := New_Deployer (From); Result : Outcome; begin -- 1. Fetch sources Result := The_Deployer.Fetch (Temp_Dir.Filename); if not Result.Success then return Result; end if; -- 2. Verify sources Result := The_Deployer.Verify_Hashes (Temp_Dir.Filename); if not Result.Success then return Result; end if; -- 3. Deploy final sources The_Deployer.Deploy (Temp_Dir.Filename).Assert; -- 4. Rename into final location. This is always in the same drive (as -- we created the temporary as a sibling of the final location) so it -- should be an instant operation. We check for the folder existence -- as some deployers may not need one (like system packages). Temp_Dir.Keep; if Ada.Directories.Exists (Temp_Dir.Filename) then Trace.Debug ("Renaming into place " & TTY.URL (Temp_Dir.Filename) & " as " & TTY.URL (Folder)); Ada.Directories.Rename (Old_Name => Temp_Dir.Filename, New_Name => Folder); end if; -- Add an info file for monorepos to make explicit where a release is if From.Is_Monorepo then Create_Info_File; end if; return Outcome_Success; exception when E : others => Log_Exception (E); if Ada.Directories.Exists (Folder) then Ada.Directories.Delete_Tree (Folder); end if; return Outcome_Failure ("Deployment of " & From.Image & " to " & Folder & " failed"); end Deploy_Steps; ------------ -- Deploy -- ------------ function Deploy (Release : Releases.Release; Folder : String := "") return Outcome is begin return Deploy_Steps (Release, Folder); end Deploy; ------------ -- Deploy -- ------------ function Deploy (This : Deployer; Folder : String) return Outcome is (raise Program_Error with "should never be called for base class"); ----------- -- Fetch -- ----------- function Fetch (This : Deployer; Folder : String) return Outcome is (raise Program_Error with "should never be called for base class"); ------------------- -- Verify_Hashes -- ------------------- function Verify_Hashes (This : Deployer'Class; Folder : String) return Outcome is begin if This.Supports_Hashing then -- Emit a note if we might profit from hashes: if This.Base.Get_Hashes.Is_Empty then Trace.Warning ("No integrity hashes provided for " & This.Base.Image); -- TODO: make this an error once all crates are updated with -- their hashes. else Trace.Detail ("Verifying integrity..."); end if; -- Compute hashes from downloaded release and verify: for Index_Hash of This.Base.Get_Hashes loop Trace.Debug ("Computing " & Hashes.Kind (Index_Hash)'Img & "..."); declare use type Hashes.Any_Digest; Local_Digest : constant Hashes.Any_Digest := This.Compute_Hash (Folder, Hashes.Kind (Index_Hash)); Local_Hash : constant Hashes.Any_Hash := Hashes.New_Hash (Hashes.Kind (Index_Hash), Local_Digest); begin if Hashes.Digest (Index_Hash) /= Local_Digest then return Outcome_Failure ("release integrity test failed: " & "expected [" & String (Index_Hash) & "] but got [" & String (Local_Hash) & "]"); end if; end; end loop; end if; return Outcome_Success; exception when E : Checked_Error => return Outcome_From_Exception (E); when E : others => -- May happen if Compute_Hash for some reason errs out. return Outcome_From_Exception (E, "Unexpected error while verify origin integrity" & " (use -d for details)"); end Verify_Hashes; end Alire.Origins.Deployers; alire-1.2.1/src/alire/alire-origins-deployers.ads000066400000000000000000000063241430264165500217460ustar00rootroot00000000000000with Alire.Releases; package Alire.Origins.Deployers is -- Actual fetching logic. -- A deployer is invoked thrice during retrieval of a release, in order: -- 1. Fetch: should obtain the sources in the format for hash verification. -- 2. Compute_Hashes: should compute the instructed hash with a method -- appropriated to the origin. -- 3. Deploy: deploy the sources in its final location in compilable state. ------------ -- Deploy -- ------------ function Deploy (Release : Releases.Release; Folder : String := "") return Outcome with Pre => Release.Origin.Is_System or else (not Release.Origin.Is_System and then Folder /= ""); -- This subprogram is intended to be called with an origin and it will -- create and redispatch the necessary concrete Deployer implementation. -- Since it may fail during normal operation (e.g. network down) it -- contains any unexpected error and returns an Outcome. -- To deploy a regular Release though, with action execution, the -- intended way is to call Release.Deploy which will in turn call this one. -------------- -- Deployer -- -------------- type Deployer is tagged private; -- Type that encapsulates the particulars of every origin and knows how -- to deploy it on disk. function New_Deployer (From : Origin) return Deployer'Class; -- Factory that wraps an Origin with its appropriate deployer -- Derivations of Deployer override (some of) the following: function Base (This : Deployer) return Origin; -- Return the origin for which this deployer was created function Fetch (This : Deployer; Folder : String) return Outcome; -- Retrieve the sources in a format ready for hashing. Folder is the final -- destination, that can be used as temporary location until Deploy. function Compute_Hash (This : Deployer; Folder : String; Kind : Hashes.Kinds) return Hashes.Any_Digest with Pre'Class => This.Supports_Hashing or else raise Program_Error; -- Called immediately after Fetch for each hash in the origin, Should -- be overridden by all deployers that support hashing; it won't be called -- otherwise. This function may raise exceptions that will be properly -- dealt with in the classwide Deploy. function Deploy (This : Deployer; Folder : String) return Outcome; -- Deploy the sources in the final form for compilation. function Supports_Hashing (This : Deployer) return Boolean is (False); -- Deployers that support hashing must override and return True. private type Deployer is tagged record Base : Alire.Origins.Origin; end record; function Base (This : Deployer) return Origin is (This.Base); function Verify_Hashes (This : Deployer'Class; Folder : String) return Outcome; -- Called immediately after Deploy to use Compute_Hash to verify all -- supplied hashes. At present, origins without hashes that support hashing -- is merely treated as a detail log; eventually we may want a way of -- enforcing that the chain of trust is not broken and fail otherwise. end Alire.Origins.Deployers; alire-1.2.1/src/alire/alire-origins-tweaks.adb000066400000000000000000000044531430264165500212160ustar00rootroot00000000000000with Ada.Directories; with Alire.OS_Lib; with Alire.URI; package body Alire.Origins.Tweaks is ------------------ -- Fixed_Origin -- ------------------ function Fixed_Origin (TOML_Path : String; This : Origin) return Origin is use OS_Lib.Operators; -------------------- -- Fix_Filesystem -- -------------------- function Fix_Filesystem return Origin is use Ada.Directories; begin if Check_Absolute_Path (This.Path) then return This; end if; return Fixed : Origins.Origin := This do -- Copy contents Fixed.Data.Path := +Full_Name (TOML_Path / This.Path); end return; end Fix_Filesystem; ------------- -- Fix_VCS -- ------------- function Fix_VCS return Origin is use Ada.Directories; URL : constant String := This.URL; -- Doesn't include #commit begin -- Check for "xxx+file://" or return as-is: if URI.Scheme (URL) not in URI.File_Schemes then return This; end if; declare Rel_Path : constant Relative_Path := URI.Local_Path (URL); Absolute : Origin := This; begin -- Check that path is indeed relative... if Check_Absolute_Path (Rel_Path) then return This; end if; -- Rebuild the filesystem path as absolute for the VCS in hand: Absolute.Data.Repo_URL := + -- Unbounded string (Prefix_File & Full_Name (TOML_Path / Rel_Path)); return Absolute; end; end Fix_VCS; begin -- If we receive the manifest file path instead of its parent folder: if Ada.Directories.Kind (TOML_Path) in Ada.Directories.Ordinary_File then return Fixed_Origin (Ada.Directories.Containing_Directory (TOML_Path), This); end if; -- We must fix filesystem, or VCSs with a filesystem upstream (that are -- used in the testsuite). case This.Kind is when Filesystem => return Fix_Filesystem; when VCS_Kinds => return Fix_VCS; when others => return This; end case; end Fixed_Origin; end Alire.Origins.Tweaks; alire-1.2.1/src/alire/alire-origins-tweaks.ads000066400000000000000000000012761430264165500212370ustar00rootroot00000000000000package Alire.Origins.Tweaks is -- Separate package for non-preelaborable operations. function Fixed_Origin (TOML_Path : String; This : Origin) return Origin; -- TOML_Path is the path to the file that contains the crate description. -- If the origin is not local nothing is done. Otherwise, the relative -- path in This is made absolute rooted from TOML_Path. This operation is -- necessary because, during index loading, the origin that parses itself -- is unable to check the filesystem (the information is not available -- to it), so it is performed after TOML parsing by the TOML_Index load -- callers. end Alire.Origins.Tweaks; alire-1.2.1/src/alire/alire-origins.adb000066400000000000000000000634441430264165500177270ustar00rootroot00000000000000with Ada.Directories; with AAA.Strings; with Alire.Root; with Alire.URI; with Alire.Utils.TTY; with Alire.VFS; package body Alire.Origins is ---------- -- Keys -- ---------- package Keys is -- TOML keys for serialization Archive_Name : constant String := "archive-name"; Binary : constant String := "binary"; Commit : constant String := "commit"; Hashes : constant String := "hashes"; Origin : constant String := "origin"; Subdir : constant String := "subdir"; URL : constant String := "url"; end Keys; function URL_Basename (URL : Alire.URL) return String; -- Try to get a basename for the given URL. Return an empty string on -- failure. ------------- -- As_Data -- ------------- function As_Data (This : Conditional_Archive) return Archive_Data'Class is -- Resolve the value that applies currently Evaluated : constant Conditional_Archive := This.Evaluate (Alire.Root.Platform_Properties); begin if Evaluated.Is_Empty then Raise_Checked_Error ("Binary archive is unavailable on current platform"); else return Conditional_Archives.Tree (Evaluated).Value; end if; end As_Data; ------------------ -- New_External -- ------------------ function New_External (Description : String) return Origin is (Data => (External, Description => +Description, Hashes => <>)); -------------------- -- New_Filesystem -- -------------------- function New_Filesystem (Path : String) return Origin is (Data => (Filesystem, Path => +Ada.Directories.Full_Name (Path), Hashes => <>)); ------------- -- New_Git -- ------------- function New_Git (URL : Alire.URL; Commit : Git_Commit; Subdir : Relative_Path := "") return Origin is (Data => (Git, Repo_URL => +URL, Commit => +Commit, Hashes => <>, Subdir => +Subdir)); ------------ -- New_Hg -- ------------ function New_Hg (URL : Alire.URL; Commit : Hg_Commit; Subdir : Relative_Path := "") return Origin is (Data => (Hg, Repo_URL => +URL, Commit => +Commit, Hashes => <>, Subdir => +Subdir)); ------------- -- New_SVN -- ------------- function New_SVN (URL : Alire.URL; Commit : String; Subdir : Relative_Path := "") return Origin is (Data => (SVN, Repo_URL => +URL, Commit => +Commit, Hashes => <>, Subdir => +Subdir)); ---------------- -- New_System -- ---------------- function New_System (System_Package_Name : String) return Origin is (Data => (System, Package_Name => +System_Package_Name, Hashes => <>)); ---------- -- Kind -- ---------- function Kind (This : Origin) return Kinds is (This.Data.Kind); ------------ -- Subdir -- ------------ function Subdir (This : Origin) return Relative_Path is (+This.Data.Subdir); --------- -- URL -- --------- function URL (This : Origin) return Alire.URL is (Alire.URL (+This.Data.Repo_URL)); ------------ -- Commit -- ------------ function Commit (This : Origin) return String is (+This.Data.Commit); --------------------- -- URL_With_Commit -- --------------------- function URL_With_Commit (This : Origin) return Alire.URL is (This.URL & "#" & This.Commit); ------------------------- -- TTY_URL_With_Commit -- ------------------------- function TTY_URL_With_Commit (This : Origin) return String is (Utils.TTY.URL (This.URL) & "#" & TTY.Emph (This.Commit)); ---------- -- Path -- ---------- function Path (This : Origin) return String is (+This.Data.Path); ----------------- -- Archive_URL -- ----------------- function Archive_URL (This : Origin) return Alire.URL is (if This.Kind in Source_Archive then +This.Data.Src_Archive.URL else +This.Data.Bin_Archive.As_Data.URL); ------------------ -- Archive_Name -- ------------------ function Archive_Name (This : Origin) return String is (if This.Kind in Source_Archive then +This.Data.Src_Archive.Name else +This.Data.Bin_Archive.As_Data.Name); -------------------- -- Archive_Format -- -------------------- function Archive_Format (This : Origin) return Known_Source_Archive_Format is (if This.Kind in Source_Archive then This.Data.Src_Archive.Format else This.Data.Bin_Archive.As_Data.Format); ------------------ -- Package_Name -- ------------------ function Package_Name (This : Origin) return String is (+This.Data.Package_Name); ------------- -- Get_URL -- ------------- function Get_URL (This : Origin) return Alire.URL is (case This.Kind is when Filesystem => This.Path, when Source_Archive => This.Archive_URL, when VCS_Kinds => This.URL, when others => raise Checked_Error with "Origin has no URL"); -------------- -- Add_Hash -- -------------- procedure Add_Hash (This : in out Origin; Hash : Hashes.Any_Hash) is begin case This.Kind is when Filesystem => This.Data.Hashes.Append (Hash); when Binary_Archive => -- This case should not happen, as publishing assistant doesn't -- work for conditional binary origins. raise Program_Error with Errors.Set ("Unintended use of Alire.Origins.Add_Hash"); when Source_Archive => This.Data.Src_Archive.Hashes.Append (Hash); when others => Raise_Checked_Error ("Cannot add hash to origin kind " & This.Kind'Image); end case; end Add_Hash; ---------------- -- Get_Hashes -- ---------------- function Get_Hashes (This : Origin) return Hash_Vectors.Vector is (case This.Kind is when Filesystem => This.Data.Hashes, when Binary_Archive => This.Data.Bin_Archive.As_Data.Hashes, when Source_Archive => This.Data.Src_Archive.Hashes, when others => Hash_Vectors.Empty_Vector); ---------------- -- Add_Hashes -- ---------------- -- Load hash information into the given origin function Add_Hashes (This : in out Hash_Vectors.Vector; Parent : TOML_Adapters.Key_Queue) return Outcome is Val : TOML.TOML_Value; begin if Parent.Pop (Keys.Hashes, Val) then if Val.Kind /= TOML.TOML_Array then return Parent.Failure (Keys.Hashes & " must be an array of hash values"); end if; for I in 1 .. Val.Length loop if Val.Item (I).Kind /= TOML.TOML_String then return Parent.Failure ("hash must be a 'kind:digest' formatted string"); end if; declare Hash : constant String := Val.Item (I).As_String; begin if not Hashes.Is_Well_Formed (Hash) then return Parent.Failure ("malformed or unknown hash: " & Hash); end if; This.Append (Hashes.Any_Hash (Hash)); end; end loop; else return Parent.Failure ("missing mandatory " & Keys.Hashes & " field"); end if; return Outcome_Success; end Add_Hashes; ------------------ -- URL_Basename -- ------------------ function URL_Basename (URL : Alire.URL) return String is Separator : Positive := URL'Last + 1; -- Index of the first URL separator we can find ('#' or '?') in URL, or -- URL'Last + 1 if we haven't found any. Last_Slash : Natural := URL'First - 1; -- Index of the last slash character in URL before the first URL -- separator or URL'First - 1 if we haven't found any. begin for I in URL'Range loop case URL (I) is when '?' | '#' => Separator := I; exit; when '/' | '\' => Last_Slash := I; when others => null; end case; end loop; return URL (Last_Slash + 1 .. Separator - 1); end URL_Basename; -------------------- -- Archive_Format -- -------------------- function Archive_Format (Name : String) return Source_Archive_Format is use AAA.Strings; begin if Has_Suffix (Name, ".zip") then return Zip_Archive; elsif Has_Suffix (Name, ".tar") or else Has_Suffix (Name, ".tar.gz") or else Has_Suffix (Name, ".tgz") or else Has_Suffix (Name, ".tar.bz2") or else Has_Suffix (Name, ".tbz2") or else Has_Suffix (Name, ".tar.xz") then return Tarball; else return Unknown; end if; end Archive_Format; ------------------------ -- New_Source_Archive -- ------------------------ function New_Source_Archive (URL : Alire.URL; Name : String := "") return Origin is Archive_Name : constant String := (if Name'Length = 0 then URL_Basename (URL) else Name); Format : Source_Archive_Format; begin if Archive_Name'Length = 0 then raise Unknown_Source_Archive_Name_Error with "Unable to determine archive name: please specify one"; end if; Format := Archive_Format (Archive_Name); if Format not in Known_Source_Archive_Format then raise Unknown_Source_Archive_Format_Error with "Unable to determine archive format from file extension"; end if; -- We add the "file:" to have a proper URI and simplify things for -- Windows absolute paths with drive letter. return (Data => (Source_Archive, Src_Archive => (URL => +(if URI.Scheme (URL) in URI.File_Schemes then "file:" & Ada.Directories.Full_Name (URI.Local_Path (URL)) else URL), Name => +Archive_Name, Format => Format, Binary => False, Hashes => <>))); end New_Source_Archive; ----------------- -- From_String -- ----------------- function From_String (Image : String) return Origin is Scheme : constant URI.Schemes := URI.Scheme (Image); begin case Scheme is when URI.File_Schemes => return New_Filesystem (URI.Local_Path (Image)); when URI.HTTP => return New_Source_Archive (Image); when others => Raise_Checked_Error ("Unsupported URL scheme: " & Image); end case; end From_String; ------------- -- New_VCS -- ------------- function New_VCS (URL : Alire.URL; Commit : String; Subdir : Relative_Path := "") return Origin is use AAA.Strings; use all type URI.Schemes; Scheme : constant URI.Schemes := URI.Scheme (URL); Transformed : constant Alire.URL := VCSs.Git.Transform_To_Public (URL); VCS_URL : constant String := (if Contains (URL, "file:") then Tail (URL, ':') -- Remove file: that confuses git elsif Has_Prefix (URL, "git@") and then Transformed /= URL -- known and transformable then Transformed elsif Scheme in URI.VCS_Schemes then Tail (URL, '+') -- remove prefix vcs+ elsif Scheme in URI.HTTP then -- A plain URL... check VCS (if Has_Suffix (To_Lower_Case (URL), ".git") then URL elsif VCSs.Git.Known_Transformable_Hosts.Contains (URI.Authority (URL)) then URL & ".git" else raise Checked_Error with "ambiguous VCS URL: " & URL) else raise Checked_Error with "unknown VCS URL: " & URL); begin case Scheme is when Pure_Git => if Transformed /= URL then return New_VCS (Transformed, Commit); else Raise_Checked_Error ("Attempting to use a private git@ URL with an unknown host: " & Utils.TTY.URL (URL)); end if; when Git | HTTP => if Commit'Length /= Git_Commit'Length then Raise_Checked_Error ("invalid git commit id, " & "40 digits hexadecimal expected"); end if; return New_Git (VCS_URL, Commit, Subdir); when Hg => if Commit'Length /= Hg_Commit'Length then Raise_Checked_Error ("invalid mercurial commit id, " & "40 digits hexadecimal expected"); end if; return New_Hg (VCS_URL, Commit, Subdir); when SVN => return New_SVN (VCS_URL, Commit, Subdir); when others => Raise_Checked_Error ("Expected a VCS origin but got scheme: " & Scheme'Image); end case; end New_VCS; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional_Archives.Tree is use TOML; Archive : TOML_Value; Table : constant TOML_Adapters.Key_Queue := From.Descend (From.Checked_Pop (Keys.Origin, TOML_Table), Context => "data"); begin -- Optional filename checks: if Table.Pop (Keys.Archive_Name, Archive) then if Archive.Kind /= TOML.TOML_String then Table.Checked_Error ("archive name must be a string"); end if; end if; declare Archive_Origin : Origin := New_Source_Archive (URL => Table.Checked_Pop (Keys.URL, TOML_String).As_String, Name => (if Archive.Is_Present then Archive.As_String else "")); begin Add_Hashes (Archive_Origin.Data.Src_Archive.Hashes, Table).Assert; if Table.Unwrap.Has (Keys.Binary) then Archive_Origin.Data.Src_Archive.Binary := Table.Checked_Pop (Keys.Binary, TOML_Boolean).As_Boolean; end if; Table.Report_Extra_Keys; -- Wrap as a conditional tree return Conditional_Archives.New_Leaf (Archive_Origin.Data.Src_Archive); end; exception when Unknown_Source_Archive_Name_Error => Table.Checked_Error ("unable to determine archive name from URL: " & "please specify one with '" & Keys.Archive_Name & "'"); end From_TOML; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Archive_Data is (Archive_Data (Conditional_Archive' (Conditional_Archives.Tree'(From_TOML (From)) with null record) .As_Data)); --------------- -- From_TOML -- --------------- overriding function From_TOML (This : in out Origin; From : TOML_Adapters.Key_Queue) return Outcome is use TOML; use all type URI.Schemes; Table : constant TOML_Adapters.Key_Queue := From.Descend (From.Checked_Pop (Keys.Origin, TOML_Table), Context => Keys.Origin); ----------------- -- Mark_Binary -- ----------------- procedure Mark_Binary (Data : in out Archive_Data) is begin Data.Binary := True; end Mark_Binary; begin -- Check if we are seeing a conditional binary origin, or a regular -- static one. If the former, divert to the dynamic loader; else -- continue loading normally. if (for some Key of Table.Unwrap.Keys => AAA.Strings.Has_Prefix (+Key, "case(")) or else (Table.Unwrap.Has (Keys.Binary) and then Table.Unwrap.Get (Keys.Binary).As_Boolean) then This := (Data => Origin_Data' (Kind => Binary_Archive, Bin_Archive => (Binary_Loader.Load (From => Table.Descend (Keys.Origin, Table.Unwrap, Context => "binary archive"), Loader => From_TOML'Access, Resolve => True, Strict => False) with null record))); -- Mark these as explicitly binary, because they're in a case, even -- if the maintainer omitted the binary field. This saves some noise -- in the manifest files. This.Data.Bin_Archive.Visit_All (Mark_Binary'Access); return Outcome_Success; end if; -- Regular static loading of other origin kinds declare URL : constant String := Table.Checked_Pop (Keys.URL, TOML_String).As_String; Scheme : constant URI.Schemes := URI.Scheme (URL); Hashed : constant Boolean := Table.Unwrap.Has (Keys.Hashes); begin case Scheme is when External => This := New_External (URI.Path (URL)); when URI.File_Schemes => if URI.Local_Path (URL) = "" then From.Checked_Error ("empty path given in local origin"); end if; This := New_Filesystem (URI.Local_Path (URL)); when URI.VCS_Schemes => declare Commit : constant String := Table.Checked_Pop (Keys.Commit, TOML_String).As_String; Subdir : constant String := (if Table.Contains (Keys.Subdir) then Table.Checked_Pop (Keys.Subdir, TOML_String).As_String else ""); begin This := New_VCS (URL, Commit => Commit, Subdir => VFS.To_Native (Portable_Path (Subdir))); end; when HTTP => -- Reinsert the URL so we can reuse the dynamic archive loader: Table.Unwrap.Set (Keys.URL, Create_String (URL)); -- And load This := (Data => (Kind => Source_Archive, Src_Archive => From_TOML (Table.Descend (Keys.Origin, Table.Unwrap, Context => "source archive")), Hashes => <>)); when System => This := New_System (URI.Path (URL)); when Unknown => From.Checked_Error ("unsupported scheme in URL: " & URL); end case; -- Check hashes existence appropriateness case This.Kind is when Filesystem => if Hashed then Add_Hashes (This.Data.Hashes, Table).Assert; end if; -- Hashes are mandatory only for source archives. This is checked -- on deployment, since at this moment we do not have the proper -- absolute patch when Binary_Archive => -- Should not happen, as we have loaded this particular case above raise Program_Error with Errors.Set ("This case should be unreachable"); when Source_Archive => -- Hashes already loaded by the archive data loader Assert (not This.Data.Src_Archive.Hashes.Is_Empty, Or_Else => "source archive hashes missing"); when others => if Hashed then return Table.Failure ("hashes cannot be provided for origins of kind " & AAA.Strings.To_Mixed_Case (This.Kind'Img)); end if; end case; return Table.Report_Extra_Keys; end; end From_TOML; ----------- -- Image -- ----------- function Image (This : Origin) return String is ((case This.Kind is when VCS_Kinds => "commit " & S (This.Data.Commit) & " from " & S (This.Data.Repo_URL), when Archive_Kinds => (if This.Kind in Source_Archive then Source_Image (This.Data.Src_Archive) elsif This.Data.Bin_Archive.Is_Value then Binary_Image (This.Data.Bin_Archive.As_Data) else This.Data.Bin_Archive.Image_One_Line), when System => "system package from platform software manager: " & This.Package_Name, when Filesystem => "path " & S (This.Data.Path), when External => "external " & S (This.Data.Description)) & (if This.Get_Hashes.Is_Empty then "" elsif This.Get_Hashes.Last_Index = 1 then " with hash " & This.Image_Of_Hashes else " with hashes " & This.Image_Of_Hashes) ); --------------------- -- Image_Of_Hashes -- --------------------- function Image_Of_Hashes (This : Origin) return String is -- Recursively concatenate all hashes: function Reduce (I : Natural := This.Get_Hashes.Last_Index) return String is (if I = 0 then "" elsif I > 1 then Reduce (I => I - 1) & ", " & String (This.Get_Hashes.Element (I)) else String (This.Get_Hashes.Element (I))); begin return Reduce; end Image_Of_Hashes; ------------------ -- Short_Commit -- ------------------ function Short_Commit (Commit : String) return String is (if Commit'Length < 8 then Commit else Commit (Commit'First .. Commit'First + 7)); --------------------- -- Short_Unique_Id -- --------------------- function Short_Unique_Id (This : Origin) return String is (Short_Commit (if This.Kind in Source_Archive | Binary_Archive then AAA.Strings.Tail (String (This.Get_Hashes.First_Element), ':') else This.Commit)); ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Origin) return TOML.TOML_Value is use TOML_Adapters; Table : TOML.TOML_Value := TOML.Create_Table; begin case This.Kind is when Filesystem => Table.Set (Keys.URL, +("file:" & This.Path)); when VCS_Kinds => Table.Set (Keys.URL, +(Prefixes (This.Kind).all & (if URI.Scheme (This.URL) in URI.None -- not needed for remote repos, but for testing -- ones used locally: then "file:" else "") & This.URL)); Table.Set (Keys.Commit, +This.Commit); if This.Subdir /= "" then Table.Set (Keys.Subdir, +String (VFS.To_Portable (This.Subdir))); end if; when External => Table.Set (Keys.URL, +(Prefixes (This.Kind).all & (+This.Data.Description))); when Binary_Archive => Table := TOML_Adapters.Merge_Tables (Table, This.Data.Bin_Archive.As_Data.To_TOML); when Source_Archive => Table := TOML_Adapters.Merge_Tables (Table, This.Data.Src_Archive.To_TOML); when System => Table.Set (Keys.URL, +(Prefixes (This.Kind).all & This.Package_Name)); end case; if not This.Get_Hashes.Is_Empty then declare Hashes : constant TOML.TOML_Value := TOML.Create_Array; begin for Hash of This.Get_Hashes loop Hashes.Append (+String (Hash)); end loop; Table.Set (Keys.Hashes, Hashes); end; end if; return Table; end To_TOML; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Archive_Data) return TOML.TOML_Value is use TOML; Table : constant TOML.TOML_Value := TOML.Create_Table; begin Table.Set (Keys.URL, Create_String (This.URL)); if This.Name /= "" and then This.Name /= URL_Basename (+This.URL) then Table.Set (Keys.Archive_Name, Create_String (This.Name)); end if; if This.Binary then Table.Set (Keys.Binary, Create_Boolean (This.Binary)); end if; return Table; end To_TOML; -------------- -- Whenever -- -------------- function Whenever (This : Origin; Env : Properties.Vector) return Origin is begin if This.Kind = Binary_Archive then return Result : Origin := This do Result.Data.Bin_Archive := This.Data.Bin_Archive.Evaluate (Env); end return; else return This; end if; end Whenever; ------------------ -- Is_Available -- ------------------ function Is_Available (This : Origin; Env : Properties.Vector) return Boolean is (This.Kind /= Binary_Archive or else not This.Data.Bin_Archive.Evaluate (Env).Is_Empty); end Alire.Origins; alire-1.2.1/src/alire/alire-origins.ads000066400000000000000000000260311430264165500177370ustar00rootroot00000000000000private with Alire.Conditional_Trees.TOML_Load; with Alire.Errors; with Alire.Hashes; with Alire.Interfaces; with Alire.Properties; with Alire.TOML_Adapters; private with Alire.TOML_Keys; with Alire.VCSs.Git; with Alire.VCSs.Hg; private with Ada.Containers.Indefinite_Vectors; private with Ada.Strings.Unbounded; with TOML; use all type TOML.Any_Value_Kind; with Alire.Utils; package Alire.Origins is type Kinds is (Binary_Archive, -- A pre-compiled binary (dynamic expr + source archive) External, -- A do-nothing origin, with some custom description Filesystem, -- Not really an origin, but a working copy of a release Git, -- Remote git repo Hg, -- Remote hg repo SVN, -- Remote svn repo Source_Archive, -- Remote source archive System -- System package ); type Kinds_Set is array (Kinds) of Boolean with Default_Component_Value => False; type String_Access is access constant String; type Prefix_Array is array (Kinds) of String_Access; Prefixes : constant Prefix_Array; subtype Archive_Kinds is Kinds with Static_Predicate => Archive_Kinds in Binary_Archive | Source_Archive; subtype External_Kinds is Kinds with Static_Predicate => External_Kinds in External | System; subtype VCS_Kinds is Kinds range Git .. SVN; type Source_Archive_Format is (Unknown, Tarball, Zip_Archive); subtype Known_Source_Archive_Format is Source_Archive_Format range Tarball .. Source_Archive_Format'Last; Unknown_Source_Archive_Format_Error : exception; type Origin is new Interfaces.Detomifiable and Interfaces.Tomifiable with private; function Kind (This : Origin) return Kinds; function Whenever (This : Origin; Env : Properties.Vector) return Origin; -- Resolve expressions in the origin function Is_Available (This : Origin; Env : Properties.Vector) return Boolean; -- For a binary origin, true if there is a value for the environment. True -- for the rest of kinds. ------------------- -- member data -- ------------------- function Commit (This : Origin) return String with Pre => This.Kind in VCS_Kinds; function Subdir (This : Origin) return Relative_Path with Pre => This.Kind in VCS_Kinds; -- Returns "" or a path in which the crate is located within the deployed -- origin. function URL (This : Origin) return Alire.URL with Pre => This.Kind in VCS_Kinds; function URL_With_Commit (This : Origin) return Alire.URL with Pre => This.Kind in VCS_Kinds; -- Append commit as '#commit' function TTY_URL_With_Commit (This : Origin) return String with Pre => This.Kind in VCS_Kinds; function Is_Monorepo (This : Origin) return Boolean; function Path (This : Origin) return String with Pre => This.Kind = Filesystem; function Archive_URL (This : Origin) return Alire.URL with Pre => This.Kind in Archive_Kinds; function Archive_Name (This : Origin) return String with Pre => This.Kind in Archive_Kinds; function Archive_Format (This : Origin) return Known_Source_Archive_Format with Pre => This.Kind in Archive_Kinds; function Archive_Format (Name : String) return Source_Archive_Format; -- Guess the format of a source archive from its file name. function Get_URL (This : Origin) return Alire.URL with Pre => This.Kind in Filesystem | Source_Archive | VCS_Kinds; function Is_System (This : Origin) return Boolean is (This.Kind = System); function Package_Name (This : Origin) return String with Pre => This.Kind = System; function Is_Regular (This : Origin) return Boolean is (This.Kind not in External | System); -- A regular origin is one that is compiled from sources, instead of coming -- from external definitions (detected or not). function Short_Unique_Id (This : Origin) return String with Pre => This.Kind in Git | Hg | Archive_Kinds; -- Helper types subtype Git_Commit is VCSs.Git.Git_Commit; subtype Hg_Commit is VCSs.Hg.Hg_Commit; function Is_Valid_Commit (S : String) return Boolean is (S'Length = Git_Commit'Length and then (for all Char of S => Char in Alire.Utils.Hexadecimal_Character)); function Short_Commit (Commit : String) return String; -- First characters in the commit -- Constructors function New_External (Description : String) return Origin; function New_Filesystem (Path : Any_Path) return Origin; -- If Path is relative it will be converted to a full path, so this -- function should be called from a point where the path makes sense -- in that case. function New_Git (URL : Alire.URL; Commit : Git_Commit; Subdir : Relative_Path := "") return Origin; function New_Hg (URL : Alire.URL; Commit : Hg_Commit; Subdir : Relative_Path := "") return Origin; function New_SVN (URL : Alire.URL; Commit : String; Subdir : Relative_Path := "") return Origin; function New_VCS (URL : Alire.URL; Commit : String; Subdir : Relative_Path := "") return Origin; -- Attempt to identify an origin kind from the transport (git+https). If no -- VCS specified, look for ".git" extension. Unknown_Source_Archive_Name_Error : exception; function New_Source_Archive (URL : Alire.URL; Name : String := "") return Origin; -- Create a reference to a source archive to be downloaded and extracted. -- URL is the address of the archive to download. Name is the name of the -- file to download. -- -- This raises an Unknown_Source_Archive_Format_Error exception when we -- either cannot deduce the archive format from its filename or when the -- archive format is unknown. -- -- If Name is omitted, it is tentatively inferred from URL. If it cannot be -- inferred, this raises a Unknown_Source_Archive_Name_Error exception. function New_System (System_Package_Name : String) return Origin; -- A system origin points to a single system package known to exist, -- already detected by some External. function Image (This : Origin) return String; procedure Add_Hash (This : in out Origin; Hash : Hashes.Any_Hash); function From_String (Image : String) return Origin with Post => From_String'Result.Kind in Filesystem | Source_Archive; -- Parse a string and dispatch to the appropriate constructor. This -- function can be used to retrieve unhashed origins too (precisely -- for hashing). overriding function From_TOML (This : in out Origin; From : TOML_Adapters.Key_Queue) return Outcome; -- Pops "origin" from From. overriding function To_TOML (This : Origin) return TOML.TOML_Value with Post => To_TOML'Result.Kind = TOML.TOML_Table; private use Ada.Strings.Unbounded; use all type Hashes.Any_Hash; package Hash_Vectors is new Ada.Containers.Indefinite_Vectors (Positive, Hashes.Any_Hash); function Get_Hashes (This : Origin) return Hash_Vectors.Vector; -- Ugly Get_ but it avoids lots of ambiguities down the line function "+" (S : String) return Unbounded_String renames To_Unbounded_String; function "+" (U : Unbounded_String) return String renames To_String; type Package_Names is tagged record Name : Unbounded_String; end record; function Image (This : Package_Names) return String is (+This.Name); function Unavailable return Package_Names is (Name => Null_Unbounded_String); function Packaged_As (Name : String) return Package_Names is (Name => +Name); function S (Str : Unbounded_String) return String is (To_String (Str)); type Archive_Data is new Interfaces.Classifiable and Interfaces.Tomifiable and Interfaces.Yamlable with record URL : Unbounded_String; Name : Unbounded_String; Format : Known_Source_Archive_Format; Hashes : Hash_Vectors.Vector; Binary : Boolean; end record; overriding function Key (This : Archive_Data) return String is (TOML_Keys.Origin); overriding function To_TOML (This : Archive_Data) return TOML.TOML_Value; overriding function To_YAML (This : Archive_Data) return String is (raise Unimplemented with Errors.Set ("Should not be needed")); function Image (Archive : Archive_Data; Kind : Archive_Kinds) return String is ((if Kind in Source_Archive then "source archive " else "binary archive ") & (if S (Archive.Name) /= "" then S (Archive.Name) & " " else "") & "at " & S (Archive.URL)); function Binary_Image (Archive : Archive_Data) return String is (Image (Archive, Binary_Archive)); function Source_Image (Archive : Archive_Data) return String is (Image (Archive, Source_Archive)); package Conditional_Archives is new Conditional_Trees (Values => Archive_Data, Image => Binary_Image); type Conditional_Archive is new Conditional_Archives.Tree with null record; package Binary_Loader is new Conditional_Archives.TOML_Load; function As_Data (This : Conditional_Archive) return Archive_Data'Class; type Origin_Data (Kind : Kinds := External) is record case Kind is when Binary_Archive => Bin_Archive : Conditional_Archive; when External => Description : Unbounded_String; when Filesystem => Path : Unbounded_String; Hashes : Hash_Vectors.Vector; when VCS_Kinds => Repo_URL : Unbounded_String; Commit : Unbounded_String; Subdir : Unbounded_Relative_Path; when Source_Archive => Src_Archive : Archive_Data; when System => Package_Name : Unbounded_String; end case; end record; type Origin is new Interfaces.Detomifiable and Interfaces.Tomifiable with record Data : Origin_Data; end record; function Image_Of_Hashes (This : Origin) return String; Prefix_External : aliased constant String := "external:"; Prefix_Git : aliased constant String := "git+"; Prefix_Hg : aliased constant String := "hg+"; Prefix_SVN : aliased constant String := "svn+"; Prefix_File : aliased constant String := "file://"; Prefix_System : aliased constant String := "system:"; Prefixes : constant Prefix_Array := (Git => Prefix_Git'Access, Hg => Prefix_Hg'Access, SVN => Prefix_SVN'Access, External => Prefix_External'Access, Filesystem => Prefix_File'Access, System => Prefix_System'Access, Archive_Kinds => null); function Is_Monorepo (This : Origin) return Boolean is (This.Kind in VCS_Kinds and then This.Subdir /= ""); end Alire.Origins; alire-1.2.1/src/alire/alire-os_lib-download.adb000066400000000000000000000024431430264165500213210ustar00rootroot00000000000000with Ada.Directories; with AAA.Strings; use AAA.Strings; with Alire.Errors; with Alire.OS_Lib.Subprocess; with Alire.Utils; use Alire.Utils; with Alire.Utils.Tools; with GNATCOLL.VFS; package body Alire.OS_Lib.Download is ---------- -- File -- ---------- function File (URL : String; Filename : Any_Path; Folder : Directory_Path) return Outcome is use GNATCOLL.VFS; Archive_File : constant Directory_Path := Folder / Ada.Directories.Simple_Name (Filename); begin -- Make sure curl is installed Utils.Tools.Check_Tool (Utils.Tools.Curl); Trace.Debug ("Creating folder: " & Folder); Create (+Folder).Make_Dir; Trace.Detail ("Downloading file: " & URL); OS_Lib.Subprocess.Checked_Spawn ("curl", Empty_Vector & URL & "--location" & -- allow for redirects at the remote host (if Log_Level < Trace.Info then Empty_Vector & "--silent" else Empty_Vector & "--progress-bar") & "--output" & Archive_File); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end File; end Alire.OS_Lib.Download; alire-1.2.1/src/alire/alire-os_lib-download.ads000066400000000000000000000003321430264165500213350ustar00rootroot00000000000000 package Alire.OS_Lib.Download is function File (URL : String; Filename : Any_Path; Folder : Directory_Path) return Outcome; end Alire.OS_Lib.Download; alire-1.2.1/src/alire/alire-os_lib-subprocess.adb000066400000000000000000000212231430264165500216770ustar00rootroot00000000000000with Ada.Text_IO; with CLIC.TTY; with GNAT.OS_Lib; with ANSI; use ANSI; package body Alire.OS_Lib.Subprocess is use AAA.Strings; function To_Argument_List (Args : AAA.Strings.Vector) return GNAT.OS_Lib.Argument_List_Access; procedure Cleanup (List : in out GNAT.OS_Lib.Argument_List_Access); function Image (Cmd : String; Args : AAA.Strings.Vector) return String; function Spawn (Command : String; Arguments : AAA.Strings.Vector; Understands_Verbose : Boolean := False) return Integer; function Spawn_And_Capture (Output : in out AAA.Strings.Vector; Command : String; Arguments : AAA.Strings.Vector; Understands_Verbose : Boolean := False; Err_To_Out : Boolean := False) return Integer; -- Returns output as vector of strings -- Even if exception raised, Output will be filled-in ---------------------- -- To_Argument_List -- ---------------------- function To_Argument_List (Args : AAA.Strings.Vector) return GNAT.OS_Lib.Argument_List_Access is use GNAT.OS_Lib; Arg_List : constant Argument_List_Access := new Argument_List'(1 .. Natural (Args.Length) => null); begin for I in Arg_List'Range loop Arg_List (I) := new String'(Args (I)); end loop; return Arg_List; end To_Argument_List; ------------- -- Cleanup -- ------------- procedure Cleanup (List : in out GNAT.OS_Lib.Argument_List_Access) is use GNAT.OS_Lib; begin for Str of List.all loop Free (Str); end loop; Free (List); end Cleanup; ----------- -- Image -- ----------- function Image (Cmd : String; Args : AAA.Strings.Vector) return String is ("[""" & Cmd & (if Args.Is_Empty then "" else """, """ & Args.Flatten (""", """)) & """]"); -------------------- -- Locate_In_Path -- -------------------- function Locate_In_Path (Name : String) return String is use GNAT.OS_Lib; Target : GNAT.OS_Lib.String_Access := Locate_Exec_On_Path (Name); begin if Target /= null then return Result : constant String := Target.all do Free (Target); end return; else return ""; end if; end Locate_In_Path; ------------------- -- Checked_Spawn -- ------------------- procedure Checked_Spawn (Command : String; Arguments : AAA.Strings.Vector; Understands_Verbose : Boolean := False) is Exit_Code : constant Integer := Spawn (Command => Command, Arguments => Arguments, Understands_Verbose => Understands_Verbose); begin if Exit_Code /= 0 then Raise_Checked_Error ("Command " & Image (Command, Arguments) & " exited with code " & AAA.Strings.Trim (Exit_Code'Image)); end if; end Checked_Spawn; ------------------------------- -- Checked_Spawn_And_Capture -- ------------------------------- function Checked_Spawn_And_Capture (Command : String; Arguments : AAA.Strings.Vector; Understands_Verbose : Boolean := False; Err_To_Out : Boolean := False; Valid_Exit_Codes : Code_Array := (1 => 0)) return AAA.Strings.Vector is Output : AAA.Strings.Vector; Exit_Code : constant Integer := Spawn_And_Capture (Output => Output, Command => Command, Arguments => Arguments, Understands_Verbose => Understands_Verbose, Err_To_Out => Err_To_Out); begin if (for some Code of Valid_Exit_Codes => Exit_Code = Code) then Trace.Debug ("Command exited with valid code:" & Exit_Code'Img); return Output; end if; Raise_Checked_Error ("Command " & Image (Command, Arguments) & " exited with code" & Exit_Code'Img & " and output: " & Output.Flatten (Separator => "\n")); return Output; end Checked_Spawn_And_Capture; --------------------------------- -- Unchecked_Spawn_And_Capture -- --------------------------------- function Unchecked_Spawn_And_Capture (Command : String; Arguments : AAA.Strings.Vector; Output : in out AAA.Strings.Vector; Understands_Verbose : Boolean := False; Err_To_Out : Boolean := False) return Integer is (Spawn_And_Capture (Output => Output, Command => Command, Arguments => Arguments, Understands_Verbose => Understands_Verbose, Err_To_Out => Err_To_Out)); ----------- -- Spawn -- ----------- function Spawn (Command : String; Arguments : AAA.Strings.Vector; Understands_Verbose : Boolean := False) return Integer is use GNAT.OS_Lib; Extra : constant AAA.Strings.Vector := (if Understands_Verbose and then Log_Level > Info then Empty_Vector & "-v" else Empty_Vector); Full_Args : constant AAA.Strings.Vector := Extra & Arguments; Arg_List : Argument_List_Access := To_Argument_List (Full_Args); Exit_Code : Integer; begin Trace.Detail ("Spawning: " & Image (Command, Full_Args)); -- Prepare arguments for I in Arg_List'Range loop Arg_List (I) := new String'(Full_Args (I)); end loop; if CLIC.TTY.Is_TTY and then CLIC.TTY.Color_Enabled then Ada.Text_IO.Put (Style (Dim, On)); end if; Exit_Code := GNAT.OS_Lib.Spawn (Program_Name => Locate_In_Path (Command), Args => Arg_List.all); if CLIC.TTY.Is_TTY and then CLIC.TTY.Color_Enabled then Ada.Text_IO.Put (Style (Dim, Off)); end if; Cleanup (Arg_List); if Exit_Code /= 0 then Trace.Debug ("Process errored with code" & Exit_Code'Img); end if; return Exit_Code; end Spawn; ----------------------- -- Spawn_And_Capture -- ----------------------- function Spawn_And_Capture (Output : in out AAA.Strings.Vector; Command : String; Arguments : AAA.Strings.Vector; Understands_Verbose : Boolean := False; Err_To_Out : Boolean := False) return Integer is use GNAT.OS_Lib; File : File_Descriptor; Name : String_Access; Extra : constant AAA.Strings.Vector := (if Understands_Verbose then Empty_Vector & "-v" else Empty_Vector); Full_Args : constant AAA.Strings.Vector := Extra & Arguments; Arg_List : Argument_List_Access := To_Argument_List (Full_Args); use Ada.Text_IO; Outfile : File_Type; Exit_Code : Integer; ------------- -- Cleanup -- ------------- procedure Cleanup is Ok : Boolean; begin Delete_File (Name.all, Ok); if not Ok then Trace.Error ("Failed to delete tmp file: " & Name.all); end if; Free (Name); Cleanup (Arg_List); end Cleanup; ----------------- -- Read_Output -- ----------------- procedure Read_Output is begin Open (Outfile, In_File, Name.all); while not End_Of_File (Outfile) loop Output.Append (Get_Line (Outfile)); end loop; Close (Outfile); end Read_Output; begin Create_Temp_Output_File (File, Name); if Name = null then Raise_Checked_Error ("Cannot create temporary file"); end if; Trace.Detail ("Spawning: " & Image (Command, Full_Args) & " > " & Name.all); -- Prepare arguments for I in Arg_List'Range loop Arg_List (I) := new String'(Full_Args (I)); end loop; Spawn (Program_Name => Locate_In_Path (Command), Args => Arg_List.all, Output_File_Descriptor => File, Return_Code => Exit_Code, Err_To_Out => Err_To_Out); Close (File); -- Can't raise Read_Output; if Exit_Code /= 0 then Trace.Debug ("Process errored with code" & Exit_Code'Img & " and output: " & Output.Flatten); end if; Cleanup; return Exit_Code; end Spawn_And_Capture; end Alire.OS_Lib.Subprocess; alire-1.2.1/src/alire/alire-os_lib-subprocess.ads000066400000000000000000000027171430264165500217270ustar00rootroot00000000000000with AAA.Strings; package Alire.OS_Lib.Subprocess is -- Separate from Alire.OS_Lib because not preelaborable function Locate_In_Path (Name : String) return String; -- Returns full path to Name command or "" if not found procedure Checked_Spawn (Command : String; Arguments : AAA.Strings.Vector; Understands_Verbose : Boolean := False); -- Either succeeds or raises Checked_Error with the code and output as -- info. type Code_Array is array (Positive range <>) of Integer; -- An array of exit codes that won't cause the following calls to raise function Checked_Spawn_And_Capture (Command : String; Arguments : AAA.Strings.Vector; Understands_Verbose : Boolean := False; Err_To_Out : Boolean := False; Valid_Exit_Codes : Code_Array := (1 => 0)) return AAA.Strings.Vector; -- Either succeeds or raises Checked_Error with the code and output as -- info. Output is captured and returned on success. The exit code is -- checked against the Valid_Exit_Codes. function Unchecked_Spawn_And_Capture (Command : String; Arguments : AAA.Strings.Vector; Output : in out AAA.Strings.Vector; Understands_Verbose : Boolean := False; Err_To_Out : Boolean := False) return Integer; -- Returns the output and exit code of the spawned command end Alire.OS_Lib.Subprocess; alire-1.2.1/src/alire/alire-os_lib.adb000066400000000000000000000025161430264165500175150ustar00rootroot00000000000000with GNAT.OS_Lib; package body Alire.OS_Lib is --------- -- "/" -- --------- function "/" (L, R : String) return String is (L & GNAT.OS_Lib.Directory_Separator & R); ------------- -- Bailout -- ------------- procedure Bailout (Code : Integer := 0) is begin GNAT.OS_Lib.OS_Exit (Code); end Bailout; ---------------- -- Exe_Suffix -- ---------------- function Exe_Suffix return String is -- Shenanigans needed to stay preelaborable use GNAT.OS_Lib; Suffix : String_Access := Get_Executable_Suffix; begin return S : constant String := Suffix.all do Free (Suffix); end return; end Exe_Suffix; ------------ -- Getenv -- ------------ function Getenv (Name : String; Default : String := "") return String is use GNAT.OS_Lib; Env_Access : GNAT.OS_Lib.String_Access := GNAT.OS_Lib.Getenv (Name); Env : constant String := Env_Access.all; begin Free (Env_Access); if Env = "" then return Default; else return Env; end if; end Getenv; ------------ -- Setenv -- ------------ procedure Setenv (Name : String; Value : String) is begin Trace.Debug ("Setenv " & Name & "=" & Value); GNAT.OS_Lib.Setenv (Name, Value); end Setenv; end Alire.OS_Lib; alire-1.2.1/src/alire/alire-os_lib.ads000066400000000000000000000010011430264165500175220ustar00rootroot00000000000000package Alire.OS_Lib with Preelaborate is function "/" (L, R : String) return String; -- Shorthand for path composition -- Package to enable easy use of "/" package Operators is function "/" (L, R : String) return String renames OS_Lib."/"; end Operators; procedure Bailout (Code : Integer := 0); function Exe_Suffix return String; function Getenv (Name : String; Default : String := "") return String; procedure Setenv (Name : String; Value : String); end Alire.OS_Lib; alire-1.2.1/src/alire/alire-outcomes-definite.ads000066400000000000000000000041471430264165500217140ustar00rootroot00000000000000with Alire.Errors; generic type Result is private; -- The type being returned in case of successful outcome. package Alire.Outcomes.Definite with Preelaborate is type Reference (Ptr : not null access constant Result) is limited null record with Implicit_Dereference => Ptr; type Outcome (<>) is new Alire.Outcome with private; function New_Result (R : Result) return Outcome with Post => New_Result'Result.Success; -- Wrap a Result in a successful Outcome. function Value (This : aliased Outcome) return Reference with Pre => This.Success or else raise Checked_Error with Errors.Set (This.Message); overriding function Outcome_Failure (Message : String; Report : Boolean := True) return Outcome; overriding function Outcome_Success return Outcome is (raise Program_Error with "A successful non-trivial outcome requires a result value"); overriding function Outcome_From_Exception (Ex : Ada.Exceptions.Exception_Occurrence; Msg : String := "") return Outcome; -- Create a failed outcome with given message (or default to Ex message). -- The exception is logged at debug level, and to stderr if debug mode on. private type Outcome (OK : Boolean) is new Alire.Outcome with record case OK is when True => The_Result : aliased Result; when False => null; end case; end record; function New_Result (R : Result) return Outcome is (Alire.Outcome_Success with OK => True, The_Result => R); function Value (This : aliased Outcome) return Reference is (Ptr => This.The_Result'Access); overriding function Outcome_Failure (Message : String; Report : Boolean := True) return Outcome is (Alire.Outcome_Failure (Message, Report) with OK => False); overriding function Outcome_From_Exception (Ex : Ada.Exceptions.Exception_Occurrence; Msg : String := "") return Outcome is (Alire.Outcome_From_Exception (Ex, Msg) with OK => False); end Alire.Outcomes.Definite; alire-1.2.1/src/alire/alire-outcomes-indefinite.adb000066400000000000000000000004501430264165500222130ustar00rootroot00000000000000package body Alire.Outcomes.Indefinite is --------------- -- To_Holder -- --------------- function To_Holder (R : Result) return Definites.List is begin return L : Definites.List do L.Append (R); end return; end To_Holder; end Alire.Outcomes.Indefinite; alire-1.2.1/src/alire/alire-outcomes-indefinite.ads000066400000000000000000000051511430264165500222370ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; with Alire.Errors; -- See documentation in the Definites package. generic type Result (<>) is private; package Alire.Outcomes.Indefinite with Preelaborate is type Reference (Ptr : not null access constant Result) is limited null record with Implicit_Dereference => Ptr; type Outcome (<>) is new Alire.Outcome with private; function New_Result (R : Result) return Outcome with Post => New_Result'Result.Success; function Value (This : aliased Outcome) return Reference with Pre => This.Success or else raise Checked_Error with Errors.Set (This.Message); overriding function Outcome_Failure (Message : String; Report : Boolean := True) return Outcome; overriding function Outcome_Success return Outcome is (raise Program_Error with "A successful non-trivial outcome requires a result"); overriding function Outcome_From_Exception (Ex : Ada.Exceptions.Exception_Occurrence; Msg : String := "") return Outcome; private use type Ada.Containers.Count_Type; package Definites is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Result); -- Indefinite_Holders raise a tampering exception on finalization. Since -- the use is not changed with this list I conclude that it is a bug in -- Indefinite_Holders. Also, the exception is raised even when there are no -- references left to the container. function To_Holder (R : Result) return Definites.List; type Outcome (OK : Boolean) is new Alire.Outcome with record case OK is when True => The_Result : Definites.List; when False => null; end case; end record with Type_Invariant => (Outcome.OK and then Outcome.The_Result.Length = 1) or else not Outcome.OK; function New_Result (R : Result) return Outcome is (Alire.Outcome_Success with OK => True, The_Result => To_Holder (R)); function Value (This : aliased Outcome) return Reference is (Ptr => This.The_Result.Constant_Reference (This.The_Result.First).Element); overriding function Outcome_Failure (Message : String; Report : Boolean := True) return Outcome is (Alire.Outcome_Failure (Message, Report) with OK => False); overriding function Outcome_From_Exception (Ex : Ada.Exceptions.Exception_Occurrence; Msg : String := "") return Outcome is (Alire.Outcome_From_Exception (Ex, Msg) with OK => False); end Alire.Outcomes.Indefinite; alire-1.2.1/src/alire/alire-outcomes.ads000066400000000000000000000006201430264165500201170ustar00rootroot00000000000000package Alire.Outcomes with Preelaborate is -- The generic children of this package allow to tie together an Outcome -- and a result value. This ensures that the result value cannot be used in -- case of Outcome_Failure, or bugs where the result is not set despite -- returning an Outcome_Success. -- Both Definite and Indefinite share the same operations. end Alire.Outcomes; alire-1.2.1/src/alire/alire-paths.ads000066400000000000000000000014621430264165500174050ustar00rootroot00000000000000with Alire.OS_Lib; use Alire.OS_Lib.Operators; package Alire.Paths with Preelaborate is Crate_File_Name : constant String := "alire.toml"; -- Name of the manifest file in a regular workspace Cache_Folder_Inside_Working_Folder : constant Relative_Path := "cache"; Deps_Folder_Inside_Cache_Folder : constant Relative_Path := "dependencies"; Temp_Folder_Inside_Working_Folder : constant Relative_Path := "tmp"; function Working_Folder_Inside_Root return Relative_Path is ("alire"); -- Folder within a working release that will contain metadata/build files, -- dependency releases, and session. Scripts_Graph_Easy : constant String := "graph-easy"; -- Script for ASCII graphs private Crate_File_Extension_With_Dot : constant String := ".toml"; end Alire.Paths; alire-1.2.1/src/alire/alire-platforms-common.adb000066400000000000000000000040601430264165500215370ustar00rootroot00000000000000with AAA.Enum_Tools; with Alire.OS_Lib.Subprocess; with System; package body Alire.Platforms.Common is Arch_Detected : Boolean := False; Arch_Value : Architectures := Architecture_Unknown; --------------------------- -- Machine_Hardware_Name -- --------------------------- function Machine_Hardware_Name return Architectures is begin if Arch_Detected then return Arch_Value; end if; -- Custom detection for Windows without requiring msys2 if On_Windows then Arch_Detected := True; case Standard.System.Word_Size is when 64 => Arch_Value := X86_64; when others => Arch_Value := Architecture_Unknown; end case; return Arch_Value; end if; -- Detection in unix-like platforms Detect : declare function Is_Known_Arch is new AAA.Enum_Tools.Is_Valid (Extended_Architectures); Output : AAA.Strings.Vector; -- uname is part of coreutils, so it should be available in -- linuxes/msys2. Code : constant Integer := OS_Lib.Subprocess.Unchecked_Spawn_And_Capture (Command => "uname", Arguments => AAA.Strings.To_Vector ("-m"), Output => Output); Name : constant String := Output.Flatten; begin Arch_Detected := True; if Code /= 0 then Trace.Debug ("uname failed with code: " & AAA.Strings.Trim (Code'Image)); else if Is_Known_Arch (Name) then Trace.Debug ("uname known machine string is: " & Name); Arch_Value := Arch_Mapping (Extended_Architectures'Value (Name)); else Trace.Debug ("uname unknown machine string is: " & Name); end if; end if; return Arch_Value; end Detect; end Machine_Hardware_Name; end Alire.Platforms.Common; alire-1.2.1/src/alire/alire-platforms-common.ads000066400000000000000000000024211430264165500215570ustar00rootroot00000000000000with Alire.OS_Lib; private with GNATCOLL.OS.Constants; private package Alire.Platforms.Common is -- Reusable code from both Linux/macOS or other several OSes. Intended for -- use from the platform-specific bodies. use OS_Lib.Operators; -- Bring in "/" for paths function Machine_Hardware_Name return Architectures; -- As reported by uname, already turned into our architecture enum function On_Windows return Boolean; -- Says if we are on Windows ---------------------- -- XDG_Cache_Folder -- ---------------------- function XDG_Cache_Folder return String is (OS_Lib.Getenv ("XDG_CACHE_HOME", Default => OS_Lib.Getenv ("HOME") / ".cache") / "alire"); ----------------------- -- XDG_Config_Folder -- ----------------------- function XDG_Config_Folder return String is (OS_Lib.Getenv ("XDG_CONFIG_HOME", Default => OS_Lib.Getenv ("HOME", Default => "/tmp") / ".config") / "alire"); private ---------------- -- On_Windows -- ---------------- pragma Warnings (Off, "condition is always"); -- Silence warning of OS check function On_Windows return Boolean is (GNATCOLL.OS.Constants.OS in GNATCOLL.OS.Windows); pragma Warnings (On); end Alire.Platforms.Common; alire-1.2.1/src/alire/alire-platforms-current.ads000066400000000000000000000070601430264165500217550ustar00rootroot00000000000000limited with Alire.Environment; private with Alire.OS_Lib.Subprocess; private with Alire.Platforms.Common; with Alire.Properties; private with Alire.Properties.Platform; private with System; package Alire.Platforms.Current is -- This spec must be fulfilled by bodies for each different OS we support ------------------- -- Low level stuff function Distribution_Root return Absolute_Path; -- Root directory of the distribution; on unixes it is "/", on Windows it -- is the root of our msys2 installation. procedure Load_Environment (Ctx : in out Alire.Environment.Context); -- Set environment variables from the platform. Used by Windows to -- initialize msys2 environment. ----------------------- -- Self identification function Detected_Distribution return Platforms.Distributions; -- Must return the actual detected distribution. Generally, client code -- should use Distribution below. function Operating_System return Platforms.Operating_Systems; -------------------------------- -- Portable derived utilities -- -------------------------------- -- Beyond this point, nothing has to be done in the body Disable_Distribution_Detection : Boolean := False with Atomic; function Distribution return Platforms.Distributions; -- Cooked distribution that may return Unknown if detection was disabled -- via config. function Distribution_Is_Known return Boolean is (Platforms."/=" (Distribution, Platforms.Distro_Unknown)); function Host_Architecture return Platforms.Architectures; function Target return Platforms.Targets; function Toolchain return Platforms.Toolchains; function Word_Size return Platforms.Word_Sizes; function Properties return Alire.Properties.Vector; -- Return the platform information wrapped in a vector of properties useful -- for dynamic expression resolution in indices/releases. private ------------------ -- Distribution -- ------------------ function Distribution return Platforms.Distributions is (if Disable_Distribution_Detection then Platforms.Distro_Unknown else Detected_Distribution); ----------------------- -- Host_Architecture -- ----------------------- function Host_Architecture return Platforms.Architectures renames Common.Machine_Hardware_Name; ---------------- -- Properties -- ---------------- package Platprop renames Alire.Properties.Platform; use all type Alire.Properties.Vector; function Properties return Alire.Properties.Vector is (Platprop.Distribution_Is (Distribution) and Platprop.Host_Arch_Is (Host_Architecture) and Platprop.System_Is (Operating_System) and Platprop.Target_Is (Target) and Platprop.Toolchain_Is (Toolchain) and Platprop.Word_Size_Is (Word_Size)); ------------ -- Target -- ------------ function Target return Platforms.Targets is (Native); --------------- -- Toolchain -- --------------- function Toolchain return Platforms.Toolchains is (if Distribution /= Distro_Unknown and then Alire.OS_Lib.Subprocess.Locate_In_Path ("gprconfig") = "/usr/bin/gprconfig" then Alire.Platforms.System else Alire.Platforms.User); --------------- -- Word_Size -- --------------- function Word_Size return Alire.Platforms.Word_Sizes is (case Standard.System.Word_Size is when 32 => Alire.Platforms.Bits_32, when 64 => Alire.Platforms.Bits_64, when others => Alire.Platforms.Bits_Unknown); end Alire.Platforms.Current; alire-1.2.1/src/alire/alire-platforms-folders.ads000066400000000000000000000014351430264165500217310ustar00rootroot00000000000000package Alire.Platforms.Folders is -- This spec must be fulfilled by bodies for each different OS we support function Config return String; -- Folder where alire will store its global configuration, indexes, and -- any other global data. Deleting it is akin to running alr afresh for -- the first time. -- On Linux/macOS it is ${XDG_CONFIG_HOME:-$HOME/.config}/alire -- On Windows it is $Homedrive:$Homepath\.config\alire function Cache return String; -- Folder for dependencies, global toolchains, and any other info that is -- not critical to lose. Can be deleted freely, it's repopulated on-demand. -- On Linux/macOS it is ${XDG_CACHE_HOME:-$HOME/.cache}/alire -- On Windows it is $Homedrive:$Homepath\.cache\alire end Alire.Platforms.Folders; alire-1.2.1/src/alire/alire-platforms.ads000066400000000000000000000055211430264165500202750ustar00rootroot00000000000000package Alire.Platforms with Preelaborate is -- Platform information necessary for some releases type Extended_Architectures is (AMD64, -- Equivalent to X86_64 (FreeBSD) ARM64, -- Equivalent to AARCH64 End_Of_Duplicates, -- Up to this point, these are architectures that we want to rename to -- some of the following because they are equivalent. ARM, AARCH64, AARCH64_BE, I386, I686, X86_64, Architecture_Unknown); subtype Architectures is Extended_Architectures range Extended_Architectures'Succ (End_Of_Duplicates) .. Architecture_Unknown; -- See e.g. https://stackoverflow.com/a/45125525/761390 type Operating_Systems is (FreeBSD, Linux, MacOS, Windows, OS_Unknown); subtype Known_Operating_Systems is Operating_Systems range Operating_Systems'First .. Operating_Systems'Pred (OS_Unknown); type Targets is (Native, Unknown_Cross_Target); -- Minimal preparations for cross-compiling type Distributions is (Debian, Ubuntu, Msys2, Arch, Rhel, -- RedHat Enterprise Linux Centos, Fedora, Distro_Unknown); subtype Known_Distributions is Distributions range Distributions'First .. Distributions'Pred (Distributions'Last); type Word_Sizes is (Bits_32, Bits_64, Bits_Unknown); type Package_Managers is (Apt, Pacman, Yum, Dnf, Packager_Unknown); Distro_Manager : constant array (Distributions) of Package_Managers := (Debian | Ubuntu => Apt, Msys2 | Arch => Pacman, Rhel => Yum, Centos | Fedora => Dnf, Distro_Unknown => Packager_Unknown); type Toolchains is (System, -- Provided through system packages, able to use other -- Ada system packages User -- Provided by the user ); type Shells is (Unix, PowerShell, WinCmd); private -- Should be in sync with testsuite/drivers/helpers.py#L106 function Arch_Mapping (Arch : Extended_Architectures) return Architectures is (case Arch is when AMD64 => X86_64, when ARM64 => AARCH64, when Architectures => Arch, when others => raise Program_Error with "Mapping missing for given architecture: " & Arch'Image); end Alire.Platforms; alire-1.2.1/src/alire/alire-policies.ads000066400000000000000000000012641430264165500200750ustar00rootroot00000000000000package Alire.Policies with Preelaborate is type For_Index_Merging is (Merge_Priorizing_Existing -- Merge two crates but any existing releases will be kept over ones -- with the same version when adding more release. This is the only -- behavior existing since multiple indexes were introduced. -- -- For the case of externals, the shared properties of the first time a -- crate externals are added take precedence as well. -- We might envision other policies, like not allowing releases from two -- indexes at the same time, keeping only the first seen or overriding -- with the last seen. ); end Alire.Policies; alire-1.2.1/src/alire/alire-properties-actions-executor.adb000066400000000000000000000063621430264165500237370ustar00rootroot00000000000000with Alire.Directories; with Alire.OS_Lib.Subprocess; with Alire.Properties.Actions.Runners; with Alire.Utils.TTY; package body Alire.Properties.Actions.Executor is ----------------- -- Execute_Run -- ----------------- procedure Execute_Run (This : Runners.Run; Capture : Boolean; Err_To_Out : Boolean; Code : out Integer; Output : out AAA.Strings.Vector; Prefix : AAA.Strings.Vector := AAA.Strings.Empty_Vector) is use Directories; use OS_Lib; Guard : Directories.Guard (Enter (This.Working_Folder)) with Unreferenced; -- This presumes the action is being run from the crate root. This is -- true for post-build root crate actions, post-fetch deployments, -- test runs... Cmd : constant AAA.Strings.Vector := Prefix.Append (This.Command_Line); begin if Capture then Code := Subprocess.Unchecked_Spawn_And_Capture (Command => Cmd.First_Element, Arguments => Cmd.Tail, Output => Output, Understands_Verbose => False, Err_To_Out => Err_To_Out); else Subprocess.Checked_Spawn (Command => Cmd.First_Element, Arguments => Cmd.Tail, Understands_Verbose => False); end if; end Execute_Run; --------------------- -- Execute_Actions -- --------------------- procedure Execute_Actions (Release : Releases.Release; Env : Properties.Vector; Moment : Moments) is Unused_Code : Integer; Unused_Output : AAA.Strings.Vector; begin Execute_Actions (Release => Release, Env => Env, Moment => Moment, Capture => False, Err_To_Out => False, Code => Unused_Code, Output => Unused_Output); end Execute_Actions; --------------------- -- Execute_Actions -- --------------------- procedure Execute_Actions (Release : Releases.Release; Env : Properties.Vector; Moment : Moments; Capture : Boolean; Err_To_Out : Boolean; Code : out Integer; Output : out AAA.Strings.Vector; Prefix : AAA.Strings.Vector := AAA.Strings.Empty_Vector) is Now : Releases.Moment_Array := (others => False); begin Now (Moment) := True; -- Cannot be done in the initialization if not Release.On_Platform_Actions (Env, Now).Is_Empty then Put_Info ("Running " & Utils.TTY.Name (AAA.Strings.To_Lower_Case (Moment'Image)) & " actions for " & Release.Milestone.TTY_Image & "..."); end if; for Act of Release.On_Platform_Actions (Env, Now) loop Trace.Detail ("Running action: " & Act.Image); Execute_Run (This => Runners.Run (Act), Capture => Capture, Err_To_Out => Err_To_Out, Code => Code, Output => Output, Prefix => Prefix); end loop; end Execute_Actions; end Alire.Properties.Actions.Executor; alire-1.2.1/src/alire/alire-properties-actions-executor.ads000066400000000000000000000017541430264165500237600ustar00rootroot00000000000000with AAA.Strings; with Alire.Releases; package Alire.Properties.Actions.Executor is procedure Execute_Actions (Release : Releases.Release; Env : Properties.Vector; Moment : Moments); -- Run Release actions that apply to a given environment. IMPORTANT: the -- working directory at the moment of this call should be the release root. procedure Execute_Actions (Release : Releases.Release; Env : Properties.Vector; Moment : Moments; Capture : Boolean; Err_To_Out : Boolean; Code : out Integer; Output : out AAA.Strings.Vector; Prefix : AAA.Strings.Vector := AAA.Strings.Empty_Vector); -- More general invocation. Prefix is prepended to the command (e.g., for -- dockerization). When capture is true, the rest of parameters are also -- used; otherwise output goes untouched straight to console. end Alire.Properties.Actions.Executor; alire-1.2.1/src/alire/alire-properties-actions-runners.adb000066400000000000000000000116541430264165500235750ustar00rootroot00000000000000with AAA.Enum_Tools; package body Alire.Properties.Actions.Runners is ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Run) return TOML.TOML_Value is use TOML_Adapters; function Tomify is new TOML_Adapters.Tomify_Enum (Moments); Arr : constant TOML.TOML_Value := TOML.Create_Array; -- Actions are output as an array of tables, so we return an array -- containing the single table of this action. Table : constant TOML.TOML_Value := TOML.Create_Table; begin Table.Set (TOML_Keys.Action_Type, Tomify (This.Moment)); Table.Set (TOML_Keys.Action_Command, +This.Command_Line); if This.Working_Folder /= "" then Table.Set (TOML_Keys.Action_Folder, +This.Working_Folder); end if; if This.Name /= "" then Table.Set (TOML_Keys.Name, +This.Name); end if; Arr.Append (Table); return Arr; end To_TOML; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is -- Actions come in a TOML array. use Conditional.For_Properties; use TOML; ---------------- -- Create_One -- ---------------- function Create_One (Raw : TOML.TOML_Value; Index : Positive) return Conditional.Properties is From : constant TOML_Adapters.Key_Queue := From_TOML.From.Descend (Raw, "action #" & AAA.Strings.Trim (Index'Image)); Kind : TOML_Value; Command : TOML_Value; Name : TOML_Value; Has_Name : Boolean; Path : TOML_Value; Has_Path : Boolean; Moment : Moments; function Is_Valid is new AAA.Enum_Tools.Is_Valid (Moments); begin if not From.Pop (TOML_Keys.Action_Type, Kind) then From.Checked_Error ("action type missing"); elsif not From.Pop (TOML_Keys.Action_Command, Command) then From.Checked_Error ("action command missing"); end if; Has_Path := From.Pop (TOML_Keys.Action_Folder, Path); -- The path key for an action is optional Has_Name := From.Pop (TOML_Keys.Name, Name); -- Name is optional but for custom actions if Kind.Kind /= TOML_String or else (Has_Path and then Path.Kind /= TOML_String) then From.Checked_Error ("actions type, and folder must be strings"); end if; if not Is_Valid (TOML_Adapters.Adafy (Kind.As_String)) then From.Checked_Error ("action type is invalid: " & Kind.As_String); else Moment := Moments'Value (TOML_Adapters.Adafy (Kind.As_String)); end if; if Moment = On_Demand and then not Has_Name then From.Checked_Error ("on-demand actions require a name"); end if; if Has_Name and then (Name.Kind /= TOML_String or else Name.As_String not in Action_Name) then From.Checked_Error ("action name must be a string made of " & "'a' .. 'z', '0' .. '9', '-', starting with a letter and not " & "ending with a dash nor containing consecutive dashes" & ASCII.LF & "Offending name is: " & Name.As_String); end if; if Command.Kind /= TOML_Array or else Command.Length = 0 or else Command.Item (1).Kind /= TOML_String then From.Checked_Error ("actions command must be an array of string(s)"); end if; From.Report_Extra_Keys; return New_Value (New_Run (Moment => Moment, Name => (if Has_Name then Name.As_String else ""), Relative_Command_Line => TOML_Adapters.To_Vector (TOML_Adapters.To_Array (Command)), Working_Folder => (if Has_Path then Path.As_String else "."))); end Create_One; Raw : constant TOML_Value := From.Pop; begin if Raw.Kind = TOML_Table then return Create_One (Raw, 1); end if; -- It should be an array that we we'll load one by one: if Raw.Kind /= TOML_Array then raise Checked_Error with "actions must be a table array"; end if; -- An empty array can be used for actions: if Raw.Length = 1 and then Raw.Item (1).Keys'Length = 0 then Trace.Debug ("Skipping empty action array"); return Conditional.No_Properties; end if; return Props : Conditional.Properties do for I in 1 .. Raw.Length loop Props := Props and Create_One (Raw.Item (I), I); end loop; end return; end From_TOML; end Alire.Properties.Actions.Runners; alire-1.2.1/src/alire/alire-properties-actions-runners.ads000066400000000000000000000055201430264165500236110ustar00rootroot00000000000000with Alire.Utils; package Alire.Properties.Actions.Runners with Preelaborate is -- A Run action executes custom commands type Run (<>) is new Action with private; -- Encapsulates the execution of an external command function Command_Line (This : Run) return AAA.Strings.Vector; function Working_Folder (This : Run) return String; overriding function To_TOML (This : Run) return TOML.TOML_Value; function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; private subtype Action_Name is String with Dynamic_Predicate => (for all Char of Action_Name => Char in 'a' .. 'z' | '0' .. '9' | '-') and then Action_Name'Length > 1 and then Action_Name (Action_Name'First) in 'a' .. 'z' and then Action_Name (Action_Name'Last) /= '-' and then (for all I in Action_Name'First .. Action_Name'Last - 1 => (if Action_Name (I) = '-' then Action_Name (I + 1) /= '-')); type Run (Moment : Moments; Folder_Len : Natural; Name_Len : Natural) is new Action (Moment) with record Name : String (1 .. Name_Len); -- Optional, except for custom actions, which require a name. Relative_Command_Line : AAA.Strings.Vector; Working_Folder : Any_Path (1 .. Folder_Len); end record with Type_Invariant => (Name = "" or else Name in Action_Name) and then (if Moment = On_Demand then Name /= ""); overriding function Image (This : Run) return String is (AAA.Strings.To_Mixed_Case (This.Moment'Img) & (if This.Name /= "" then " (" & This.Name & ")" else "") & " run: ${CRATE_DIR}" & (if This.Working_Folder /= "" then "/" else "") & This.Working_Folder & "/" & This.Relative_Command_Line.Flatten); overriding function To_YAML (This : Run) return String is (AAA.Strings.To_Mixed_Case (This.Moment'Img) & " run: " & (if This.Working_Folder /= "" then "/" else "") & This.Working_Folder & "/" & This.Relative_Command_Line.Flatten); function New_Run (Moment : Moments; Name : String; Relative_Command_Line : AAA.Strings.Vector; Working_Folder : Any_Path) return Run'Class -- Working folder will be entered for execution -- Relative command-line must consider being in working folder is (Run' (Moment, Working_Folder'Length, Name'Length, Name, Relative_Command_Line, Utils.To_Native (Working_Folder))); function Command_Line (This : Run) return AAA.Strings.Vector is (This.Relative_Command_Line); function Working_Folder (This : Run) return String is (This.Working_Folder); end Alire.Properties.Actions.Runners; alire-1.2.1/src/alire/alire-properties-actions.adb000066400000000000000000000014651430264165500221020ustar00rootroot00000000000000with Alire.Properties.Actions.Runners; package body Alire.Properties.Actions is ------------- -- Execute -- ------------- procedure Execute (This : Action; Implementer : access procedure (This : Action'Class)) is begin Implementer (This); end Execute; -- We redispatch TOML serialization to the Run class, which currently -- implements all of it, being the only existing Action class. ------------- -- To_TOML -- ------------- function To_TOML_CW (This : Action'Class) return TOML.TOML_Value is (This.To_TOML); --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is (Runners.From_TOML (From)); end Alire.Properties.Actions; alire-1.2.1/src/alire/alire-properties-actions.ads000066400000000000000000000053011430264165500221140ustar00rootroot00000000000000with Alire.Conditional; with Alire.TOML_Adapters; with Alire.TOML_Keys; package Alire.Properties.Actions with Preelaborate is type Moments is ( Post_Fetch, -- After being downloaded/on dependency updates Pre_Build, -- Before being compiled Post_Build, -- After being compiled Test, -- On demand for testing of releases On_Demand -- On demand from command-line ); -- The "lifecycle" of releases in Alire is described here. For all pre/post -- actions, dependencies are visited in a safe order, and the root is -- visited last. E.g., for the following dependency graph: -- R +-> A --> B --| -- |-> D --------+-> C -- C will be visited first. Then B and D will be visited, potentially -- simultaneously. Then, A will be visited, and then R will be visited. -- In the following descriptions, "for all releases" includes releases -- user-pinned as a link to a folder/remote. -- * Post_Fetch is triggered for all releases whenever there is a change in -- dependencies, which includes just after retrieval via `alr get` or `alr -- with`. In addition, running `alr update` will also trigger Post_Fetch, -- even when there are no updates to apply. -- * Pre_Build is triggered for all releases whenever a build is going to -- happen, which currently is on `alr build`, `alr run`, `alr get --build`. -- * Post_Build is triggered for all releases after a build completes. -- * Test is triggered only for the root crate after the crate build (and -- after all Post_Build complete), only when `alr test` is run. type Action (<>) is abstract new Properties.Property with private; -- Action was abstract in case we ever need other kinds of actions than -- running custom commands (see the Run action). The need hasn't arisen -- yet. overriding function Key (This : Action) return String is (TOML_Keys.Action); function Moment (This : Action) return Moments; procedure Execute (This : Action; Implementer : access procedure (This : Action'Class)); -- This indirection is meant to keep this package preelaborable, as the -- rest of the properties hierarchy. -- Note that the TOML crate spec does not reflect the type/moment -- difference; moments are used as the class of the action. function To_TOML_CW (This : Action'Class) return TOML.TOML_Value; function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; private type Action (Moment : Moments) is abstract new Properties.Property with null record; function Moment (This : Action) return Moments is (This.Moment); end Alire.Properties.Actions; alire-1.2.1/src/alire/alire-properties-bool.adb000066400000000000000000000041051430264165500213670ustar00rootroot00000000000000package body Alire.Properties.Bool is --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is Value : TOML.TOML_Value; Key : constant String := From.Pop (Value); ------------------ -- Key_To_Label -- ------------------ function Key_To_Label (K : String) return Labels is begin -- TODO: instead of this inefficient O(n) lookup, have a map. for L in Labels loop if Bool.Key (L) = K then return L; end if; end loop; From.Checked_Error ("Key is not a valid boolean property: " & K); end Key_To_Label; -- For conditional loading, we use specific conditional loaders that -- only recognize the property being loaded: begin return Props : Conditional.Properties do declare Val : constant TOML.TOML_Value := TOML_Adapters.To_Array (Value); -- We process the same way single values and arrays of values -- (since they get converted into individual properties). begin if Val.Length > 1 then raise Checked_Error with "Expected single value for " & Key; end if; if Val.Item (1).Kind /= TOML_Boolean then raise Checked_Error with "Expected boolean value for " & Key; end if; declare L : constant Property := New_Property (Key_To_Label (Key), Val.Item (1).As_Boolean); use all type Conditional.Properties; begin -- Labeled property is valid and added to the release props. Props := Props and Conditional.For_Properties.New_Value (L); end; end; end return; exception when E : others => Log_Exception (E); raise Checked_Error with "Cannot read valid property from " & Key; end From_TOML; end Alire.Properties.Bool; alire-1.2.1/src/alire/alire-properties-bool.ads000066400000000000000000000034441430264165500214150ustar00rootroot00000000000000with Alire.Conditional; with Alire.TOML_Adapters; with Alire.TOML_Keys; package Alire.Properties.Bool with Preelaborate is type Labels is (Auto_GPR_With -- Boolean to specify if a crate is compatible with the auto-gpr-with -- feature. ); type Property is new Properties.Property with private; function New_Property (Name : Labels; V : Boolean) return Property; overriding function Image (V : Property) return String; overriding function To_YAML (V : Property) return String; overriding function Key (V : Property) return String; function Value (V : Property) return Boolean; function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; private function Key (L : Labels) return String is (case L is when Auto_GPR_With => TOML_Keys.Auto_GPR_With); type Property is new Properties.Property with record Name : Labels; Value : Boolean; end record; overriding function To_TOML (V : Property) return TOML.TOML_Value; function New_Property (Name : Labels; V : Boolean) return Property is (Name => Name, Value => V); overriding function Image (V : Property) return String is (AAA.Strings.To_Mixed_Case (V.Name'Img) & ": " & V.To_YAML); overriding function To_YAML (V : Property) return String is (Key (V.Name) & "=" & (if V.Value then "true" else "false")); overriding function To_TOML (V : Property) return TOML.TOML_Value is (TOML.Create_Boolean (V.Value)); overriding function Key (V : Property) return String is (Key (V.Name)); function Value (V : Property) return Boolean is (V.Value); end Alire.Properties.Bool; alire-1.2.1/src/alire/alire-properties-build_profiles.adb000066400000000000000000000103721430264165500234410ustar00rootroot00000000000000with Alire.TOML_Keys; with Alire.Utils.Switches; use Alire.Utils.Switches; package body Alire.Properties.Build_Profiles is ----------- -- Image -- ----------- overriding function Image (This : Variable) return String is ("Build Profile: "); --------- -- Key -- --------- overriding function Key (This : Variable) return String is pragma Unreferenced (This); begin return TOML_Keys.Build_Profiles; end Key; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is use type Conditional.Properties; use TOML; Env : TOML_Value; Var : Variable; begin if From.Unwrap.Kind /= TOML_Table then From.Checked_Error ("Build: table with assignments expected, but got: " & From.Unwrap.Kind'Img); end if; if From.Pop_Single_Table (Env, TOML_Table) /= TOML_Keys.Build_Profiles then raise Program_Error; -- Can't happen, unless the dispatch to us itself was erroneous end if; Var.T := Env.Clone; -- Check that the data is valid for Crate of Env.Keys loop declare Crate_Str : constant String := +Crate; Profile : constant TOML_Value := Env.Get (Crate); begin if Profile.Kind /= TOML_String then From.Checked_Error ("Should be string"); end if; declare Profile_Str : constant String := Profile.As_String; begin if Crate_Str = "*" then if Var.Wildcard_Found then From.Checked_Error ("Multiple definition of wildcard (""*"")" & " build profile"); else Var.Wildcard_Found := True; end if; elsif not Is_Valid_Name (Crate_Str) then From.Checked_Error ("Invalid crate name for build profile (" & Error_In_Name (Crate_Str) & ")"); else declare Unused : Profile_Kind; begin Unused := Profile_Kind'Value (Profile_Str); exception when Constraint_Error => From.Checked_Error ("Invalid build profile name: '" & Profile_Str & "' for '" & Crate_Str & "'"); end; end if; end; Env.Unset (+Crate); end; end loop; return Props : Conditional.Properties do Props := Props and Var; end return; end From_TOML; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Variable) return TOML.TOML_Value is begin return This.T.Clone; end To_TOML; ------------- -- To_YAML -- ------------- overriding function To_YAML (This : Variable) return String is ("Build profile: []"); --------------- -- Selection -- --------------- function Selection (This : Variable) return Profile_Selection_Maps.Map is begin return Result : Profile_Selection_Maps.Map do for Crate of This.T.Keys loop if (+Crate) /= "*" then declare Val : constant TOML.TOML_Value := This.T.Get (Crate); begin Result.Insert (+(+Crate), Profile_Kind'Value (Val.As_String)); end; end if; end loop; end return; end Selection; ------------------ -- Has_Wildcard -- ------------------ function Has_Wildcard (This : Variable) return Boolean is begin return This.Wildcard_Found; end Has_Wildcard; -------------- -- Wildcard -- -------------- function Wildcard (This : Variable) return Profile_Kind is begin for Crate of This.T.Keys loop if (+Crate) = "*" then return Profile_Kind'Value (This.T.Get (Crate).As_String); end if; end loop; raise Program_Error; end Wildcard; end Alire.Properties.Build_Profiles; alire-1.2.1/src/alire/alire-properties-build_profiles.ads000066400000000000000000000023661430264165500234660ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; with Alire.Conditional; with Alire.TOML_Adapters; with Alire.Utils.Switches; private with TOML; package Alire.Properties.Build_Profiles with Preelaborate is use type Utils.Switches.Profile_Kind; package Profile_Selection_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Utils.Switches.Profile_Kind); type Variable is new Property with private; function Selection (This : Variable) return Profile_Selection_Maps.Map; function Has_Wildcard (This : Variable) return Boolean; function Wildcard (This : Variable) return Utils.Switches.Profile_Kind with Pre => This.Has_Wildcard; -- Inherited operations overriding function Image (This : Variable) return String; overriding function Key (This : Variable) return String; function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; overriding function To_TOML (This : Variable) return TOML.TOML_Value; overriding function To_YAML (This : Variable) return String; private type Variable is new Property with record Wildcard_Found : Boolean := False; T : TOML.TOML_Value; end record; end Alire.Properties.Build_Profiles; alire-1.2.1/src/alire/alire-properties-build_switches.adb000066400000000000000000000245241430264165500234530ustar00rootroot00000000000000with Alire.TOML_Keys; with TOML; use TOML; package body Alire.Properties.Build_Switches is -------------- -- Modifier -- -------------- function Modifier (This : Variable) return Profile_Modifier is begin return This.Modif; end Modifier; ----------- -- Image -- ----------- overriding function Image (This : Variable) return String is ("Build Switches: "); --------- -- Key -- --------- overriding function Key (This : Variable) return String is pragma Unreferenced (This); begin return TOML_Keys.Build_Switches; end Key; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue; Cat : Switches_Categories; T : TOML.TOML_Value) return Switches_Modifier is Result : Switches_Modifier (Cat); List : Switch_List; begin if T.Kind = TOML_Array then if (for some Index in 1 .. T.Length => T.Item (Index).Kind /= TOML_String) then From.Checked_Error ("At least one element on the switch list is not a string"); end if; -- We have a custom list of switches for Index in 1 .. T.Length loop List.Append (T.Item (Index).As_String); end loop; case Cat is when Optimization => Result.Optimization := (Custom, List); when Debug_Info => Result.Debug_Info := (Custom, List); when Compile_Checks => Result.Compile_Checks := (Custom, List); when Runtime_Checks => Result.Runtime_Checks := (Custom, List); when Contracts => Result.Contracts := (Custom, List); when Style_Checks => Result.Style_Checks := (Custom, List); when Ada_Version => Result.Ada_Version := (Custom, List); end case; elsif T.Kind = TOML_String then begin case Cat is when Optimization => declare K : constant Optimization_Kind := Optimization_Kind'Value (T.As_String); begin Result.Optimization := (case K is when Performance => (Kind => Performance), when Size => (Kind => Size), when Debug => (Kind => Debug), when Custom => raise Constraint_Error); end; when Debug_Info => declare K : constant Debug_Info_Kind := Debug_Info_Kind'Value (T.As_String); begin Result.Debug_Info := (case K is when No => (Kind => No), when Yes => (Kind => Yes), when Custom => raise Constraint_Error); end; when Runtime_Checks => declare K : constant Runtime_Checks_Kind := Runtime_Checks_Kind'Value (T.As_String); begin Result.Runtime_Checks := (case K is when None => (Kind => None), when Default => (Kind => Default), when Overflow => (Kind => Overflow), when Everything => (Kind => Everything), when Custom => raise Constraint_Error); end; when Compile_Checks => declare K : constant Compile_Checks_Kind := Compile_Checks_Kind'Value (T.As_String); begin Result.Compile_Checks := (case K is when None => (Kind => None), when Warnings => (Kind => Warnings), when Errors => (Kind => Errors), when Custom => raise Constraint_Error); end; when Contracts => declare K : constant Contracts_Kind := Contracts_Kind'Value (T.As_String); begin Result.Contracts := (case K is when No => (Kind => No), when Yes => (Kind => Yes), when Custom => raise Constraint_Error); end; when Style_Checks => declare K : constant Style_Checks_Kind := Style_Checks_Kind'Value (T.As_String); begin Result.Style_Checks := (case K is when No => (Kind => No), when Yes => (Kind => Yes), when Custom => raise Constraint_Error); end; when Ada_Version => declare K : constant Ada_Version_Kind := Ada_Version_Kind'Value (T.As_String); begin Result.Ada_Version := (case K is when Compiler_Default => (Kind => Compiler_Default), when Ada83 => (Kind => Ada83), when Ada95 => (Kind => Ada95), when Ada05 => (Kind => Ada05), when Ada12 => (Kind => Ada12), when Ada2022 => (Kind => Ada2022), when GNAT_Extensions => (Kind => GNAT_Extensions), when Custom => raise Constraint_Error); end; end case; exception when Constraint_Error => From.Checked_Error ("Invalid switch selector '" & T.As_String & "' for category '" & Cat'Img & "'"); end; else From.Checked_Error ("String or array of string expected"); end if; return Result; end From_TOML; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue; T : TOML.TOML_Value) return Switches_Modifier_Lists.List is List : Switches_Modifier_Lists.List; begin if T.Kind /= TOML_Table then raise Program_Error; end if; for Key of T.Keys loop declare Cat : Switches_Categories; begin Cat := Switches_Categories'Value (+Key); List.Append (From_TOML (From, Cat, T.Get (Key))); exception when Constraint_Error => From.Checked_Error ("Invalid switch category: '" & (+Key) & "'"); end; end loop; return List; end From_TOML; ----------- -- Apply -- ----------- procedure Apply (Sw : in out Switches_Configuration; M : Switches_Modifier) is begin case M.Cat is when Optimization => Sw.Optimization := M.Optimization; when Debug_Info => Sw.Debug_Info := M.Debug_Info; when Runtime_Checks => Sw.Runtime_Checks := M.Runtime_Checks; when Compile_Checks => Sw.Compile_Checks := M.Compile_Checks; when Contracts => Sw.Contracts := M.Contracts; when Style_Checks => Sw.Style_Checks := M.Style_Checks; when Ada_Version => Sw.Ada_Version := M.Ada_Version; end case; end Apply; ----------- -- Apply -- ----------- procedure Apply (Sw : in out Switches_Configuration; L : Switches_Modifier_Lists.List) is begin for Elt of L loop Apply (Sw, Elt); end loop; end Apply; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue; T : TOML.TOML_Value) return Profile_Modifier is Result : Profile_Modifier; begin if T.Kind /= TOML_Table then raise Program_Error; end if; for Key of T.Keys loop if (+Key) = "*" then Result.Wildcard := From_TOML (From, T.Get (Key)); else declare Prof : Profile_Kind; begin Prof := Profile_Kind'Value (+Key); case Prof is when Release => Result.Release := From_TOML (From, T.Get (Key)); when Validation => Result.Validation := From_TOML (From, T.Get (Key)); when Development => Result.Development := From_TOML (From, T.Get (Key)); end case; exception when Constraint_Error => From.Checked_Error ("Invalid profile name: '" & (+Key) & "'"); end; end if; end loop; return Result; end From_TOML; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is use type Conditional.Properties; Env : TOML_Value; Var : Variable; begin if From.Unwrap.Kind /= TOML_Table then From.Checked_Error ("Build_Switches: table expected, but got: " & From.Unwrap.Kind'Img); end if; if From.Pop_Single_Table (Env, TOML_Table) /= TOML_Keys.Build_Switches then raise Program_Error; -- Can't happen, unless the dispatch to us itself was erroneous end if; Var.T := Env.Clone; return Props : Conditional.Properties do Var.Modif := From_TOML (From, Env); Props := Props and Var; end return; end From_TOML; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Variable) return TOML.TOML_Value is begin return This.T; end To_TOML; ------------- -- To_YAML -- ------------- overriding function To_YAML (This : Variable) return String is ("Build switches: 'TODO'"); end Alire.Properties.Build_Switches; alire-1.2.1/src/alire/alire-properties-build_switches.ads000066400000000000000000000043031430264165500234650ustar00rootroot00000000000000with Ada.Containers.Doubly_Linked_Lists; with Alire.Conditional; with Alire.TOML_Adapters; with Alire.Utils.Switches; use Alire.Utils.Switches; private with TOML; package Alire.Properties.Build_Switches with Preelaborate is type Switches_Modifier (Cat : Switches_Categories := Optimization) is record case Cat is when Optimization => Optimization : Optimization_Switches; when Debug_Info => Debug_Info : Debug_Info_Switches; when Runtime_Checks => Runtime_Checks : Runtime_Checks_Switches; when Compile_Checks => Compile_Checks : Compile_Checks_Switches; when Contracts => Contracts : Contracts_Switches; when Style_Checks => Style_Checks : Style_Checks_Switches; when Ada_Version => Ada_Version : Ada_Version_Switches; end case; end record; package Switches_Modifier_Lists is new Ada.Containers.Doubly_Linked_Lists (Switches_Modifier); procedure Apply (Sw : in out Switches_Configuration; M : Switches_Modifier); procedure Apply (Sw : in out Switches_Configuration; L : Switches_Modifier_Lists.List); type Profile_Modifier is record Wildcard : Switches_Modifier_Lists.List; Release : Switches_Modifier_Lists.List; Validation : Switches_Modifier_Lists.List; Development : Switches_Modifier_Lists.List; end record; type Variable is new Property with private; function Modifier (This : Variable) return Profile_Modifier; -- Inherited operations overriding function Image (This : Variable) return String; overriding function Key (This : Variable) return String; function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; overriding function To_TOML (This : Variable) return TOML.TOML_Value; overriding function To_YAML (This : Variable) return String; private type Variable is new Property with record Modif : Profile_Modifier; T : TOML.TOML_Value; -- Original import end record; end Alire.Properties.Build_Switches; alire-1.2.1/src/alire/alire-properties-cases.ads000066400000000000000000000016131430264165500215540ustar00rootroot00000000000000generic -- Encapsulated enumeration type type Enum is (<>); -- Encapsulating property that contains one of the enumerated values type Property is new Properties.Property with private; with function Element (P : Property) return Enum; Name : String with Warnings => Off; -- String used for Image (seen by the user). TOML_Name : String with Warnings => Off; -- String used for case(toml-name) expressions in files. package Alire.Properties.Cases with Preelaborate is -- Traits package to be able to deal with case expressions that are -- resolved based on the value of a property. function Is_Satisfied (E : Enum; V : Properties.Vector) return Boolean -- Convenience for conditional trees to check if a case value is satisfied. is (for some P of V => P in Property and then Element (Property (P)) = E); end Alire.Properties.Cases; alire-1.2.1/src/alire/alire-properties-configurations.adb000066400000000000000000000674601430264165500235030ustar00rootroot00000000000000with TOML; use TOML; with Alire.Utils.YAML; with Ada.Characters.Handling; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package body Alire.Properties.Configurations is use AAA.Strings; ------------- -- To_Type -- ------------- function To_Type (Str : String) return Config_Type_Kind is Lower : constant String := Ada.Characters.Handling.To_Lower (Str); begin if Lower = "real" then return Real; elsif Lower = "integer" then return Int; elsif Lower = "string" then return Configurations.Str; elsif Lower = "enum" then return Enum; elsif Lower = "boolean" then return Bool; end if; Raise_Checked_Error ("Invalid configuration type '" & Str & "', must be (real, integer, string, enum or boolean)"); end To_Type; --------------- -- To_String -- --------------- function To_String (Str_Array : TOML_Value; Wrap_With_Quotes : Boolean := False) return String is Res : Unbounded_String; First : Boolean := True; begin for Index in 1 .. Str_Array.Length loop if Str_Array.Item (Index).Kind /= TOML_String then raise Program_Error with "Invalid TOML kind for enum values"; end if; declare Val : constant String := Str_Array.Item (Index).As_String; Val_Str : constant Unbounded_String := +(if Wrap_With_Quotes then """" & Val & """" else Val); begin if First then Res := Res & Val_Str; First := False; else Res := Res & ", " & Val_Str; end if; end; end loop; return +Res; end To_String; ----------- -- Image -- ----------- function Image (This : Config_Integer) return String is Ret : constant String := This'Img; begin if Ret (Ret'First) = ' ' then return Ret (Ret'First + 1 .. Ret'Last); else return Ret; end if; end Image; ----------- -- Image -- ----------- function Image (This : Config_Real) return String is begin case This.Kind is when Regular => declare Ret : constant String := This.Value'Img; begin if Ret (Ret'First) = ' ' then return Ret (Ret'First + 1 .. Ret'Last); else return Ret; end if; end; when NaN => if This.Positive then return "+nan"; else return "-nan"; end if; when Infinity => if This.Positive then return "+inf"; else return "-inf"; end if; end case; end Image; ----------- -- Image -- ----------- function Image (Val : TOML_Value) return String is begin if Val = No_TOML_Value then Raise_Checked_Error ("Unexpected No_TOML_Value in conversion to String"); end if; case Val.Kind is when TOML_String => return Val.As_String; when TOML_Boolean => return Val.As_Boolean'Img; when TOML_Float => return Image (Val.As_Float); when TOML_Integer => return Image (Val.As_Integer); when TOML_Array => -- Type of elements is checked inside following call return To_String (Val); when others => Raise_Checked_Error ("Unexpected kind '" & Val.Kind'Img & "' in conversion to String"); end case; end Image; -------------------- -- Type_To_String -- -------------------- function Type_To_String (This : Config_Type_Definition) return String is ((case This.Kind is when Str => "String", when Bool => "Boolean", when Enum => "Enum (" & To_String (This.Values) & ")", when Real => "Real range " & Image (This.Real_First) & " .. " & Image (This.Real_Last), when Int => "Integer range " & Image (This.Int_First) & " .. " & Image (This.Int_Last)) ); ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Config_Entry) return TOML.TOML_Value is Table : constant TOML.TOML_Value := TOML.Create_Table; begin Table.Set ("output_dir", Create_String (This.Output_Dir)); Table.Set ("disabled", Create_Boolean (This.Disabled)); Table.Set ("generate_ada", Create_Boolean (This.Gen_Ada)); Table.Set ("generate_gpr", Create_Boolean (This.Gen_GPR)); Table.Set ("generate_c", Create_Boolean (This.Gen_C)); Table.Set ("auto_gpr_with", Create_Boolean (This.Auto_GPR_With)); return Table; end To_TOML; ----------- -- Image -- ----------- overriding function Image (This : Config_Type_Definition) return String is Ret : Unbounded_String; begin Ret := "Config type: " & This.Name & " : " & Type_To_String (This) & ""; if This.Default /= No_TOML_Value then Append (Ret, String'(" default: '" & Image (This.Default) & "'")); end if; return +Ret; end Image; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Config_Type_Definition) return TOML.TOML_Value is Table1 : constant TOML.TOML_Value := TOML.Create_Table; Table2 : constant TOML.TOML_Value := TOML.Create_Table; begin Table2.Set ("type", Create_String (case This.Kind is when Str => "String", when Enum => "Enum", when Int => "Integer", when Bool => "Boolean", when Real => "Real")); if This.Default /= TOML.No_TOML_Value then Table2.Set ("default", This.Default); end if; case This.Kind is when Enum => Table2.Set ("values", This.Values); when Int => Table2.Set ("first", Create_Integer (This.Int_First)); Table2.Set ("last", Create_Integer (This.Int_Last)); when Real => Table2.Set ("first", Create_Float (This.Real_First)); Table2.Set ("last", Create_Float (This.Real_Last)); when Bool | Str => null; end case; Table1.Set (+This.Name, Table2); return Table1; end To_TOML; ------------- -- To_YAML -- ------------- overriding function To_YAML (This : Config_Type_Definition) return String is Ret : Unbounded_String; begin Ret := "{name: '" & This.Name & "', type: '" & Type_To_String (This) & "'"; if This.Default /= No_TOML_Value then Append (Ret, ", default: " & Alire.Utils.YAML.YAML_Stringify (Image (This.Default))); end if; return +Ret & "}"; end To_YAML; ----------- -- Image -- ----------- overriding function Image (This : Config_Value_Assignment) return String is Ret : Unbounded_String; First : Boolean := True; begin Ret := "Config set: " & This.Crate & " {"; for Elt of This.List loop if not First then Append (Ret, ", "); else First := False; end if; Append (Ret, +Elt.Name & " := " & Image (Elt.Value)); end loop; Append (Ret, "}"); return +Ret; end Image; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Config_Value_Assignment) return TOML.TOML_Value is Root : constant TOML.TOML_Value := TOML.Create_Table; Assign : constant TOML.TOML_Value := TOML.Create_Table; begin for Elt of This.List loop Assign.Set (Elt.Name, Elt.Value); end loop; Root.Set (+This.Crate, Assign); return Root; end To_TOML; ------------- -- To_YAML -- ------------- overriding function To_YAML (This : Config_Value_Assignment) return String is Ret : Unbounded_String; First : Boolean := True; begin Ret := "{crate: '" & This.Crate & "', settings: ["; for Elt of This.List loop if not First then Append (Ret, ", " & ASCII.LF); else First := False; end if; Append (Ret, "{name: '" & Elt.Name & "', value: " & Alire.Utils.YAML.YAML_Stringify (Image (Elt.Value)) & "}"); end loop; Append (Ret, "]}"); return +Ret; end To_YAML; ----------- -- Valid -- ----------- function Valid (This : Config_Type_Definition; Val : TOML.TOML_Value) return Boolean is begin if Val = No_TOML_Value then return False; end if; -- Validate the TOML type case This.Kind is when Str | Enum => if Val.Kind /= TOML_String then return False; end if; when Bool => if Val.Kind /= TOML_Boolean then return False; end if; when Real => if Val.Kind /= TOML_Float then return False; end if; when Int => if Val.Kind /= TOML_Integer then return False; end if; end case; case This.Kind is when Str | Bool => -- Nothing else to check return True; when Enum => declare Str : constant String := Val.As_String; begin for Index in 1 .. This.Values.Length loop if This.Values.Item (Index).As_String = Str then return True; end if; end loop; return False; end; when Real => declare F : constant Config_Real := Val.As_Float; First : Config_Real renames This.Real_First; Last : Config_Real renames This.Real_Last; begin -- We don't accept infinity or Nan here if F.Kind /= Regular then return False; end if; return not ( -- Lower bound (First.Kind = Infinity and then First.Positive) or else (First.Kind /= Infinity and then F.Value < First.Value) or else -- Upper bound (Last.Kind = Infinity and then not Last.Positive) or else (Last.Kind /= Infinity and then F.Value > Last.Value) ); end; when Int => declare I : constant Config_Integer := Val.As_Integer; begin return I >= This.Int_First and then I <= This.Int_Last; end; end case; exception when others => return False; end Valid; ---------- -- Name -- ---------- function Name (This : Config_Type_Definition) return String is (+This.Name); ------------------------ -- To_Ada_Declaration -- ------------------------ function To_Ada_Declaration (This : Config_Type_Definition; Value : TOML.TOML_Value) return String is use ASCII; Name : constant String := +This.Name; Indent : constant String := " "; begin case This.Kind is when Str => return Indent & Name & " : constant String := """ & Value.As_String & """;"; when Bool => return Indent & Name & " : constant Boolean := " & (if Value.As_Boolean then "True" else "False") & ";"; when Enum => return Indent & "type " & Name & "_Kind is (" & To_String (This.Values) & ");" & LF & Indent & Name & " : constant " & Name & "_Kind := " & Value.As_String & ";"; when Real => -- For Real and Int we do not declare a ranged type such as: -- -- type Test_Type is range 0 .. 100; -- Test : constant Test_Type := 50; -- -- because this would limit the possibilities of users for things -- such as alignment size, etc. Instead we define named numbers -- (constant) for the First, Last and actual value of the -- variable: -- -- Test_First : constant := 0; -- Test_Last : constant := 100 -- Test : constant := 50; -- -- User can then define their own types: -- -- type Test_Type is range Config.Test_First .. Config.Test_Last -- with Size => 32; return Indent & Name & "_First : constant := " & Image (This.Real_First) & ";" & LF & Indent & Name & "_Last : constant := " & Image (This.Real_Last) & ";" & LF & Indent & Name & " : constant := " & Image (Value.As_Float) & ";"; when Int => return Indent & Name & "_First : constant := " & This.Int_First'Img & ";" & LF & Indent & Name & "_Last : constant := " & This.Int_Last'Img & ";" & LF & Indent & Name & " : constant := " & Value.As_Integer'Img & ";"; end case; end To_Ada_Declaration; ------------------------ -- To_GPR_Declaration -- ------------------------ function To_GPR_Declaration (This : Config_Type_Definition; Value : TOML.TOML_Value) return String is use ASCII; Name : constant String := +This.Name; Indent : constant String := " "; begin case This.Kind is when Str => return Indent & Name & " := """ & Value.As_String & """;"; when Bool => return Indent & Name & " := """ & (if Value.As_Boolean then "True" else "False") & """;"; when Enum => return Indent & "type " & Name & "_Kind is (" & To_String (This.Values, Wrap_With_Quotes => True) & ");" & LF & Indent & Name & " : " & Name & "_Kind := """ & Value.As_String & """;"; when Real => return Indent & Name & "_First := """ & Image (This.Real_First) & """;" & LF & Indent & Name & "_Last := """ & Image (This.Real_Last) & """;" & LF & Indent & Name & " := """ & Image (Value.As_Float) & """;"; when Int => return Indent & Name & "_First := """ & Image (This.Int_First) & """;" & LF & Indent & Name & "_Last := """ & Image (This.Int_Last) & """;" & LF & Indent & Name & " := """ & Image (Value.As_Integer) & """;"; end case; end To_GPR_Declaration; ---------------------- -- To_C_Declaration -- ---------------------- function To_C_Declaration (This : Config_Type_Definition; Value : TOML.TOML_Value) return String is use ASCII; Name : constant String := To_Upper_Case (+This.Name); begin case This.Kind is when Str => return "#define " & Name & " """ & Value.As_String & """"; when Bool => return "#define " & Name & "_TRUE 1" & LF & "#define " & Name & "_FALSE 0" & LF & "#define " & Name & " " & (if Value.As_Boolean then "1" else "0"); when Enum => declare Ret : Unbounded_String; Count : Positive := 1; Value_Id : Positive := 1; begin for Index in 1 .. This.Values.Length loop declare Elt : constant String := This.Values.Item (Index).As_String; begin Ret := Ret & "#define " & Name & "_" & To_Upper_Case (Elt) & Count'Img & LF; if Elt = Value.As_String then Value_Id := Count; end if; Count := Count + 1; end; end loop; return +Ret & LF & "#define " & Name & " " & Value_Id'Img; end; when Real => return "#define " & Name & "_FIRST " & Image (This.Real_First) & LF & "#define " & Name & "_LAST " & Image (This.Real_Last) & LF & "#define " & Name & " " & Image (Value.As_Float); when Int => return "#define " & Name & "_FIRST " & Image (This.Int_First) & LF & "#define " & Name & "_LAST " & Image (This.Int_Last) & LF & "#define " & Name & " " & Image (Value.As_Integer); end case; end To_C_Declaration; --------------------------- -- Definitions_From_TOML -- --------------------------- function Definitions_From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is use Conditional.For_Properties; ---------------- -- Create_One -- ---------------- function Create_One (Name : String; Raw : TOML.TOML_Value) return Conditional.Properties is From : constant TOML_Adapters.Key_Queue := TOML_Adapters.From (Raw, TOML_Keys.Config_Vars & "." & Name); Typ : TOML_Value; First : TOML_Value; Last : TOML_Value; Unused : Boolean; begin if Raw.Kind /= TOML_Table then From.Checked_Error ("variable definition must be a table"); end if; if not From.Pop ("type", Typ) then From.Checked_Error ("'type' missing"); end if; if Typ.Kind /= TOML_String then From.Checked_Error ("'type' must be string"); end if; declare Type_Def : Config_Type_Definition (To_Type (Typ.As_String)); begin Type_Def.Name := +Name; case Type_Def.Kind is when Int => if From.Pop ("first", First) then if First.Kind /= TOML_Integer then From.Checked_Error ("first must be integer"); end if; Type_Def.Int_First := First.As_Integer; else Type_Def.Int_First := Config_Integer'First; end if; if From.Pop ("last", Last) then if Last.Kind /= TOML_Integer then From.Checked_Error ("'last' must be integer"); end if; Type_Def.Int_Last := Last.As_Integer; else Type_Def.Int_Last := Config_Integer'Last; end if; when Real => if From.Pop ("first", First) then if First.Kind /= TOML_Float then From.Checked_Error ("'first' must be float/real"); end if; Type_Def.Real_First := First.As_Float; if Type_Def.Real_First.Kind = TOML.NaN then From.Checked_Error ("'first' cannot be NaN"); end if; else Type_Def.Real_First := (TOML.Infinity, Positive => False); end if; if From.Pop ("last", Last) then if Last.Kind /= TOML_Float then From.Checked_Error ("'last' must be float/real"); end if; Type_Def.Real_Last := Last.As_Float; if Type_Def.Real_Last.Kind = TOML.NaN then From.Checked_Error ("'last' cannot be NaN"); end if; else Type_Def.Real_Last := (TOML.Infinity, Positive => True); end if; when Enum => if From.Pop ("values", Type_Def.Values) then if Type_Def.Values.Kind /= TOML_Array or else Type_Def.Values.Length = 0 or else (for some I in 1 .. Type_Def.Values.Length => Type_Def.Values.Item (I).Kind /= TOML_String) then From.Checked_Error ("'values' must be a not empty array of strings"); end if; else From.Checked_Error ("missing 'values' for enumeration type"); end if; when others => null; end case; if From.Pop ("default", Type_Def.Default) then if not Valid (Type_Def, Type_Def.Default) then From.Checked_Error ("invalid default value for " & Type_To_String (Type_Def)); end if; else Type_Def.Default := No_TOML_Value; end if; From.Report_Extra_Keys; return New_Value (Type_Def); end; end Create_One; Raw : constant TOML_Value := From.Pop; begin if Raw.Kind /= TOML_Table then Raise_Checked_Error (TOML_Keys.Config_Vars & "must be a table"); end if; return Props : Conditional.Properties do for Item of Iterate_On_Table (Raw) loop Props := Props and Create_One (To_String (Item.Key), Item.Value); Raw.Unset (Item.Key); end loop; end return; end Definitions_From_TOML; --------------------------- -- Assignments_From_TOML -- --------------------------- function Assignments_From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is use Conditional.For_Properties; ---------------- -- Create_One -- ---------------- function Create_One (Crate : String; Raw : TOML.TOML_Value) return Conditional.Properties is Val : Config_Value_Assignment; begin if Raw.Kind /= TOML_Table then Raise_Checked_Error (TOML_Keys.Config_Values & " assignments must be a table"); end if; Val.Crate := +Crate; for Item of Iterate_On_Table (Raw) loop declare Assign : Assignment; begin Assign.Name := Item.Key; Assign.Value := Item.Value; Val.List.Append (Assign); end; end loop; return New_Value (Val); end Create_One; Raw : constant TOML_Value := From.Pop; begin if Raw.Kind /= TOML_Table then raise Checked_Error with TOML_Keys.Config_Values & " must be a table"; end if; return Props : Conditional.Properties do for Item of Iterate_On_Table (Raw) loop Props := Props and Create_One (To_String (Item.Key), Item.Value); Raw.Unset (Item.Key); end loop; end return; end Assignments_From_TOML; ---------------------------- -- Config_Entry_From_TOML -- ---------------------------- function Config_Entry_From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is Config : constant TOML_Adapters.Key_Queue := From.Descend (From.Checked_Pop (TOML_Keys.Configuration, TOML_Table), TOML_Keys.Configuration); Ent : Config_Entry; begin return Props : Conditional.Properties do loop declare Val : TOML_Value; Key : constant String := Config.Pop (Val); Nested : Conditional.Properties; -- For nested tables under [configuration] begin exit when Key = ""; if Key = Tail (TOML_Keys.Config_Vars, '.') then Nested := Definitions_From_TOML (From.Descend (Key, Val, "variables")); elsif Key = Tail (TOML_Keys.Config_Values, '.') then Nested := Assignments_From_TOML (From.Descend (Key, Val, "settings")); elsif Key = "output_dir" then if Val.Kind = TOML_String then Ent.Output_Dir := Val.As_Unbounded_String; else Raise_Checked_Error ("invalid value for: " & Key & "(string expected)"); end if; elsif Key = "generate_ada" then if Val.Kind = TOML_Boolean then Ent.Gen_Ada := Val.As_Boolean; else Raise_Checked_Error ("invalid value for: " & Key & "(boolean expected)"); end if; elsif Key = "generate_gpr" then if Val.Kind = TOML_Boolean then Ent.Gen_GPR := Val.As_Boolean; else Raise_Checked_Error ("invalid value for: " & Key & "(Boolean expected)"); end if; elsif Key = "generate_c" then if Val.Kind = TOML_Boolean then Ent.Gen_C := Val.As_Boolean; else Raise_Checked_Error ("invalid value for: " & Key & "(Boolean expected)"); end if; elsif Key = "auto_gpr_with" then if Val.Kind = TOML_Boolean then Ent.Auto_GPR_With := Val.As_Boolean; else Raise_Checked_Error ("invalid value for: " & Key & "(Boolean expected)"); end if; elsif Key = "disabled" then if Val.Kind = TOML_Boolean then Ent.Disabled := Val.As_Boolean; else Raise_Checked_Error ("invalid value for: " & Key & "(Boolean expected)"); end if; else Raise_Checked_Error ("Unknown configuration entry: " & Key); end if; Props.Append (Nested); end; end loop; Props.Append (Conditional.For_Properties.New_Value (Ent)); end return; end Config_Entry_From_TOML; ----------------------- -- Builtin_From_Enum -- ----------------------- function Typedef_From_Enum return Config_Type_Definition is Ret : constant Config_Type_Definition := (Kind => Enum, Name => +Type_Name, Default => No_TOML_Value, Values => TOML.Create_Array); begin for P in T loop if Lower_Case then Ret.Values.Append (TOML.Create_String (To_Lower_Case (P'Img))); else Ret.Values.Append (TOML.Create_String (P'Img)); end if; end loop; return Ret; end Typedef_From_Enum; -------------------- -- String_Typedef -- -------------------- function String_Typedef (Name : String) return Config_Type_Definition is (Kind => Str, Name => +Name, Default => No_TOML_Value); end Alire.Properties.Configurations; alire-1.2.1/src/alire/alire-properties-configurations.ads000066400000000000000000000147461430264165500235230ustar00rootroot00000000000000with Alire.Conditional; with Alire.TOML_Adapters; with Alire.TOML_Keys; with Ada.Strings.Unbounded; with Ada.Containers.Doubly_Linked_Lists; with TOML; package Alire.Properties.Configurations with Preelaborate is -- Configuration looks like this: -- [configuration] -- # Top-level options here -- generate_c = false -- [configuration.variables] -- # Variables declared here -- test = { type = "Boolean" } -- [configuration.values] -- # Assignments made here -- crate.test = false -- To be able to have a top-level [conf] entry and dynamic expressions, -- without significantly changing the parsing internals, there is a -- top-level property [configuration] that internally parses the nested -- variables/settings tables. So, in practice, only this top-level entry -- is called by the index loading machinery, and in consequence only the -- top-level [configuration] can be dynamic: -- [configuration] -- [configuration.'case(os)'.windows.variables] -- etc. -- This top-level loader fools the caller by returning not only its own -- type of property, but also the children tables as same-level properties -- (top-level, or under a case). type Config_Entry is new Properties.Property with private; -- This property is the [configuration] itself function Output_Dir (This : Config_Entry) return Relative_Path; function Generate_Ada (This : Config_Entry) return Boolean; function Generate_GPR (This : Config_Entry) return Boolean; function Generate_C (This : Config_Entry) return Boolean; function Auto_GPR_With (This : Config_Entry) return Boolean; function Disabled (This : Config_Entry) return Boolean; type Config_Type_Definition (<>) is new Properties.Property with private; -- [configuration.variables] function Valid (This : Config_Type_Definition; Val : TOML.TOML_Value) return Boolean; function Default (This : Config_Type_Definition) return TOML.TOML_Value; function Name (This : Config_Type_Definition) return String; function To_Ada_Declaration (This : Config_Type_Definition; Value : TOML.TOML_Value) return String with Pre => This.Valid (Value); function To_GPR_Declaration (This : Config_Type_Definition; Value : TOML.TOML_Value) return String with Pre => This.Valid (Value); function To_C_Declaration (This : Config_Type_Definition; Value : TOML.TOML_Value) return String with Pre => This.Valid (Value); type Assignment is record Name : Ada.Strings.Unbounded.Unbounded_String; Value : TOML.TOML_Value; end record; package Assignment_List_Pck is new Ada.Containers.Doubly_Linked_Lists (Assignment); type Config_Value_Assignment is new Properties.Property with record Crate : Ada.Strings.Unbounded.Unbounded_String; List : Assignment_List_Pck.List; end record; -- [configuration.settings] function Config_Entry_From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; function Definitions_From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; function Assignments_From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; generic type T is (<>); Type_Name : String; Lower_Case : Boolean := False; function Typedef_From_Enum return Config_Type_Definition; function String_Typedef (Name : String) return Config_Type_Definition; private type Config_Entry is new Properties.Property with record Output_Dir : Ada.Strings.Unbounded.Unbounded_String := +"config"; Gen_Ada : Boolean := True; Gen_GPR : Boolean := True; Gen_C : Boolean := True; Auto_GPR_With : Boolean := True; Disabled : Boolean := False; end record; overriding function Key (This : Config_Entry) return String is (TOML_Keys.Configuration); overriding function To_TOML (This : Config_Entry) return TOML.TOML_Value; overriding function Image (This : Config_Entry) return String is ("Configuration: no modifiers"); -- In the future, we may have other settings here overriding function To_YAML (This : Config_Entry) return String is ("Configuration: no modifiers"); function Output_Dir (This : Config_Entry) return Relative_Path is (Relative_Path (+This.Output_Dir)); function Generate_Ada (This : Config_Entry) return Boolean is (This.Gen_Ada); function Generate_GPR (This : Config_Entry) return Boolean is (This.Gen_GPR); function Generate_C (This : Config_Entry) return Boolean is (This.Gen_C); function Auto_GPR_With (This : Config_Entry) return Boolean is (This.Auto_GPR_With); function Disabled (This : Config_Entry) return Boolean is (This.Disabled); type Config_Type_Kind is (Real, Int, Enum, Str, Bool); subtype Config_Integer is TOML.Any_Integer; subtype Config_Real is TOML.Any_Float; type Config_Type_Definition (Kind : Config_Type_Kind) is new Properties.Property with record Name : Ada.Strings.Unbounded.Unbounded_String; Default : TOML.TOML_Value; case Kind is when Real => Real_First, Real_Last : Config_Real; when Int => Int_First, Int_Last : Config_Integer; when Enum => Values : TOML.TOML_Value; when Str | Bool => null; end case; end record; overriding function Key (This : Config_Type_Definition) return String is (TOML_Keys.Config_Vars); overriding function Image (This : Config_Type_Definition) return String; overriding function To_TOML (This : Config_Type_Definition) return TOML.TOML_Value; overriding function To_YAML (This : Config_Type_Definition) return String; function Default (This : Config_Type_Definition) return TOML.TOML_Value is (This.Default); overriding function Key (This : Config_Value_Assignment) return String is (Alire.TOML_Keys.Config_Values); overriding function To_TOML (This : Config_Value_Assignment) return TOML.TOML_Value; overriding function Image (This : Config_Value_Assignment) return String; overriding function To_YAML (This : Config_Value_Assignment) return String; end Alire.Properties.Configurations; alire-1.2.1/src/alire/alire-properties-environment.adb000066400000000000000000000076241430264165500230110ustar00rootroot00000000000000with Alire.TOML_Keys; package body Alire.Properties.Environment is ------------ -- Action -- ------------ function Action (This : Variable) return Actions is (This.Action); ---------- -- Name -- ---------- function Name (This : Variable) return String is (+This.Name); function Shell_Name (This : Variable) return String is ("${" & Name (This) & "}"); ----------- -- Value -- ----------- function Value (This : Variable) return String is (+This.Value); --------------- -- Image_RHS -- --------------- function Image_RHS (This : Variable) return String is (Name (This) & (case This.Action is when Append => "=" & Shell_Name (This) & ":" & Value (This), when Prepend => "=" & Value (This) & ":" & Shell_Name (This), when Set => "=" & Value (This))); ----------- -- Image -- ----------- overriding function Image (This : Variable) return String is ("Environment: " & Image_RHS (This)); --------- -- Key -- --------- overriding function Key (This : Variable) return String is pragma Unreferenced (This); begin return TOML_Keys.Environment; end Key; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is use type Conditional.Properties; use TOML; Env : TOML_Value; begin if From.Unwrap.Kind /= TOML_Table then From.Checked_Error ("environment: table with assignments expected, but got: " & From.Unwrap.Kind'Img); end if; if From.Pop_Single_Table (Env, TOML_Table) /= TOML_Keys.Environment then raise Program_Error; -- Can't happen, unless the dispatch to us itself was erroneous end if; return Props : Conditional.Properties do for Name of Env.Keys loop declare Var : Variable; -- The env. var. being parsed Val : TOML_Value; -- The env. var. value begin Var.Name := Name; -- Action declare Action_Image : constant String := From.Descend (Value => Env.Get (Name), Context => "environment: " & (+Name)) .Pop_Single_Table (Val, TOML_String); begin Var.Action := Actions'Value (Action_Image); exception when Constraint_Error => -- because Action is invalid From.Checked_Error (": " & (+Var.Name) & "invalid action: " & Action_Image); end; -- Value (already type checked in previous pop) Var.Value := +Val.As_String; -- Pop entry to avoid upper "unexpected key" errors Env.Unset (+Name); -- Final assignment Props := Props and Var; end; end loop; end return; end From_TOML; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Variable) return TOML.TOML_Value is use TOML; Child : constant TOML_Value := Create_Table; begin return Result : constant TOML_Value := Create_Table do -- Create the VAR.action.Value nested tables Child.Set (AAA.Strings.To_Lower_Case (This.Action'Img), Create_String (Value (This))); Result.Set (Name (This), Child); end return; end To_TOML; ------------- -- To_YAML -- ------------- overriding function To_YAML (This : Variable) return String is ("Environment: '" & Image_RHS (This) & "'"); end Alire.Properties.Environment; alire-1.2.1/src/alire/alire-properties-environment.ads000066400000000000000000000021721430264165500230230ustar00rootroot00000000000000with Alire.Conditional; with Alire.TOML_Adapters; package Alire.Properties.Environment with Preelaborate is type Actions is (Append, Prepend, Set); type Variable is new Property with private; -- Own data function Action (This : Variable) return Actions; function Name (This : Variable) return String; -- Returns the name as is. See Shell_Name below. function Shell_Name (This : Variable) return String; -- Returns the name as it appears in "shell" expressions: ${NAME} function Value (This : Variable) return String; -- Inherited operations overriding function Image (This : Variable) return String; overriding function Key (This : Variable) return String; function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; overriding function To_TOML (This : Variable) return TOML.TOML_Value; overriding function To_YAML (This : Variable) return String; private type Variable is new Property with record Action : Actions; Name : UString; Value : UString; end record; end Alire.Properties.Environment; alire-1.2.1/src/alire/alire-properties-from_toml.adb000066400000000000000000000046241430264165500224400ustar00rootroot00000000000000with AAA.Enum_Tools; package body Alire.Properties.From_TOML is ------------ -- Loader -- ------------ function Loader (From : TOML_Adapters.Key_Queue; Loaders : Loader_Array; Section : Crates.Sections; Strict : Boolean) return Conditional.Properties is begin return Props : Conditional.Properties do loop declare function Is_Valid is new AAA.Enum_Tools.Is_Valid (Property_Keys); Val : TOML.TOML_Value; Key : constant String := From.Pop (Val); Prop : Property_Keys; Ada_Key : constant String := TOML_Adapters.Adafy (Key); begin if Key = "" then return; -- No more keys end if; -- Extract property name from string Process_Property : -- Single-pass loop to emulate Continue loop if Is_Valid (Ada_Key) then Prop := Property_Keys'Value (TOML_Adapters.Adafy (Key)); -- Check that the property is expected in this section. if Loaders (Prop) in null then From.Recoverable_Error ("property '" & Key & "' must not appear in section " & AAA.Strings.To_Lower_Case (Section'Image)); exit Process_Property; end if; -- Load property once we know its exact name, allowing -- expressions were appropriate. Props.Append (Prop_Loader.Load (From => From.Descend (Key => Key, Value => Val, Context => Key), Loader => Loaders (Prop), Resolve => Is_Dynamic (Prop), Strict => Strict)); else From.Recoverable_Error ("invalid property: " & Key); end if; exit Process_Property; end loop Process_Property; end; end loop; end return; end Loader; end Alire.Properties.From_TOML; alire-1.2.1/src/alire/alire-properties-from_toml.ads000066400000000000000000000200251430264165500224520ustar00rootroot00000000000000with Alire.Conditional; with Alire.Conditional_Trees.TOML_Load; with Alire.Crates; with Alire.Properties.Actions; with Alire.Properties.Configurations; with Alire.Properties.Environment; with Alire.Properties.Build_Profiles; with Alire.Properties.Build_Switches; with Alire.Properties.Labeled; with Alire.Properties.Licenses; with Alire.Properties.Scenarios; with Alire.Properties.Bool; with Alire.TOML_Adapters; package Alire.Properties.From_TOML is package Prop_Loader is new Conditional.For_Properties.TOML_Load; subtype Property_Loader is Prop_Loader.Static_Loader; type Property_Keys is (Actions, Authors, Auto_GPR_With, Build_Profiles, Build_Switches, Configuration, Description, Environment, Executables, GPR_Externals, GPR_Set_Externals, Hint, Licenses, Long_Description, Maintainers, Maintainers_Logins, Name, Notes, Project_Files, Tags, Version, Website); -- These enum values must match the toml key they represent with '-' => '_' -- The following array describes which properties are mandatory, depending -- on what we are loading. Mandatory : array (Crates.Sections, Property_Keys) of Boolean := (Crates.External_Private_Section => (others => False), Crates.External_Shared_Section => (Description | Maintainers | Maintainers_Logins | Name => True, others => False), Crates.Index_Release => (Description | Maintainers | Maintainers_Logins | Name | Version => True, others => False), Crates.Local_Release => (Description | Name | Version => True, others => False) ); Recommended : array (Property_Keys) of Boolean := (Authors | Licenses | Tags | Website => True, others => False); type Loader_Array is array (Property_Keys range <>) of Property_Loader; -- We use the following arrays to determine which properties may appear -- in a manifest section. These loaders will always receive a table of the -- form prop_name = prop_value. Dynamic expressions are resolved prior to -- dispatching to these loaders, so they need not to care. External_Private_Loaders : constant Loader_Array (Property_Keys) := (Hint => Labeled.From_TOML'Access, others => null); -- This loader is used for properties common to all external classes, found -- in their private [[external]] sections External_Shared_Loaders : constant Loader_Array (Property_Keys) := (Authors | Description => Labeled.From_TOML'Access, Licenses => Properties.Licenses.From_TOML'Access, Long_Description | Maintainers | Maintainers_Logins | Name | Tags | Website => Labeled.From_TOML'Access, others => null); -- This loader is used for properties a manifest containing externals may -- provide, shared by all external definitions found therein Release_Loaders : constant Loader_Array (Property_Keys) := (Actions => Properties.Actions.From_TOML'Access, Authors => Labeled.From_TOML'Access, Auto_GPR_With => Bool.From_TOML'Access, Build_Profiles => Properties.Build_Profiles.From_TOML'Access, Build_Switches => Properties.Build_Switches.From_TOML'Access, Description => Labeled.From_TOML'Access, Configuration => Properties.Configurations.Config_Entry_From_TOML'Access, Environment => Properties.Environment.From_TOML'Access, Executables => Labeled.From_TOML'Access, GPR_Externals | GPR_Set_Externals => Scenarios.From_TOML'Access, Hint => null, Licenses => Properties.Licenses.From_TOML'Access, Long_Description | Maintainers | Maintainers_Logins | Name | Notes | Project_Files | Tags | Version | Website => Labeled.From_TOML'Access); -- This loader applies to a normal release manifest -- The following array determines which properties accept dynamic -- expressions, per index semantics. All other properties must be static. Is_Dynamic : constant array (Property_Keys) of Boolean := (Actions | Build_Profiles | Configuration | Environment | Executables | GPR_Set_Externals | Hint | Project_Files => True, others => False); function Loader (From : TOML_Adapters.Key_Queue; Loaders : Loader_Array; Section : Crates.Sections; Strict : Boolean) return Conditional.Properties; -- Takes a table of mixed properties and dispatches to each concrete -- property loader. Takes into account dynamic properties. Indirectly -- called from Alire.TOML_Load to load each individual property, with -- the appropriate static loaders for the section. -- Following functions are wrappers on Loader that conform to the signature -- expected by the dynamic expression loader. Merely used to associate the -- appropriate section to the Loader. use all type Crates.Sections; function External_Private_Loader (From : TOML_Adapters.Key_Queue; Strict : Boolean) return Conditional.Properties is (Loader (From, External_Private_Loaders, External_Private_Section, Strict)); function External_Shared_Loader (From : TOML_Adapters.Key_Queue; Strict : Boolean) return Conditional.Properties is (Loader (From, External_Shared_Loaders, External_Shared_Section, Strict)); function Index_Release_Loader (From : TOML_Adapters.Key_Queue; Strict : Boolean) return Conditional.Properties is (Loader (From, Release_Loaders, Index_Release, Strict)); function Local_Release_Loader (From : TOML_Adapters.Key_Queue; Strict : Boolean) return Conditional.Properties is (Loader (From, Release_Loaders, Local_Release, Strict)); Section_Loaders : constant array (Crates.Sections) of access function (From : TOML_Adapters.Key_Queue; Strict : Boolean) return Conditional.Properties := (External_Private_Section => External_Private_Loader'Access, External_Shared_Section => External_Shared_Loader'Access, Index_Release => Index_Release_Loader'Access, Local_Release => Local_Release_Loader'Access); end Alire.Properties.From_TOML; alire-1.2.1/src/alire/alire-properties-labeled.adb000066400000000000000000000110231430264165500220210ustar00rootroot00000000000000package body Alire.Properties.Labeled is ------------ -- Filter -- ------------ function Filter (LV : Vector; Name : Labels) return Vector is begin return Result : Vector do for L of LV loop if L in Label and then Label'Class (L).Name = Name then Result.Append (L); end if; end loop; end return; end Filter; ------------ -- Filter -- ------------ function Filter (PV : Conditional.Properties; Name : Labels) return Vector is (Filter (Conditional.Enumerate (PV), Name)); --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is Value : TOML.TOML_Value; Key : constant String := From.Pop (Value); ------------------ -- Key_To_Label -- ------------------ function Key_To_Label (K : String) return Labels is begin -- TODO: instead of this inefficient O(n) lookup, have a map. for L in Labels loop if Labeled.Key (L) = K then return L; end if; end loop; From.Checked_Error ("Key is not a valid property: " & K); end Key_To_Label; -- For conditional loading, we use specific conditional loaders that -- only recognize the property being loaded: begin return Props : Conditional.Properties do declare Val : constant TOML.TOML_Value := TOML_Adapters.To_Array (Value); -- We process the same way single values and arrays of values -- (since they get converted into individual properties). begin for I in 1 .. Val.Length loop if Val.Item (I).Kind /= TOML_String then raise Checked_Error with "Expected String value for " & Key; end if; declare L : constant Label := New_Label (Key_To_Label (Key), Val.Item (I).As_String); use all type Conditional.Properties; begin if Cardinality (L.Name) = Unique and then I > 1 then raise Checked_Error with "Expected single value for " & Key; end if; -- Label-specific validation: L.Validate (From); -- Labeled property is valid and added to the release props. Props := Props and Conditional.For_Properties.New_Value (L); end; end loop; end; end return; exception when Checked_Error => raise; -- Let the more informative error raise when E : others => Log_Exception (E); From.Checked_Error ("Cannot read valid property from " & Key); end From_TOML; -------------- -- Validate -- -------------- procedure Validate (L : Label; From : TOML_Adapters.Key_Queue) is begin case L.Name is when Description => if L.Value'Length > Max_Description_Length then From.Checked_Error ("Description string is too long (must be no more than" & Max_Description_Length'Img & ")"); end if; when Maintainer => if not Utils.Could_Be_An_Email (L.Value, With_Name => True) then From.Checked_Error ("Maintainers must have a valid email, but got: " & L.Value); end if; when Maintainers_Logins => if not Utils.Is_Valid_GitHub_Username (L.Value) then From.Checked_Error ("maintainers-logins must be a valid GitHub login, but got: " & L.Value); end if; when Tag => if L.Value'Length = 0 then From.Checked_Error ("Tag string is empty"); end if; if L.Value'Length > Max_Tag_Length then From.Checked_Error ("Tag string is too long (must be no more than" & Max_Tag_Length'Img & ")"); end if; if not Utils.Is_Valid_Tag (L.Value) then From.Checked_Error ("Tag string is not valid: " & TTY.Error (L.Value)); end if; when others => null; end case; end Validate; end Alire.Properties.Labeled; alire-1.2.1/src/alire/alire-properties-labeled.ads000066400000000000000000000137511430264165500220540ustar00rootroot00000000000000with Alire.Conditional; with Alire.TOML_Adapters; private with Alire.TOML_Keys; private with Alire.Utils.YAML; package Alire.Properties.Labeled with Preelaborate is -- Properties that have a string atomic/array value and a name. -- Note that string arrays are internally stored as several individual -- properties with the same label at present. type Labels is (Author, -- VIP Description, -- Free-form but short description Executable, -- A resulting executable built by the release Hint, -- A text to display to the user for externals that fail detection Long_Description, -- Unlimited-length crate description Maintainer, -- Info about the maintainer of the alr-packaged crate Maintainers_Logins, -- E-mails used by the maintainers of a crate to log in to GitHub Name, -- Crate name Notes, -- Specific information about a release Path, -- Extra path for PATH to add to build (prepended) Project_File, -- Buildable project files in the release, with full relative path Version, -- Semantic version of the release Website, -- A website other than the repository Tag -- One word that identify one of the topic convered by a crate ); type Cardinalities is (Unique, Multiple); -- Are they atoms or arrays? -- This information is used during loading to enforce index correctness, -- and during exporting to ensure the proper type (atom/array) is created. Cardinality : array (Labels) of Cardinalities := (Author => Multiple, Description => Unique, Executable => Multiple, Hint => Unique, Long_Description => Unique, Maintainer => Multiple, Maintainers_Logins => Multiple, Name => Unique, Notes => Unique, Path => Multiple, Project_File => Multiple, Version => Unique, Website => Unique, Tag => Multiple); type Label (<>) is new Properties.Property and Interfaces.Tomifiable with private; function New_Label (Name : Labels; Value : String) return Label; function Name (L : Label) return Labels; function Value (L : Label) return String; function Filter (LV : Vector; Name : Labels) return Vector; -- Return only Label'Class with matching name function Filter (PV : Conditional.Properties; Name : Labels) return Vector; -- Version that takes a conditional tree, enumerates it and filters it. overriding function Image (L : Label) return String; overriding function To_YAML (L : Label) return String; function Key (L : Labels) return String; overriding function Key (L : Label) return String; overriding function To_TOML (L : Label) return TOML.TOML_Value with Post => To_TOML'Result.Kind = TOML.TOML_String; -- Returns only the value, not the name (TOML key) function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; -- Loads any labeled property. May raise Checked_Error. generic Name : Labels; function Cond_New_Label (Value : String) return Conditional.Properties; generic Name : Labels; function Cond_New_Path_Label (Value : Any_Path) return Conditional.Properties; private type Label (Length : Natural) is new Properties.Property and Interfaces.Tomifiable with record Name : Labels; Value : String (1 .. Length); end record; not overriding procedure Validate (L : Label; From : TOML_Adapters.Key_Queue); -- Check a just loaded label for validity (descr. length, email format...). -- If invalid, raise Checked_Error with appropriate context and message. function New_Label (Name : Labels; Value : String) return Label is (Properties.Property with Value'Length, Name, Value); function Name (L : Label) return Labels is (L.Name); function Value (L : Label) return String is (L.Value); function Cond_New_Label (Value : String) return Conditional.Properties is (Conditional.For_Properties.New_Value (New_Label (Name, Value))); function Cond_New_Path_Label (Value : Any_Path) return Conditional.Properties is (Conditional.For_Properties.New_Value (New_Label (Name, Utils.To_Native (Value)))); overriding function Image (L : Label) return String is (AAA.Strings.To_Mixed_Case (L.Name'Img) & ": " & L.Value); overriding function To_YAML (L : Label) return String is (Utils.YAML.YAML_Stringify (L.Value)); function Key (L : Labels) return String is (case L is when Author => TOML_Keys.Author, when Description => TOML_Keys.Description, when Executable => TOML_Keys.Executable, when Hint => TOML_Keys.Hint, when Long_Description => TOML_Keys.Long_Descr, when Maintainer => TOML_Keys.Maintainer, when Maintainers_Logins => TOML_Keys.Maint_Logins, when Name => TOML_Keys.Name, when Notes => TOML_Keys.Notes, when Path => TOML_Keys.Path, when Project_File => TOML_Keys.Project_File, when Tag => TOML_Keys.Tag, when Version => TOML_Keys.Version, when Website => TOML_Keys.Website); overriding function Key (L : Label) return String is (Key (L.Name)); overriding function To_TOML (L : Label) return TOML.TOML_Value is (TOML.Create_String (L.Value)); end Alire.Properties.Labeled; alire-1.2.1/src/alire/alire-properties-licenses.adb000066400000000000000000000120741430264165500222450ustar00rootroot00000000000000with Alire.Errors; with Alire.Warnings; package body Alire.Properties.Licenses is function Legacy_To_SPDX (Legacy : Licensing.Licenses) return String is (case Legacy is when AFL_3_0 => "AFL-3.0", when AGPL_3_0 => "AGPL-3.0-only", when Apache_2_0 => "Apache-2.0", when Artistic_2_0 => "Artistic-2.0", when BSD_2_Clause => "BSD-2-Clause", when BSD_3_Clause_Clear => "BSD-3-Clause-Clear", when BSD_3_Clause => "BSD-3-Clause", when BSL_1_0 => "BSL-1.0", when CC0_1_0 => "CC0-1.0", when CC_BY_4_0 => "CC-BY-4.0", when CC_BY_SA_4_0 => "CC-BY-SA-4.0", when ECL_2_0 => "ECL-2.0", when EPL_1_0 => "EPL-1.0", when EPL_2_0 => "EPL-2.0", when EUPL_1_1 => "EUPL-1.1", when EUPL_1_2 => "EUPL-1.2", when GPL_2_0 => "GPL-2.0-only", when GPL_3_0 => "GPL-3.0-only", when ISC => "ISC", when LGPL_2_1 => "LGPL-2.1-only", when LGPL_3_0 => "LGPL-3.0-only", when LPPL_1_3c => "LPPL-1.3c", when MIT => "MIT", when MPL_2_0 => "MPL-2.0", when MS_PL => "MS-PL", when MS_RL => "MS-RL", when NCSA => "NCSA", when OFL_1_1 => "OFL-1.1", when OSL_3_0 => "OSL-3.0", when PostgreSQL => "PostgreSQL", when Unlicense => "Unlicense", when WTFPL => "WTFPL", when Zlib => "Zlib", when GMGPL_2_0 => "GPL-2.0-only WITH GCC-exception-2.0", when GMGPL_3_0 => "GPL-3.0-only WITH GCC-exception-3.1", when Public_Domain => "custom-public-domain", when Custom => "custom-not-specified", when Unknown => raise Checked_Error with Errors.Set ("Invalid legacy license conversion for '" & Legacy'Img & "'")); ----------------- -- New_License -- ----------------- function New_License (From : String) return License is Legacy : constant Licensing.Licenses := Licensing.From_String (From); SPDX_Exp : constant SPDX.Expression := SPDX.Parse (From, Allow_Custom => True); begin if From'Length > Max_SPDX_Expression_Length then Raise_Checked_Error ("License expression too long (must be no more than" & Max_SPDX_Expression_Length'Img & " chars)"); end if; if not SPDX.Valid (SPDX_Exp) then if Legacy = Licensing.Unknown then raise Checked_Error with Errors.Set ("Invalid license expression '" & From & "': " & SPDX.Error (SPDX_Exp) & " . SPDX expression expected (https://spdx.org/licenses/)"); else Trace.Warning ("Deprecated license identifier '" & From & "'. Please replace with an SPDX expression " & "(https://spdx.org/licenses/)"); -- Try again with a translation of Legacy identifiers to SPDX return New_License (Legacy_To_SPDX (Legacy)); end if; end if; return License'(Holder => SPDX_Holder.To_Holder (SPDX_Exp)); end New_License; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is use TOML; use all type Conditional.Properties; Props : Conditional.Properties; Value : constant TOML.TOML_Value := From.Pop; begin if Value.Kind = TOML_Array then Warnings.Warn_Once (Errors.Stack ("Array of license in manifest is deprecated. " & "License should be a single string containing a " & "valid SPDX expression (https://spdx.org/licenses/)")); for I in 1 .. Value.Length loop if Value.Item (I).Kind = TOML_String then Props := Props and Conditional.For_Properties.New_Value (New_License (Value.Item (I).As_String)); else raise Checked_Error with "licenses must be strings"; end if; end loop; elsif Value.Kind = TOML_String then Props := Props and Conditional.For_Properties.New_Value (New_License (Value.As_String)); else raise Checked_Error with "licenses must be a string"; end if; return Props; exception when E : Checked_Error => -- May happen on unknown non-custom license. From.Checked_Error (Errors.Get (E)); -- Re-raise with full context of From. end From_TOML; end Alire.Properties.Licenses; alire-1.2.1/src/alire/alire-properties-licenses.ads000066400000000000000000000036501430264165500222660ustar00rootroot00000000000000with Alire.Conditional; with Alire.Licensing; with Alire.TOML_Adapters; with Alire.TOML_Keys; with Alire.Utils.YAML; with TOML; private with Ada.Containers.Indefinite_Holders; private with SPDX; with AAA.Strings; use AAA.Strings; package Alire.Properties.Licenses is -- Licenses can be either a value from the enumeration of known licenses, -- or a free custom text. type License is new Property with private; function New_License (From : String) return License; -- Verify that From is a known license name, and create it. In other cases -- Checked_Error is raised. overriding function Key (Dummy_L : License) return String is (TOML_Keys.License); overriding function Image (L : License) return String; overriding function To_TOML (L : License) return TOML.TOML_Value; function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; overriding function To_YAML (L : License) return String; private Max_SPDX_Expression_Length : constant := 150; -- SPDX the license expression can be arbitrary long, so we cap the -- accepted size. function "=" (A, B : SPDX.Expression) return Boolean is (SPDX.Img (A) = SPDX.Img (B)); package SPDX_Holder is new Ada.Containers.Indefinite_Holders (SPDX.Expression); use all type Licensing.Licenses; type License is new Property with record Holder : SPDX_Holder.Holder; end record; overriding function Image (L : License) return String is ("License: " & SPDX.Img (L.Holder.Element)); overriding function To_TOML (L : License) return TOML.TOML_Value is (TOML.Create_String (+SPDX.Img (L.Holder.Element))); overriding function To_YAML (L : License) return String is (Alire.Utils.YAML.YAML_Stringify (Replace (L.Image, "License: ", ""))); -- Remove the prefix "License: " which is not machine-intended. end Alire.Properties.Licenses; alire-1.2.1/src/alire/alire-properties-platform.ads000066400000000000000000000120311430264165500222760ustar00rootroot00000000000000with Alire.Platforms; with Alire.Properties.Cases; with Alire.TOML_Adapters; with Alire.TOML_Keys; package Alire.Properties.Platform with Preelaborate is -- The following packages declare types used by requisites so they have to -- be public. pragma Warnings (Off); -- unreferenced galore follows function Distro_Key (D : Platforms.Distributions) return String is (TOML_Keys.Distribution); function Tomify is new TOML_Adapters.Tomify_Enum (Platforms.Distributions); package Distributions is new Values (Platforms.Distributions, Platforms.Distributions'Image, Platforms.Distributions'Image, Distro_Key, Tomify); function Host_Arch_Key (A : Platforms.Architectures) return String is (TOML_Keys.Host_Arch); function Tomify is new TOML_Adapters.Tomify_Enum (Platforms.Architectures); package Host_Archs is new Values (Platforms.Architectures, Platforms.Architectures'Image, Platforms.Architectures'Image, Host_Arch_Key, Tomify); function OS_Key (OS : Platforms.Operating_Systems) return String is (TOML_Keys.OS); function Tomify is new TOML_Adapters.Tomify_Enum (Platforms.Operating_Systems); package Operating_Systems is new Values (Platforms.Operating_Systems, Platforms.Operating_Systems'Image, Platforms.Operating_Systems'Image, OS_Key, Tomify); function Target_Key (T : Platforms.Targets) return String is (TOML_Keys.Target); function Tomify is new TOML_Adapters.Tomify_Enum (Platforms.Targets); package Targets is new Values (Platforms.Targets, Platforms.Targets'Image, Platforms.Targets'Image, Target_Key, Tomify); function Toolchain_Key (T : Platforms.Toolchains) return String is (TOML_Keys.Toolchain); function Tomify is new TOML_Adapters.Tomify_Enum (Platforms.Toolchains); package Toolchains is new Values (Platforms.Toolchains, Platforms.Toolchains'Image, Platforms.Toolchains'Image, Toolchain_Key, Tomify); function Word_Size_Key (WS : Platforms.Word_Sizes) return String is (TOML_Keys.Word_Size); function Tomify is new TOML_Adapters.Tomify_Enum (Platforms.Word_Sizes); package Word_Sizes is new Values (Platforms.Word_Sizes, Platforms.Word_Sizes'Image, Platforms.Word_Sizes'Image, Word_Size_Key, Tomify); pragma Warnings (On); -- Case instantiations for case expressions package Ps renames Platforms; package PrPl renames Properties.Platform; package Distro_Cases is new Cases (Enum => Ps.Distributions, Property => PrPl.Distributions.Property, Element => PrPl.Distributions.Element, Name => "Distribution", TOML_Name => TOML_Keys.Distribution); package Host_Arch_Cases is new Cases (Enum => Ps.Architectures, Property => PrPl.Host_Archs.Property, Element => PrPl.Host_Archs.Element, Name => "Architecture", TOML_Name => TOML_Keys.Host_Arch); package OS_Cases is new Cases (Enum => Ps.Operating_Systems, Property => PrPl.Operating_Systems.Property, Element => PrPl.Operating_Systems.Element, Name => "OS", TOML_Name => TOML_Keys.OS); package Toolchain_Cases is new Cases (Enum => Ps.Toolchains, Property => PrPl.Toolchains.Property, Element => PrPl.Toolchains.Element, Name => "Toolchain", TOML_Name => TOML_Keys.Toolchain); package Word_Size_Cases is new Cases (Enum => Ps.Word_Sizes, Property => PrPl.Word_Sizes.Property, Element => PrPl.Word_Sizes.Element, Name => "Word_Size", TOML_Name => TOML_Keys.Word_Size); function Host_Arch_Is (A : Platforms.Architectures) return Vector renames Host_Archs.New_Vector; function Distribution_Is (D : Platforms.Distributions) return Vector renames Distributions.New_Vector; function System_Is (OS : Platforms.Operating_Systems) return Vector renames Operating_Systems.New_Vector; function Target_Is (T : Platforms.Targets) return Vector renames Targets.New_Vector; function Toolchain_Is (T : Platforms.Toolchains) return Vector renames Toolchains.New_Vector; function Word_Size_Is (V : Platforms.Word_Sizes) return Vector renames Word_Sizes.New_Vector; end Alire.Properties.Platform; alire-1.2.1/src/alire/alire-properties-scenarios.adb000066400000000000000000000123741430264165500224310ustar00rootroot00000000000000with Alire.Errors; package body Alire.Properties.Scenarios is --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties is use Conditional.For_Properties; use TOML; Value : TOML.TOML_Value; Key : constant String := From.Pop (Value); -- This function both processes scenario declarations and the setting of -- scenario variables, which are stored in the same type of property. -- The two following functions are devoted respectively to each case. ----------------------- -- Process_Externals -- ----------------------- function Process_Externals return Conditional.Properties is Table : constant TOML_Adapters.Key_Queue := From.Descend (Value, TOML_Keys.GPR_Ext); begin return Props : Conditional.Properties do loop declare Val : TOML.TOML_Value; Key : constant String := Table.Pop (Val); begin exit when Key = ""; if Val.Kind = TOML_String then if Val.As_String = "" then Props := Props and (New_Property (GPR.Free_Variable (Key))); else Table.Checked_Error ("free scenario variable must be given as """""); return; end if; elsif Val.Kind = TOML_Array then if Val.Length < 2 then Table.Checked_Error ("At least two values required in scenario"); end if; declare use GPR; Values : GPR.Value_Vector; begin for I in 1 .. Val.Length loop if Val.Item (I).Kind /= TOML_String then Table.Checked_Error ("scenario values must be a string array"); end if; Values := Values or Val.Item (I).As_String; end loop; Props := Props and New_Property (GPR.Enum_Variable (Key, Values)); end; end if; end; end loop; if Props.Is_Empty then Table.Checked_Error ("empty table"); end if; end return; end Process_Externals; --------------------------- -- Process_Set_Externals -- --------------------------- function Process_Set_Externals return Conditional.Properties is Table : constant TOML_Adapters.Key_Queue := From.Descend (Value, TOML_Keys.GPR_Set_Ext); begin return Props : Conditional.Properties do loop declare Val : TOML.TOML_Value; Key : constant String := Table.Pop (Val); begin exit when Key = ""; if Val.Kind /= TOML_String then Table.Checked_Error ("external variables must be given as " & "'var = string' pairs"); return; end if; Props := Props and New_Property (GPR.External_Value (Key, Val.As_String)); end; end loop; if Props.Is_Empty then Table.Checked_Error ("scenario sets no externals"); end if; end return; end Process_Set_Externals; begin if Value.Kind /= TOML_Table then From.Checked_Error ("scenarios require a table"); end if; if Key = TOML_Keys.GPR_Ext then return Process_Externals; else return Process_Set_Externals; end if; end From_TOML; --------------------- -- From_TOML_Cases -- --------------------- function From_TOML_Cases (From : TOML_Adapters.Key_Queue) return Conditional.Properties is (if +From.Unwrap.Keys (1) = TOML_Keys.GPR_Set_Ext then From_TOML (From) else raise Checked_Error with Errors.Stack ("scenario expressions can only set externals")); ------------- -- To_TOML -- ------------- overriding function To_TOML (V : Property) return TOML.TOML_Value is Table : constant TOML.TOML_Value := TOML.Create_Table; use all type GPR.Variable_Kinds; use TOML_Adapters; begin case V.Var.Element.Kind is when Enumeration => declare Arr : constant TOML.TOML_Value := TOML.Create_Array; begin for Val of V.Var.Element.Values loop Arr.Append (+Val); end loop; Table.Set (V.Var.Element.Name, Arr); end; when Free_String => Table.Set (V.Var.Element.Name, +""); when External => Table.Set (V.Var.Element.Name, +V.Var.Element.External_Value); end case; return Table; end To_TOML; end Alire.Properties.Scenarios; alire-1.2.1/src/alire/alire-properties-scenarios.ads000066400000000000000000000041261430264165500224460ustar00rootroot00000000000000with Alire.Conditional; with Alire.GPR; with Alire.TOML_Adapters; with Alire.TOML_Keys; private with Ada.Containers.Indefinite_Holders; package Alire.Properties.Scenarios with Preelaborate is type Property is new Properties.Property with private; function New_Property (V : GPR.Variable) return Property; overriding function Image (V : Property) return String; overriding function To_YAML (V : Property) return String; function Value (V : Property) return GPR.Variable; overriding function Key (V : Property) return String; function From_TOML (From : TOML_Adapters.Key_Queue) return Conditional.Properties; -- Recognizes GPR_Scenario and GPR_Set_Scenario properties. function From_TOML_Cases (From : TOML_Adapters.Key_Queue) return Conditional.Properties; -- Only accepts GPR_Set_Scenario properties, which can appear on dynamic -- expressions. GPR_Scenario are required to be static in the index. private package Holders is new Ada.Containers.Indefinite_Holders (GPR.Variable, GPR."="); type Property is new Properties.Property with record Var : Holders.Holder; end record; overriding function To_TOML (V : Property) return TOML.TOML_Value; function New_Property (V : GPR.Variable) return Property is (Var => Holders.To_Holder (V)); overriding function Image (V : Property) return String is ((case V.Var.Element.Kind is when GPR.External => "GPR External: ", when others => "GPR Scenario: ") & V.Var.Element.Image); overriding function To_YAML (V : Property) return String is ((case V.Var.Element.Kind is when GPR.External => "GPR External: ", when others => "GPR Scenario: ") & V.Var.Element.Image); overriding function Key (V : Property) return String is (case V.Var.Element.Kind is when GPR.External => TOML_Keys.GPR_Set_Ext, when others => TOML_Keys.GPR_Ext); function Value (V : Property) return GPR.Variable is (V.Var.Element); end Alire.Properties.Scenarios; alire-1.2.1/src/alire/alire-properties.adb000066400000000000000000000023561430264165500204440ustar00rootroot00000000000000with Alire.Conditional; package body Alire.Properties is ------------ -- Filter -- ------------ function Filter (V : Vector; Ancestor : Ada.Tags.Tag) return Vector is Result : Vector := No_Properties; begin for Prop of V loop if Ada.Tags.Is_Descendant_At_Same_Level (Prop'Tag, Ancestor) then Result.Append (Prop); end if; end loop; return Result; end Filter; ------------ -- Filter -- ------------ function Filter (V : Vector; Key : String) return Vector is Result : Vector := No_Properties; begin for Prop of V loop if Prop.Key = Key then Result.Append (Prop); end if; end loop; return Result; end Filter; ------------- -- To_TOML -- ------------- overriding function To_TOML (V : Vector) return TOML.TOML_Value is use Conditional.For_Properties; Tree : Conditional.Properties; begin -- Convert to a conditional vector to reuse the export function there, -- which is more general and takes property cardinalities into account. for Prop of V loop Tree := Tree and Prop; end loop; return Tree.To_TOML; end To_TOML; end Alire.Properties; alire-1.2.1/src/alire/alire-properties.ads000066400000000000000000000074661430264165500204740ustar00rootroot00000000000000with Ada.Containers.Indefinite_Vectors; with Ada.Tags; with Alire.Interfaces; with TOML; use all type TOML.Any_Value_Kind; package Alire.Properties with Preelaborate is -- Properties are the general mechanism used to store all info about a -- release. They can be specialized (e.g. in version, platform, compiler) -- but that can be transparent to the user. -- Since a property can be checked against a variety of conditions, this -- would require fully fledged multiple inheritance for the simplest -- design. Instead, a first check of matching tags is done and then the -- checks can proceed. type Property is abstract new Interfaces.Classifiable and Interfaces.Tomifiable and Interfaces.Yamlable with null record; overriding function Key (P : Property) return String is abstract; function Image (P : Property) return String is abstract; function Image_Classwide (P : Property'Class) return String is (P.Image); overriding function To_TOML (P : Property) return TOML.TOML_Value is abstract; overriding function To_YAML (P : Property) return String is abstract; package Vectors is new Ada.Containers.Indefinite_Vectors (Positive, Property'Class); type Vector is new Vectors.Vector and Interfaces.Tomifiable with null record; -- New type so using all it sees "and" below No_Properties : constant Vector; function "and" (L, R : Vector) return Vector; function "+" (P : Property'Class) return Vector; function To_Vector (P : Property'Class) return Vector renames "+"; function Filter (V : Vector; Ancestor : Ada.Tags.Tag) return Vector; -- Filter properties by ancestor class function Filter (V : Vector; Key : String) return Vector; -- Filter properties by key overriding function To_TOML (V : Vector) return TOML.TOML_Value with Post => To_TOML'Result.Kind = TOML.TOML_Table; -- Generates a table with key = value for its properties. -- Several values with the same key will be turned into an array. -- A generic helper to simply store/retrieve e.g. an enumerated type generic type Value is private; with function Image (V : Value) return String is <>; with function Yamlify (V : Value) return String is <>; with function Key (V : Value) return String is <>; with function Tomify (V : Value) return TOML.TOML_Value; package Values is type Property is new Properties.Property with private; function New_Property (V : Value) return Property; function New_Vector (V : Value) return Vector; function Element (P : Property) return Value; private overriding function Key (P : Property) return String; overriding function Image (P : Property) return String; overriding function To_YAML (P : Property) return String; overriding function To_TOML (P : Property) return TOML.TOML_Value; type Property is new Properties.Property with record V : Value; end record; function New_Property (V : Value) return Property is (V => V); function New_Vector (V : Value) return Vector is (+New_Property (V)); function Element (P : Property) return Value is (P.V); overriding function Image (P : Property) return String is (Image (P.V)); overriding function To_YAML (P : Property) return String is (Yamlify (P.V)); overriding function Key (P : Property) return String is (Key (P.V)); overriding function To_TOML (P : Property) return TOML.TOML_Value is (Tomify (P.V)); end Values; private No_Properties : constant Vector := (Vectors.Empty_Vector with null record); function "and" (L, R : Vector) return Vector is (L & R); function "+" (P : Property'Class) return Vector is (To_Vector (P, 1)); end Alire.Properties; alire-1.2.1/src/alire/alire-provides.adb000066400000000000000000000037671430264165500201120ustar00rootroot00000000000000with Semantic_Versioning.Extended; package body Alire.Provides is -------------------- -- Image_One_Line -- -------------------- function Image_One_Line (This : Equivalences) return String is use UStrings; Result : UString; First : Boolean := True; begin if This.Is_Empty then return "(nothing)"; -- not visible anywhere if all goes well end if; for Equiv of This loop if not First then Append (Result, ", "); end if; Append (Result, Equiv.TTY_Image); First := False; end loop; return +Result; end Image_One_Line; --------------- -- Satisfies -- --------------- function Satisfies (This : Equivalences; Dep : Dependencies.Dependency'Class) return Boolean is (for some Milestone of This => Milestone.Crate = Dep.Crate and then Semantic_Versioning.Extended.Is_In (Milestone.Version, Dep.Versions)); --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Equivalences is use TOML; TOML_Equivs : constant TOML_Value := From.Unwrap; begin return Result : Equivalences do for I in 1 .. TOML_Equivs.Length loop From.Assert (TOML_Equivs.Item (I).Kind = TOML_String, "expected a string describing a milestone, but got: " & TOML_Equivs.Item (I).Kind'Image); Result.Append (Milestones.New_Milestone (TOML_Equivs.Item (I).As_String)); end loop; end return; end From_TOML; ------------- -- To_TOML -- ------------- function To_TOML (This : Equivalences) return TOML.TOML_Value is use TOML; Result : constant TOML_Value := Create_Array; begin for Equiv of This loop Result.Append (Create_String (Equiv.Image)); end loop; return Result; end To_TOML; end Alire.Provides; alire-1.2.1/src/alire/alire-provides.ads000066400000000000000000000024161430264165500201210ustar00rootroot00000000000000with Alire.Dependencies; with Alire.Milestones.Containers; with Alire.TOML_Adapters; with TOML; package Alire.Provides with Preelaborate is -- Support for releases filling in for another crate release. Each -- individual equivalence is a milestone. Conceptually, an equivalence -- could be a dependency, but this complicates things elsewhere, as we -- would need to intersect dependencies (which Semantic_Versioning cannot -- do) to check satisfiability. type Equivalences is new Milestones.Containers.Lists.List with null record; No_Equivalences : constant Equivalences; function Satisfies (This : Equivalences; Dep : Dependencies.Dependency'Class) return Boolean; -- Check if any of the stored milestones fulfills the dependency. function Image_One_Line (This : Equivalences) return String; function From_TOML (From : TOML_Adapters.Key_Queue) return Equivalences with Pre => From.Unwrap.Kind in TOML.TOML_Array; function To_TOML (This : Equivalences) return TOML.TOML_Value with Post => To_TOML'Result.Kind in TOML.TOML_Array; private No_Equivalences : constant Equivalences := (Milestones.Containers.Lists.Empty_List with null record); end Alire.Provides; alire-1.2.1/src/alire/alire-publish.adb000066400000000000000000001235171430264165500177210ustar00rootroot00000000000000with Ada.Directories; with Ada.Text_IO; with AAA.Strings; with Alire.Config.Edit; with Alire.Crates; with Alire.Directories; with Alire.Errors; with Alire.Index_On_Disk.Loading; with Alire.GitHub; with Alire.Hashes; with Alire.Index; with Alire.Manifest; with Alire.Optional; with Alire.Origins.Deployers; with Alire.OS_Lib.Subprocess; with Alire.Paths; with Alire.Properties.From_TOML; with Alire.Releases; with Alire.Root; with Alire.Roots.Optional; with Alire.TOML_Adapters; with Alire.TOML_Index; with Alire.TOML_Keys; with Alire.TOML_Load; with Alire.User_Pins.Maps; with Alire.Utils.TTY; with Alire.Utils.User_Input.Query_Config; with Alire.VCSs.Git; with Alire.VFS; with CLIC.User_Input; with GNATCOLL.OS.Constants; with Semantic_Versioning; with TOML.File_IO; with TOML_Slicer; package body Alire.Publish is package Semver renames Semantic_Versioning; use all type UString; use Directories.Operators; use AAA.Strings; Trusted_Sites : constant AAA.Strings.Vector := AAA.Strings.Empty_Vector .Append ("bitbucket.org") .Append ("github.com") .Append ("gitlab.com") .Append ("savannah.nongnu.org") .Append ("sf.net"); type Data is limited record Options : All_Options; Origin : Origins.Origin := Origins.New_External ("undefined"); -- We use external as "undefined" until a proper origin is provided. Path : UString := +"."; -- Where to find the local workspace Subdir : Unbounded_Relative_Path; -- Subdir inside the root repo, for monorepo crates Revision : UString := +"HEAD"; -- A particular revision for publishing from a git repo Tmp_Deploy_Dir : Directories.Temp_File; -- Place to check the sources end record; --------------- -- Base_Path -- --------------- -- The workspace root path. To support out-of-alire packaging, this -- defaults to the current directory when using a nonstandard manifest. function Base_Path (This : Data) return Any_Path is (if This.Options.Nonstandard_Manifest then +This.Path else Root.Current.Path); ----------------- -- Deploy_Path -- ----------------- -- The folder in which we are testing the local build, which will be either -- the temp folder we create, or a nested crate within it for monorepos. function Deploy_Path (This : Data) return Any_Path is (if This.Subdir /= "" then This.Tmp_Deploy_Dir.Filename / (+This.Subdir) else This.Tmp_Deploy_Dir.Filename); ----------------------- -- Starting_Manifest -- ----------------------- -- The initial manifest in the workspace, at the standard location, or -- overridden to be taken from somewhere else. function Starting_Manifest (This : Data) return Any_Path is (if This.Options.Nonstandard_Manifest then This.Options.Manifest else Root.Current.Path / Roots.Crate_File_Name); ----------------------- -- Packaged_Manifest -- ----------------------- -- The manifest that we have in tmp folder during verification. This is -- always named and placed at the expected location. function Packaged_Manifest (This : Data) return Any_Path is (Deploy_Path (This) / Roots.Crate_File_Name); ----------------- -- New_Options -- ----------------- function New_Options (Skip_Build : Boolean := False; Manifest : String := Roots.Crate_File_Name) return All_Options is (Manifest_File => +Manifest, Skip_Build => Skip_Build); --------------- -- Git_Error -- --------------- procedure Git_Error (Msg : String; Path : Any_Path) is begin if Path /= "." then Raise_Checked_Error (TTY.URL (Path) & ": " & Msg); else Raise_Checked_Error (Msg); end if; end Git_Error; --------------------- -- Check_Git_Clean -- --------------------- -- Check that the repo is clean. If we need it only for generating an -- archive, that is enough; otherwise, check that we are in sync with -- the remote to which the origin will point to. procedure Check_Git_Clean (Path : Any_Path; For_Archiving : Boolean) is use all type VCSs.Git.States; Git : constant VCSs.Git.VCS := VCSs.Git.Handler; begin case Git.Status (Path) is when No_Remote => if For_Archiving then Put_Success ("Local repository is clean (without remote)."); else Git_Error ("No remote configured", Path); end if; when Clean => Put_Success ("Local repository is clean."); when Ahead => Git_Error ("Your branch is ahead of remote" & ASCII.LF & "Please push local commits to the remote branch.", Path); when Dirty => Git_Error (TTY.Emph ("git status") & " You have unstaged changes. " & "Please commit or stash them.", Path); end case; end Check_Git_Clean; ------------------- -- Check_Release -- ------------------- -- Checks the presence of recommended/mandatory fileds in the release procedure Check_Release (Release : Releases.Release) is use CLIC.User_Input; Recommend : AAA.Strings.Vector; -- Optional Missing : AAA.Strings.Vector; -- Mandatory Caret_Pre_1 : Boolean := False; -- To warn about this function Tomify (S : String) return String renames TOML_Adapters.Tomify; begin -- Check not duplicated Index_On_Disk.Loading.Setup_And_Load (From => Config.Edit.Indexes_Directory, Strict => True); if Index.Exists (Release.Name, Release.Version) then Recoverable_Error ("Target release " & Release.Milestone.TTY_Image & " already exist in a loaded index"); end if; -- Present release information to user Ada.Text_IO.New_Line; Trace.Info ("The release to be published contains this information:"); Ada.Text_IO.New_Line; Release.Print; -- Warn if the release contains pins if not Release.Pins.Is_Empty then Ada.Text_IO.New_Line; Trace.Warning ("The release manifest " & TTY.Warn ("contains pins that will be removed") & " in the published version."); end if; -- Detect missing recommended fields for Key in Properties.From_TOML.Recommended'Range loop if Properties.From_TOML.Recommended (Key) then if not Release.Has_Property (Tomify (Key'Image)) then Recommend.Append (Tomify (Key'Image)); end if; end if; end loop; if not Recommend.Is_Empty then Ada.Text_IO.New_Line; Trace.Warning ("Missing optional recommended properties: " & TTY.Warn (Recommend.Flatten (", "))); end if; -- Detect missing mandatory. This isn't detected by the TOML -- deserialization because we are still relying on the user manifest -- (the index one isn't generated until the user gives the go-ahead). for Key in Properties.From_TOML.Mandatory'Range (2) loop if Properties.From_TOML.Mandatory (Crates.Index_Release, Key) then if not Release.Has_Property (Tomify (Key'Image)) then Missing.Append (Tomify (Key'Image)); end if; end if; end loop; Caret_Pre_1 := Release.Check_Caret_Warning; if not Missing.Is_Empty then Ada.Text_IO.New_Line; Raise_Checked_Error ("Missing required properties: " & TTY.Error (Missing.Flatten (", "))); end if; -- Final confirmation. We default to Yes if no recommended missing or -- Force. Ada.Text_IO.New_Line; if Query ("Do you want to proceed with this information?", Valid => (Yes | No => True, others => False), Default => (if Force or else (Recommend.Is_Empty and then not Caret_Pre_1) then Yes else No)) /= Yes then Raise_Checked_Error ("Abandoned by user"); end if; end Check_Release; ----------------- -- STEP BODIES -- ----------------- type Step_Subprogram is access procedure (Context : in out Data); -- The following procedures share the spec, in the case in the future we -- need to reorder/reuse/insert them as part of a navigable workflow. ----------------- -- Check_Build -- ----------------- procedure Check_Build (Context : in out Data) with Pre => GNAT.OS_Lib.Is_Directory (Context.Tmp_Deploy_Dir.Filename); -- Check that the sources we are trying to publish can be built procedure Check_Build (Context : in out Data) is -- Enter the temporary as if it were a workspace (which it has to -- be, as it contains the user manifest). Auto-update should retrieve -- dependencies, and since we are not repackaging, there's no problem -- with altering contents under alire or regenerating the lock file. Guard : Directories.Guard (Directories.Enter (Deploy_Path (Context))) with Unreferenced; begin if Context.Options.Skip_Build then Trace.Warning ("Build check skipped."); return; end if; -- We need the alire folder, which usually will not be among sources if not Ada.Directories.Exists (Paths.Working_Folder_Inside_Root) then Ada.Directories.Create_Directory (Paths.Working_Folder_Inside_Root); end if; -- Unfortunately, building is one of the parts that still are hard to -- extricate from Alr.*, so for now the simplest solution is to spawn -- a child alr. OS_Lib.Subprocess.Checked_Spawn ("alr", AAA.Strings.Empty_Vector .Append ("--non-interactive") .Append ("build")); Put_Success ("Build succeeded."); end Check_Build; ------------------------- -- Check_User_Manifest -- ------------------------- -- Ensure that we are at a valid root, or else that the nonstandard -- manifest file is loadable. Either way, the contents of the release -- described by the manifest are vetted for completeness. procedure Check_User_Manifest (Context : in out Data) is use all type Roots.Optional.States; begin if Context.Options.Nonstandard_Manifest then Check_Release (Releases.From_Manifest (Starting_Manifest (Context), Alire.Manifest.Local, Strict => True)); -- Will have raised if the release is not loadable or incomplete else declare Root : constant Roots.Optional.Root := Alire.Root.Current; begin case Root.Status is when Outside => Raise_Checked_Error ("No Alire workspace found at current location"); when Broken => Raise_Checked_Error (Errors.Wrap ("Invalid metadata found at " & Root.Value.Path, Root.Brokenness)); when Valid => Check_Release (Root.Value.Release); end case; end; end if; end Check_User_Manifest; -------------------- -- Deploy_Sources -- -------------------- procedure Deploy_Sources (Context : in out Data) with Pre => Context.Origin.Kind not in Origins.External; -- Extract origin to a temporary location, to compute hash, read user -- manifest and verify buildability. procedure Deploy_Sources (Context : in out Data) is Deployer : constant Origins.Deployers.Deployer'Class := Origins.Deployers.New_Deployer (Context.Origin); begin -- Obtain source archive (or no-op for repositories): Deployer.Fetch (Context.Tmp_Deploy_Dir.Filename).Assert; -- Compute hashes in supported origin kinds (e.g. source archives) if Deployer.Supports_Hashing then for Kind in Hashes.Kinds loop declare Hash : constant Hashes.Any_Hash := Hashes.New_Hash (Kind, Deployer.Compute_Hash (Context.Tmp_Deploy_Dir.Filename, Kind)); begin Put_Success ("Computed hash: " & String (Hash)); Context.Origin.Add_Hash (Hash); end; end loop; end if; -- Pull the repo/unpack source archive Deployer.Deploy (Context.Tmp_Deploy_Dir.Filename).Assert; -- Check that the maintainer's manifest is at the expected location if not GNAT.OS_Lib.Is_Regular_File (Deploy_Path (Context) / Context.Options.Manifest) then Raise_Checked_Error ("Remote sources are missing the '" & Context.Options.Manifest & "' manifest file expected at " & Deploy_Path (Context) / Context.Options.Manifest); end if; -- For a non-standard manifest, move it in place (akin to how `alr get` -- will regenerate it from the index). Subsequent tests can then assume -- a regularly deployed crate. if Context.Options.Nonstandard_Manifest then Ada.Directories.Copy_File (Context.Tmp_Deploy_Dir.Filename / Context.Options.Manifest, Context.Tmp_Deploy_Dir.Filename / Roots.Crate_File_Name); end if; -- Remove pins at this point, as this manifest will be the basis for the -- published one; also this way the build test will not rely on pins. TOML_Slicer.Remove_Array (File_Name => Packaged_Manifest (Context), Array_Name => TOML_Keys.Pins, Backup => True, Backup_Dir => Deploy_Path (Context)); end Deploy_Sources; ----------------------------- -- Generate_Index_Manifest -- ----------------------------- procedure Generate_Index_Manifest (Context : in out Data) with Pre => GNAT.OS_Lib.Is_Directory (Context.Tmp_Deploy_Dir.Filename); -- Bind the user manifest with the origin TOML object and create the index -- manifest. procedure Generate_Index_Manifest (Context : in out Data) is User_Manifest : constant Any_Path := Packaged_Manifest (Context); Workspace : constant Roots.Optional.Root := Root.Current; begin if not GNAT.OS_Lib.Is_Read_Accessible_File (User_Manifest) then Raise_Checked_Error ("User manifest not found at expected location" & " (${SRC_ROOT}/" & Roots.Crate_File_Name & ")."); end if; declare use Ada.Text_IO; use TOML; TOML_Manifest : constant TOML_Value := TOML_Load.Load_File (User_Manifest); TOML_Origin : constant TOML_Value := Create_Table; Name : constant Crate_Name := +TOML_Manifest.Get (TOML_Keys.Name).As_String; Version : constant Semver.Version := Semver.Parse (TOML_Manifest.Get (TOML_Keys.Version).As_String); Index_Manifest : constant Any_Path := (if Workspace.Is_Valid then Workspace.Value.Working_Folder else "." / Paths.Working_Folder_Inside_Root) / "releases" / TOML_Index.Manifest_File (Name, Version); Index_File : File_Type; begin if Workspace.Is_Valid and then (not Context.Options.Nonstandard_Manifest) and then Workspace.Value.Release.Name /= Name then Raise_Checked_Error (Errors.Wrap ("Current workspace does not match the crate being published", "Working crate is " & Utils.TTY.Name (Workspace.Value.Release.Name) & ", publishing crate is " & Utils.TTY.Name (Name))); end if; TOML_Origin.Set (TOML_Keys.Origin, Context.Origin.To_TOML); -- Prepare the destination dir for the generated index manifest: Ada.Directories.Create_Path (Ada.Directories.Containing_Directory (Index_Manifest)); Ada.Directories.Copy_File (User_Manifest, Index_Manifest); -- Take the user manifest and bundle it under the proper index -- manifest name with the origin we are being provided with: Open (Index_File, Append_File, Index_Manifest); New_Line (Index_File); TOML.File_IO.Dump_To_File (TOML_Origin, Index_File); Close (Index_File); Put_Success ("Your index manifest file has been generated at " & TTY.URL (Index_Manifest)); -- Show the upload URL in normal circumstances, or a more generic -- message otherwise (when lacking a github login). if Config.DB.Defined (Config.Keys.User_Github_Login) then Put_Info ("Please upload this file to " & TTY.URL (Index.Community_Host & "/" & Config.DB.Get (Config.Keys.User_Github_Login, "") & "/" & Index.Community_Repo_Name & "/upload/" & Index.Community_Branch & "/" & String (TOML_Index.Manifest_Path (Name))) & " to create a pull request against the community index."); else Put_Info ("Please create a pull request against the community index at " & TTY.URL (Tail (Index.Community_Repo, '+')) & " including this file at " & TTY.URL (String (TOML_Index.Manifest_Path (Name)))); end if; exception when others => if Is_Open (Index_File) then Close (Index_File); end if; raise; end; end Generate_Index_Manifest; --------------------- -- Prepare_Archive -- --------------------- procedure Prepare_Archive (Context : in out Data) with Pre => Alire.Manifest.Is_Valid (Context.Options.Manifest, Alire.Manifest.Local); -- Prepare a tar file either using git archive (if git repo detected) or -- plain tar otherwise. procedure Prepare_Archive (Context : in out Data) is use CLIC.User_Input; Target_Dir : constant Relative_Path := Paths.Working_Folder_Inside_Root / "archives"; Release : constant Releases.Release := Releases.From_Manifest (Context.Options.Manifest, Alire.Manifest.Local, Strict => True); Milestone : constant String := TOML_Index.Manifest_File (Release.Name, Release.Version, With_Extension => False); Git : constant VCSs.Git.VCS := VCSs.Git.Handler; Is_Repo : constant Boolean := Git.Is_Repository (Base_Path (Context)); Archive : constant Relative_Path := Target_Dir / (Milestone & (if Is_Repo then ".tgz" else ".tbz2")); ----------------- -- Git_Archive -- ----------------- procedure Git_Archive is begin OS_Lib.Subprocess.Checked_Spawn ("git", Empty_Vector & "archive" & "-o" & Archive -- Destination file at alire/archives/crate-version.tar.gz & String'("--prefix=" & Milestone & "/") -- Prepend empty milestone dir name as required for our tars & (+Context.Revision)); end Git_Archive; ----------------- -- Tar_Archive -- ----------------- procedure Tar_Archive is begin pragma Warnings (Off, "condition is always"); -- To silence our below check for macOS OS_Lib.Subprocess.Checked_Spawn ("tar", Empty_Vector & "cfj" & Archive -- Destination file at alire/archives/crate-version.tbz2 & String'("--exclude=./alire") -- Exclude top-level alire folder, before applying prefix -- exclude .git and the like, with workaround for macOS bsd tar & (if GNATCOLL.OS.Constants.OS in GNATCOLL.OS.MacOS then Empty_Vector & "--exclude=./.git" & "--exclude=./.hg" & "--exclude=./.svn" & String'("-s,^./," & Milestone & "/,") -- Prepend empty milestone dir as required for our tars) else Empty_Vector & "--exclude-backups" -- exclude .#* *~ #*# patterns & "--exclude-vcs" -- exclude .git, .hg, etc & "--exclude-vcs-ignores" -- exclude from .gitignore, etc & String'("--transform=s,^./," & Milestone & "/,")) -- Prepend empty milestone dir as required for our tars & "."); pragma Warnings (On); end Tar_Archive; begin if Is_Repo then Check_Git_Clean (Base_Path (Context), For_Archiving => True); else Trace.Warning ("Not in a git repository, assuming plain sources."); end if; -- Create a tarball with our required nested structure, and excluding -- the alire folder and our own temporary. if not Ada.Directories.Exists (Target_Dir) then Ada.Directories.Create_Path (Target_Dir); end if; if Is_Repo then Git_Archive; else Tar_Archive; end if; Put_Success ("Source archive created successfully."); declare -------------- -- Is_Valid -- -------------- function Is_Valid (Remote_URL : String) return Boolean is begin Trace.Always (""); Trace.Always ("The URL is: " & TTY.URL (Remote_URL)); Context.Origin := Origins.New_Source_Archive (Trim (Remote_URL), -- remove unwanted extra whitespaces Ada.Directories.Simple_Name (Archive)); -- This origin creation may raise if URL is improper return True; exception when E : others => Errors.Pretty_Print (Errors.Wrap ("The URL does not seem to be valid:", Errors.Get (E))); return False; end Is_Valid; ----------------- -- Get_Default -- ----------------- function Get_Default (Remote_URL : String) return Answer_Kind is (if Force or else URI.Scheme (Remote_URL) in URI.HTTP then Yes else No); -- We don't use the following answer because the validation function -- already stores the information we need. Unused : constant Answer_With_Input := Validated_Input (Question => "Please upload the archive generated" & " at " & TTY.URL (Archive) & " to its definitive online storage location." & ASCII.LF & "Once you have uploaded the file, enter its URL:", Prompt => "Enter URL> ", Valid => (Yes | No => True, others => False), Default => Get_Default'Access, Is_Valid => Is_Valid'Access); begin null; -- Nothing to do, everything happens at Answer_With_Input end; end Prepare_Archive; ---------------------- -- Show_And_Confirm -- ---------------------- procedure Show_And_Confirm (Context : in out Data) with Pre => GNAT.OS_Lib.Is_Regular_File (Deploy_Path (Context) / Roots.Crate_File_Name); -- Present the final release information for confirmation by the user, -- after checking that no critical information is missing, or the release -- already exists. procedure Show_And_Confirm (Context : in out Data) is Release : constant Releases.Release := Releases .From_Manifest (Packaged_Manifest (Context), Alire.Manifest.Local, Strict => True) .Replacing (Origin => Context.Origin); begin Check_Release (Release); end Show_And_Confirm; ------------------- -- Verify_Github -- ------------------- procedure Verify_Github (Context : in out Data) is pragma Unreferenced (Context); begin -- Early return if forcing if Force then Trace.Warning ("GitHub checks skipped"); return; end if; -- User has an account if not Config.DB.Defined (Config.Keys.User_Github_Login) then Put_Info ("Publishing to the community index" & " requires a GitHub account."); else Put_Success ("User has a GitHub account: " & TTY.Emph (Utils.User_Input.Query_Config.User_GitHub_Login)); end if; -- Check several remote GitHub items declare Login : constant String := Utils.User_Input.Query_Config.User_GitHub_Login; begin -- User must exist if not GitHub.User_Exists (Login) then Raise_Checked_Error ("Your GitHub login does not seem to exist: " & TTY.Emph (Login)); end if; -- It has to have its own fork of the repo if not GitHub.Repo_Exists (Login, Index.Community_Repo_Name) then Raise_Checked_Error ("You must fork the community index to your GitHub account" & ASCII.LF & "Please visit " & TTY.URL (Tail (Index.Community_Repo, '+')) & " and fork the repository."); else Put_Success ("User has forked the community repository"); end if; -- The repo must contain the base branch, or otherwise GitHub -- redirects to the main repository page with an error banner on top. if not GitHub.Branch_Exists (User => Login, Repo => Index.Community_Repo_Name, Branch => Index.Community_Branch) then Raise_Checked_Error ("Your index fork is missing the current base branch (" & TTY.Emph (Index.Community_Branch) & ")" & " for pull requests to the community repository" & ASCII.LF & "Please synchronize this branch and try again" & ASCII.LF & "Your fork URL is: " & TTY.URL (Index.Community_Host & "/" & Login & "/" & Index.Community_Repo_Name)); else Put_Success ("User's fork contains base branch: " & TTY.Emph (Index.Community_Branch)); end if; end; end Verify_Github; ------------------- -- Verify_Origin -- ------------------- procedure Verify_Origin (Context : in out Data) is URL : constant Alire.URL := Context.Origin.Get_URL; begin -- Ensure the origin is remote if URI.Scheme (URL) not in URI.HTTP then -- A git@ URL is private to the user and should not be used for -- packaging: if AAA.Strings.Has_Prefix (URL, "git@") then Raise_Checked_Error ("The origin cannot use a private git remote: " & URL); end if; -- Otherwise we assume this is a local path Recoverable_Error ("The origin must be a definitive remote location, but is " & URL); -- For testing we may want to allow local URLs, or may be for -- internal use with network drives? So allow forcing it. end if; Put_Success ("Origin is of supported kind: " & Context.Origin.Kind'Img); if Context.Origin.Kind in Origins.VCS_Kinds then -- Check an VCS origin is from a trusted site, unless we are forcing -- a local repository. if (Force and then URI.Scheme (URL) in URI.File_Schemes | URI.Unknown) -- We are forcing, so we accept an unknown scheme (this happens -- for local file on Windows, where drive letters are interpreted -- as the scheme). or else (for some Site of Trusted_Sites => URI.Authority_Without_Credentials (URL) = Site or else Has_Suffix (URI.Authority (URL), "." & Site)) then Put_Success ("Origin is hosted on trusted site: " & URI.Authority_Without_Credentials (URL)); else Raise_Checked_Error ("Origin is hosted on unknown site: " & URI.Authority_Without_Credentials (URL)); end if; end if; end Verify_Origin; ----------------------- -- STEPS SCAFFOLDING -- ----------------------- -- Any sequence of steps can be selected by creating an array of step names type Step_Names is (Step_Check_User_Manifest, Step_Prepare_Archive, Step_Verify_Origin, Step_Verify_Github, Step_Deploy_Sources, Step_Check_Build, Step_Show_And_Confirm, Step_Generate_Index_Manifest); type Step_Array is array (Positive range <>) of Step_Names; Step_Calls : constant array (Step_Names) of Step_Subprogram := (Step_Check_User_Manifest => Check_User_Manifest'Access, Step_Prepare_Archive => Prepare_Archive'Access, Step_Verify_Origin => Verify_Origin'Access, Step_Verify_Github => Verify_Github'Access, Step_Deploy_Sources => Deploy_Sources'Access, Step_Check_Build => Check_Build'Access, Step_Show_And_Confirm => Show_And_Confirm'Access, Step_Generate_Index_Manifest => Generate_Index_Manifest'Access); function Step_Description (Step : Step_Names) return String is (case Step is when Step_Check_User_Manifest => "Verify user manifest", when Step_Prepare_Archive => "Prepare remote source archive", when Step_Verify_Origin => "Verify origin URL", when Step_Verify_Github => "Verify GitHub infrastructure", when Step_Deploy_Sources => "Deploy sources", when Step_Check_Build => "Build release", when Step_Show_And_Confirm => "User review", when Step_Generate_Index_Manifest => "Generate index manifest"); --------------- -- Run_Steps -- --------------- -- Gives feedback on the current step and dispatches to its actual code procedure Run_Steps (Context : in out Data; Steps : Step_Array) is -- Manage publishing steps up to exhaustion or error begin for Current in Steps'Range loop Ada.Text_IO.New_Line; Trace.Info ("Publishing assistant: step" & TTY.Emph (Integer'Image (Current)) & " of" & TTY.Emph (Integer'Image (Steps'Last) & ": " & TTY.Emph (Step_Description (Steps (Current))))); Step_Calls (Steps (Current)) (Context); end loop; end Run_Steps; ------------------- -- Directory_Tar -- ------------------- procedure Directory_Tar (Path : Any_Path := "."; Revision : String := "HEAD"; Options : All_Options := New_Options) is Context : Data := (Options => Options, Origin => <>, Path => +Path, Subdir => <>, Revision => +Revision, Tmp_Deploy_Dir => <>); Guard : Directories.Guard (Directories.Enter (Base_Path (Context))) with Unreferenced; begin Run_Steps (Context, (Step_Check_User_Manifest, Step_Prepare_Archive, Step_Verify_Origin, Step_Verify_Github, Step_Deploy_Sources, Step_Check_Build, Step_Show_And_Confirm, Step_Generate_Index_Manifest)); end Directory_Tar; ---------------------- -- Local_Repository -- ---------------------- procedure Local_Repository (Path : Any_Path := "."; Revision : String := "HEAD"; Options : All_Options := New_Options) is Root : constant Roots.Optional.Root := Roots.Optional.Search_Root (Path); Git : constant VCSs.Git.VCS := VCSs.Git.Handler; use all type Roots.Optional.States; Subdir : Unbounded_Relative_Path; -- In case we are publishing a nested crate (monorepo), its relative -- path in regard to the git worktree will be stored here by -- Check_Nested_Crate. ----------------------- -- Check_Root_Status -- ----------------------- procedure Check_Root_Status is begin case Root.Status is when Outside => if Options.Nonstandard_Manifest then Trace.Debug ("Using non-standard manifest location: " & Options.Manifest); else Raise_Checked_Error ("No Alire workspace found at " & TTY.URL (Path)); end if; when Broken => Raise_Checked_Error (Errors.Wrap ("Invalid metadata found at " & TTY.URL (Path), Root.Brokenness)); when Valid => null; end case; end Check_Root_Status; ------------------------ -- Check_Nested_Crate -- ------------------------ procedure Check_Nested_Crate (Root_Path : Absolute_Path) is Git_Root : constant Optional.Absolute_Path := Git.Root; begin if Git_Root.Has_Element and then not VFS.Is_Same_Dir (Git_Root.Value, Root_Path) then -- To make our life easier for now, do not allow complex cases -- like using a manifest from elsewhere to package a nested crate. if Options.Nonstandard_Manifest then Raise_Checked_Error ("Nonstandard manifest and nested crates cannot be used " & "simultaneously."); end if; Put_Info ("Crate at " & TTY.URL (Root_Path) & " is nested in repo at " & TTY.URL (Git_Root.Value)); declare Nested_Path : constant Relative_Path := Git.Get_Rel_Path_Inside_Repo (Root_Path); begin Trace.Debug ("Publishing nested crate at " & TTY.URL (Nested_Path)); Subdir := +Nested_Path; end; end if; end Check_Nested_Crate; begin Check_Root_Status; declare Root_Path : constant Absolute_Path := (if Options.Nonstandard_Manifest then Ada.Directories.Full_Name (Path) else Ada.Directories.Full_Name (Root.Value.Path)); begin if not Git.Is_Repository (Root_Path) then Git_Error ("no git repository found", Root_Path); end if; -- Do not continue if the local repo is dirty Check_Git_Clean (Root_Path, For_Archiving => False); -- If the Git root does not match the path to the manifest, we are -- seeing a crate in a subdir, so we go to monorepo mode. Check_Nested_Crate (Root_Path); -- If not given a revision, check the local manifest contents -- already. No matter what, it will be checked again on the -- deployed sources step. if Revision = "" or Revision = "HEAD" then declare Tmp_Context : Data := (Options => Options, others => <>); begin Check_User_Manifest (Tmp_Context); end; end if; -- If given a revision, extract commit and verify it exists locally declare Commit : constant String := Git.Revision_Commit (Root_Path, (if Revision /= "" then Revision else "HEAD")); begin if Commit /= "" then Put_Success ("Revision exists in local repository (" & TTY.Emph (Commit) & ")."); else Raise_Checked_Error ("Revision not found in local repository: " & TTY.Emph (Revision)); end if; declare Raw_URL : constant String := Git.Fetch_URL (Root_Path, Origin => Git.Remote (Root_Path)); -- The one reported by the repo, in its public form Fetch_URL : constant String := -- With an added ".git", if it hadn't one. Not usable in local -- filesystem. Raw_URL & (if Has_Suffix (To_Lower_Case (Raw_URL), ".git") then "" else ".git"); begin -- To allow this call to succeed with local tests, we check -- here. For a regular repository we will already have an HTTP -- transport. A GIT transport is not wanted, because that one -- requires the owner keys. case URI.Scheme (Fetch_URL) is when URI.VCS_Schemes => Raise_Checked_Error ("The remote URL seems to require repository ownership: " & Fetch_URL); when URI.None | URI.Unknown => Publish.Remote_Origin (URL => "git+file:" & Raw_URL, Commit => Commit, Subdir => +Subdir, Options => Options); when URI.File => Publish.Remote_Origin (URL => Raw_URL, Commit => Commit, Subdir => +Subdir, Options => Options); when URI.HTTP => Publish.Remote_Origin (URL => Fetch_URL, Commit => Commit, Subdir => +Subdir, Options => Options); when others => Raise_Checked_Error ("Unsupported scheme: " & Fetch_URL); end case; end; end; end; end Local_Repository; ------------------- -- Remote_Origin -- ------------------- procedure Remote_Origin (URL : Alire.URL; Commit : String := ""; Subdir : Relative_Path := ""; Options : All_Options := New_Options) is begin -- Preliminary argument checks if Has_Suffix (AAA.Strings.To_Lower_Case (URL), ".git") and then Commit = "" then Raise_Checked_Error ("URL seems to point to a repository, but no commit was provided."); end if; -- Verify that subdir is not used with an archive (it is only for VCSs) if Subdir /= "" and then Commit = "" then Raise_Checked_Error ("Cannot publish a nested crate from an archive"); end if; -- Create origin, which will do more checks, and proceed declare Context : Data := (Options => Options, Origin => -- with commit (if Commit /= "" then Origins.New_VCS (URL, Commit, Subdir) -- without commit elsif URI.Scheme (URL) in URI.VCS_Schemes or else VCSs.Git.Known_Transformable_Hosts.Contains (URI.Authority_Without_Credentials (URL)) then raise Checked_Error with "A commit id is mandatory for a VCS origin" -- plain archive else Origins.New_Source_Archive (URL)), Path => <>, -- will remain unused Subdir => +Subdir, Revision => +Commit, Tmp_Deploy_Dir => <>); begin Run_Steps (Context, (Step_Verify_Origin, Step_Verify_Github, Step_Deploy_Sources, Step_Check_Build, Step_Show_And_Confirm, Step_Generate_Index_Manifest)); end; exception when E : Checked_Error | Origins.Unknown_Source_Archive_Format_Error => Log_Exception (E); Raise_Checked_Error (Errors.Wrap ("Could not complete the publishing assistant", Errors.Get (E))); end Remote_Origin; ------------------------- -- Print_Trusted_Sites -- ------------------------- procedure Print_Trusted_Sites is begin for Site of Trusted_Sites loop Trace.Always (Site); end loop; end Print_Trusted_Sites; end Alire.Publish; alire-1.2.1/src/alire/alire-publish.ads000066400000000000000000000043061430264165500177340ustar00rootroot00000000000000with Alire.Roots; with Alire.URI; package Alire.Publish is type All_Options is private; function New_Options (Skip_Build : Boolean := False; Manifest : String := Roots.Crate_File_Name) return All_Options; procedure Directory_Tar (Path : Any_Path := "."; Revision : String := "HEAD"; Options : All_Options := New_Options); -- Publish the release at the given directory, by creating a source archive -- to be uploaded somewhere. Then proceed with Remote_Origin using the -- uploaded archive. If a git repo is at Path, `git archive` will be -- used; otherwise `tar` will be used. procedure Local_Repository (Path : Any_Path := "."; Revision : String := "HEAD"; Options : All_Options := New_Options) with Pre => URI.Scheme (Path) in URI.File_Schemes; -- Check that given Path is an up-to-date git repo. If so, proceed with -- remote repo verification. If no revision given use the HEAD commit, -- otherwise use the revision (tag, branch, commit) commit. procedure Remote_Origin (URL : Alire.URL; Commit : String := ""; Subdir : Relative_Path := ""; Options : All_Options := New_Options); -- Requires a remote URL to a source file or a git repository. Commit is -- mandatory in the latter case. If Subdir is /= "", it is a relative path -- inside a repository with the actual location of a nested crate. Produces -- a file `crate-version.toml` in the current directory or raises -- Checked_Error with the appropriate error message set. procedure Print_Trusted_Sites; -- Print our list of allowed sites to host git releases private type All_Options is tagged record Manifest_File : UString; Skip_Build : Boolean := False; end record; function Manifest (Options : All_Options) return Any_Path is (+Options.Manifest_File); function Nonstandard_Manifest (Options : All_Options) return Boolean is (Options.Manifest /= Roots.Crate_File_Name); end Alire.Publish; alire-1.2.1/src/alire/alire-releases-containers.adb000066400000000000000000000145071430264165500222170ustar00rootroot00000000000000with AAA.Strings; with Alire.Errors; with Semantic_Versioning.Extended; with Semantic_Versioning.Basic; package body Alire.Releases.Containers is -------------------------- -- Contains_Or_Provides -- -------------------------- function Contains_Or_Provides (This : Release_Map; Crate : Crate_Name) return Boolean is (This.Contains (Crate) or else (for some Rel of This => Rel.Provides (Crate))); ------------------------ -- Elements_Providing -- ------------------------ function Elements_Providing (This : Release_Map'Class; Crate : Crate_Name) return Release_Set is Result : Release_Set; begin for Rel of This loop if Rel.Provides (Crate) then Result.Include (Rel); end if; end loop; return Result; end Elements_Providing; -------------- -- From_Set -- -------------- function From_Set (This : Release_Set) return Release_Set_By_Version.Set is begin return Result : Release_Set_By_Version.Set do for Rel of This loop Result.Insert (Rel); end loop; end return; end From_Set; ------------ -- Insert -- ------------ procedure Insert (Dst : in out Release_Map; Src : Releases.Release) is begin Dst.Insert (Src.Name, Src); end Insert; ------------ -- Insert -- ------------ procedure Insert (Dst : in out Release_Map; Src : Release_Map) is begin for E of Src loop Dst.Insert (E); end loop; end Insert; --------------- -- Inserting -- --------------- function Inserting (Dst : Release_Map; Src : Release_Map) return Release_Map is begin return Result : Release_Map := Dst do for E of Src loop Result.Insert (E.Name, E); end loop; end return; end Inserting; --------------- -- Inserting -- --------------- function Inserting (Dst : Release_Map; Src : Releases.Release) return Release_Map is (Dst.Inserting (To_Map (Src))); --------------- -- Excluding -- --------------- function Excluding (Map : Release_Map; Name : Crate_Name) return Release_Map is begin return Filtered : Release_Map := Map do Filtered.Exclude (Name); end return; end Excluding; -------------------- -- Image_One_Line -- -------------------- function Image_One_Line (This : Release_Set) return String is Result : UString; use UStrings; begin for Rel of This loop if Result /= "" then Append (Result, ", "); end if; Append (Result, Rel.Milestone.TTY_Image); end loop; return +Result; end Image_One_Line; --------------- -- Including -- --------------- function Including (Map : Release_Map; Release : Releases.Release) return Release_Map is begin return New_Map : Release_Map := Map do New_Map.Include (Release.Name, Release); end return; end Including; -------------- -- Is_Older -- -------------- function Is_Older (This, Than : Releases.Release) return Boolean is (This.Version < Than.Version or else (This.Version = Than.Version and then This.Version.Build < Than.Version.Build) or else (This.Version = Than.Version and then This.Version.Build = Than.Version.Build and then This.Provides (GNAT_Crate) and then Than.Provides (GNAT_Crate) and then not AAA.Strings.Has_Suffix (This.Name.As_String, "_native") and then AAA.Strings.Has_Suffix (Than.Name.As_String, "_native")) or else (This.Version = Than.Version and then This.Version.Build = Than.Version.Build and then Than.Name < This.Name)); ------------ -- Remove -- ------------ procedure Remove (This : in out Release_Map; Release : Releases.Release) is begin if This.Contains (Release.Name) then This.Exclude (Release.Name); return; else for Mil of Release.Provides loop if This.Contains (Mil.Crate) then This.Exclude (Mil.Crate); return; end if; end loop; end if; raise Constraint_Error with Errors.Set ("Release not in map: " & Release.Milestone.TTY_Image); end Remove; ---------------- -- Satisfying -- ---------------- function Satisfying (This : Release_Set; Dep : Alire.Dependencies.Dependency) return Release_Set is begin return Result : Release_Set do for Release of This loop if Release.Satisfies (Dep) then Result.Include (Release); end if; end loop; end return; end Satisfying; --------------------- -- To_Dependencies -- --------------------- function To_Dependencies (Map : Release_Map) return Conditional.Dependencies is package Semver renames Semantic_Versioning; use Conditional.For_Dependencies; begin return Deps : Conditional.Dependencies do for I in Map.Iterate loop Deps := Deps and Conditional.New_Dependency (Map (I).Name, Semver.Extended.To_Extended (Semver.Basic.Exactly (Map (I).Version))); end loop; end return; end To_Dependencies; ------------ -- To_Map -- ------------ function To_Map (R : Releases.Release) return Release_Map is begin return M : Release_Map do M.Include (R.Name, R); end return; end To_Map; -------------- -- Whenever -- -------------- function Whenever (Map : Release_Map; Props : Alire.Properties.Vector) return Release_Map is begin return Result : Release_Map do for Release of Map loop Result.Insert (Release.Name, Release.Whenever (Props)); end loop; end return; end Whenever; end Alire.Releases.Containers; alire-1.2.1/src/alire/alire-releases-containers.ads000066400000000000000000000105001430264165500222250ustar00rootroot00000000000000with AAA.Containers.Indefinite_Holders; with Ada.Containers.Indefinite_Ordered_Sets; with Optional.Values; package Alire.Releases.Containers is function Release_Image (R : Releases.Release) return String is (R.Milestone.TTY_Image); package Optional_Releases is new Optional.Values (Releases.Release, Release_Image); subtype Optional is Optional_Releases.Optional; package Release_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Releases.Release, Releases."<", Releases."="); type Release_Set is new Release_Sets.Set with null record; Empty_Release_Set : constant Release_Set; function Is_Older (This, Than : Releases.Release) return Boolean; package Release_Set_By_Version is new Ada.Containers.Indefinite_Ordered_Sets (Releases.Release, Is_Older, Releases."="); function From_Set (This : Release_Set) return Release_Set_By_Version.Set; function Image_One_Line (This : Release_Set) return String; function Satisfying (This : Release_Set; Dep : Alire.Dependencies.Dependency) return Release_Set with Post => Satisfying'Result.Is_Empty or else (for all Release of Satisfying'Result => Release.Satisfies (Dep)); package Release_Holders is new AAA.Containers.Indefinite_Holders (Releases.Release); subtype Release_H is Release_Holders.Holder; package Crate_Release_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Releases.Release, "<", Releases."="); type Release_Map is new Crate_Release_Maps.Map with null record; Empty_Release_Map : constant Release_Map; function Excluding (Map : Release_Map; Name : Crate_Name) return Release_Map; function Including (Map : Release_Map; Release : Releases.Release) return Release_Map; -- Finds the current release (if existing) and replaces/adds the new -- Release. procedure Insert (Dst : in out Release_Map; Src : Releases.Release); -- Insert a release under its name as key procedure Insert (Dst : in out Release_Map; Src : Release_Map); function Inserting (Dst : Release_Map; Src : Release_Map) return Release_Map; function Inserting (Dst : Release_Map; Src : Releases.Release) return Release_Map; -- Those insert both under the actual crate name and Provides, if -- different. procedure Remove (This : in out Release_Map; Release : Releases.Release); -- Locate the release, by name or provides, and remove it. Will raise if -- the release is not found. function Contains_Or_Provides (This : Release_Map; Crate : Crate_Name) return Boolean; -- Say if either the crate is a direct member, or provided by one or more -- of the stored releases. function Elements_Providing (This : Release_Map'Class; Crate : Crate_Name) return Release_Set with Pre => This.Contains_Or_Provides (Crate); -- Returns the release that is or provides Crate function To_Dependencies (Map : Release_Map) return Conditional.Dependencies; -- Will filter out duplicates under Provides key (only actual crates will -- remain). function Whenever (Map : Release_Map; Props : Alire.Properties.Vector) return Release_Map; -- Replace every release with one that has no case expressions, using -- environment Props. function To_Map (R : Releases.Release) return Release_Map; function To_Release_H (R : Releases.Release) return Release_H renames Release_Holders.To_Holder; private Empty_Release_Map : constant Release_Map := (Crate_Release_Maps.Empty_Map with null record); Empty_Release_Set : constant Release_Set := (Release_Sets.Empty_Set with null record); end Alire.Releases.Containers; alire-1.2.1/src/alire/alire-releases.adb000066400000000000000000001125611430264165500200530ustar00rootroot00000000000000with Ada.Directories; with Ada.Text_IO; with Alire.Config; with Alire.Crates; with Alire.Directories; with Alire.Defaults; with Alire.Errors; with Alire.Origins.Deployers; with Alire.Paths; with Alire.Properties.Bool; with Alire.Properties.Actions.Executor; with Alire.TOML_Load; with Alire.Utils.YAML; with Alire.Warnings; with GNAT.IO; -- To keep preelaborable with Semantic_Versioning.Basic; with Semantic_Versioning.Extended; with TOML.File_IO; with Ada.Strings.Fixed; package body Alire.Releases is package Semver renames Semantic_Versioning; use all type Alire.Properties.Labeled.Labels; --------- -- "<" -- --------- function "<" (L, R : Release) return Boolean is (if L.Provides (GNAT_Crate) and then R.Provides (GNAT_Crate) then Sort_Compilers (L, R) else Standard_Sorting (L, R)); -------------------- -- All_Properties -- -------------------- function All_Properties (R : Release; P : Alire.Properties.Vector) return Alire.Properties.Vector is (Materialize (R.Properties, P)); ------------------------ -- Default_Properties -- ------------------------ function Default_Properties return Conditional.Properties is (Conditional.For_Properties.New_Value (New_Label (Description, Defaults.Description))); ----------------------- -- Flat_Dependencies -- ----------------------- function Flat_Dependencies (R : Release; P : Alire.Properties.Vector := Alire.Properties.No_Properties) return Alire.Dependencies.Containers.List is begin if P.Is_Empty then -- Trying to evaluate a tree with empty dependencies will result -- in spurious warnings about missing environment properties (as we -- indeed didn't give any). Since we want to get flat dependencies -- that do not depend on any properties, this is indeed safe to do. return Conditional.Enumerate (R.Dependencies); else return Conditional.Enumerate (R.Dependencies.Evaluate (P)); end if; end Flat_Dependencies; ------------------------- -- Check_Caret_Warning -- ------------------------- -- Warn of ^0.x dependencies that probably should be ~0.x function Check_Caret_Warning (This : Release) return Boolean is Newline : constant String := ASCII.LF & " "; begin for Dep of This.Flat_Dependencies loop if Config.DB.Get (Config.Keys.Warning_Caret, Default => True) and then AAA.Strings.Contains (Dep.Versions.Image, "^0") then Warnings.Warn_Once ("Possible tilde intended instead of caret for a 0.x version." & Newline & "Alire does not change the meaning of caret and tilde" & " for pre/post-1.0 versions." & Newline & "The suspicious dependency is: " & TTY.Version (Dep.Image) & Newline & "You can disable this warning by setting the option " & TTY.Emph (Config.Keys.Warning_Caret) & " to false.", Warnings.Caret_Or_Tilde); return True; end if; end loop; return False; end Check_Caret_Warning; ------------------- -- Dependency_On -- ------------------- function Dependency_On (R : Release; Crate : Crate_Name; P : Alire.Properties.Vector := Alire.Properties.No_Properties) return Alire.Dependencies.Containers.Optional is begin for Dep of R.Flat_Dependencies (P) loop if Dep.Crate = Crate then return Alire.Dependencies.Containers.Optionals.Unit (Dep); end if; end loop; return Alire.Dependencies.Containers.Optionals.Empty; end Dependency_On; ----------------- -- Base_Folder -- ----------------- function Base_Folder (R : Release) return Relative_Path is use Directories.Operators; begin if R.Origin.Is_Monorepo then return R.Deployment_Folder / R.Origin.Subdir; else return R.Deployment_Folder; end if; end Base_Folder; ----------------------- -- Deployment_Folder -- ----------------------- function Deployment_Folder (R : Release) return Folder_String is use all type Origins.Kinds; ------------------- -- Monorepo_Path -- ------------------- function Monorepo_Path return Relative_Path is -- For a monorepo we want to reuse the checkout, so instead of the -- name of the release we use the simple name of the URL, no version -- (as a monorepo may contain differently versioned crates) and the -- commit ID. -------------- -- Sanitize -- -------------- -- Repository names may still contain problematic chars, we replace -- all of those with a '_'. function Sanitize (Name : String) return String is begin return Safe : String := Name do for I in Safe'Range loop if Safe (I) & "" not in Folder_String then Safe (I) := '_'; end if; end loop; end return; end Sanitize; ----------------- -- Simple_Name -- ----------------- function Simple_Name (URL : String) return String is -- For local repos, on Windows, we may find '\' in the URL, so -- here we get as simple name of a repo whatever is after the -- last '/' or '\'. begin for I in reverse URL'Range loop if URL (I) in '\' | '/' | ':' then return URL (I + 1 .. URL'Last); end if; end loop; Raise_Checked_Error ("Malformed URL: " & URL); end Simple_Name; begin return Sanitize (Ada.Directories.Base_Name (Simple_Name (R.Origin.URL))) & "_" & (case R.Origin.Kind is when Git | Hg => R.Origin.Short_Unique_Id, when SVN => R.Origin.Commit, when others => raise Program_Error with "monorepo folder only applies to VCS origins"); end Monorepo_Path; ------------------ -- Release_Path -- ------------------ function Release_Path return Relative_Path is ( -- Name of the release R.Name_Str & "_" & -- Version without pre-release/build strings AAA.Strings.Head (AAA.Strings.Head (Image (R.Version), '-'), '+') & "_" & -- Remove patch/build strings that may violate folder valid chars -- Unique hash when available (case R.Origin.Kind is when Binary_Archive => R.Origin.Short_Unique_Id, when External => "external", when Filesystem => "filesystem", when System => "system", when Source_Archive => R.Origin.Short_Unique_Id, when Git | Hg => R.Origin.Short_Unique_Id, when SVN => R.Origin.Commit)); begin if R.Origin.Is_Monorepo then return Monorepo_Path; else return Release_Path; end if; end Deployment_Folder; ------------ -- Deploy -- ------------ procedure Deploy (This : Alire.Releases.Release; Env : Alire.Properties.Vector; Parent_Folder : String; Was_There : out Boolean; Perform_Actions : Boolean := True; Create_Manifest : Boolean := False; Include_Origin : Boolean := False) is use Alire.Directories; use all type Alire.Properties.Actions.Moments; Folder : constant Any_Path := Parent_Folder / This.Deployment_Folder; ------------------------------ -- Backup_Upstream_Manifest -- ------------------------------ procedure Backup_Upstream_Manifest is Working_Dir : Guard (Enter (Folder)) with Unreferenced; begin Ada.Directories.Create_Path (Paths.Working_Folder_Inside_Root); if GNAT.OS_Lib.Is_Regular_File (Paths.Crate_File_Name) then Trace.Debug ("Backing up bundled manifest file as *.upstream"); declare Upstream_File : constant String := Paths.Working_Folder_Inside_Root / (Paths.Crate_File_Name & ".upstream"); begin Alire.Directories.Backup_If_Existing (Upstream_File, Base_Dir => Paths.Working_Folder_Inside_Root); Ada.Directories.Rename (Old_Name => Paths.Crate_File_Name, New_Name => Upstream_File); end; end if; end Backup_Upstream_Manifest; ----------------------------------- -- Create_Authoritative_Manifest -- ----------------------------------- procedure Create_Authoritative_Manifest (Kind : Manifest.Sources) is begin Trace.Debug ("Generating manifest file for " & This.Milestone.TTY_Image & " with" & This.Dependencies.Leaf_Count'Img & " dependencies"); This.Whenever (Env).To_File (Folder / Paths.Crate_File_Name, Kind); end Create_Authoritative_Manifest; begin Trace.Debug ("Deploying " & This.Milestone.TTY_Image & " into " & TTY.URL (Folder)); -- Deploy if the target dir is not already there if Ada.Directories.Exists (Folder) then Was_There := True; Trace.Detail ("Skipping checkout of already available " & This.Milestone.Image); else Was_There := False; Put_Info ("Deploying " & This.Milestone.TTY_Image & "..."); Alire.Origins.Deployers.Deploy (This, Folder).Assert; -- For deployers that do nothing, we ensure the folder exists so all -- dependencies leave a trace in the cache/dependencies folder, and -- a place from where to run their actions by default. Ada.Directories.Create_Path (Folder); -- Backup a potentially packaged manifest, so our authoritative -- manifest from the index is always used. Backup_Upstream_Manifest; if Create_Manifest then Create_Authoritative_Manifest (if Include_Origin then Manifest.Index else Manifest.Local); end if; end if; -- Run post-fetch actions on first retrieval if Perform_Actions and then not Was_There then declare Work_Dir : Guard (Enter (Folder)) with Unreferenced; begin Alire.Properties.Actions.Executor.Execute_Actions (Release => This, Env => Env, Moment => Post_Fetch); exception when E : others => Log_Exception (E); Trace.Warning ("A post-fetch action failed, " & "re-run with -vv -d for details"); end; end if; exception when E : others => -- Clean up if deployment failed after the initial deployment (e.g. -- during an action). Log_Exception (E); if Ada.Directories.Exists (Folder) then Trace.Debug ("Cleaning up failed release deployment of " & This.Milestone.TTY_Image); Directories.Force_Delete (Folder); end if; raise; end Deploy; ---------------- -- Forbidding -- ---------------- function Forbidding (Base : Release; Forbidden : Conditional.Forbidden_Dependencies) return Release is begin return Extended : Release := Base do Extended.Forbidden := Forbidden; end return; end Forbidding; --------------- -- Providing -- --------------- function Providing (Base : Release; Targets : Containers.Crate_Name_Sets.Set) return Release is begin return Result : Release := Base do for Target of Targets loop Result.Equivalences.Append (Milestones.New_Milestone (Target, Base.Version)); end loop; end return; end Providing; --------------- -- Replacing -- --------------- function Replacing (Base : Release; Origin : Origins.Origin) return Release is begin return Replaced : Release := Base do Replaced.Origin := Origin; end return; end Replacing; --------------- -- Replacing -- --------------- function Replacing (Base : Release; Dependencies : Conditional.Dependencies := Conditional.No_Dependencies) return Release is begin return Replaced : Release := Base do Replaced.Dependencies := Dependencies; end return; end Replacing; --------------- -- Replacing -- --------------- function Replacing (Base : Release; Properties : Conditional.Properties := Conditional.No_Properties) return Release is begin return Replaced : Release := Base do Replaced.Properties := Properties; end return; end Replacing; --------------- -- Replacing -- --------------- function Replacing (Base : Release; Notes : Description_String := "") return Release is New_Notes : constant Description_String := (if Notes = "" then Base.Notes else Notes); begin return Replacement : constant Release (Base.Name.Length, New_Notes'Length) := (Prj_Len => Base.Name.Length, Notes_Len => New_Notes'Length, Name => Base.Name, Notes => New_Notes, Version => Base.Version, Origin => Base.Origin, Dependencies => Base.Dependencies, Equivalences => Base.Equivalences, Pins => Base.Pins, Forbidden => Base.Forbidden, Properties => Base.Properties, Available => Base.Available) do null; end return; end Replacing; --------------- -- Retagging -- --------------- function Retagging (Base : Release; Version : Semantic_Versioning.Version) return Release is begin return Upgraded : Release := Base do Upgraded.Version := Version; end return; end Retagging; --------------- -- Upgrading -- --------------- function Upgrading (Base : Release; Version : Semantic_Versioning.Version; Origin : Origins.Origin) return Release is begin return Upgraded : Release := Base do Upgraded.Version := Version; Upgraded.Origin := Origin; end return; end Upgrading; ----------------- -- New_Release -- ----------------- function New_Release (Name : Crate_Name; Version : Semantic_Versioning.Version; Origin : Origins.Origin; Notes : Description_String; Dependencies : Conditional.Dependencies; Properties : Conditional.Properties; Available : Conditional.Availability) return Release is (Prj_Len => Name.Length, Notes_Len => Notes'Length, Name => Name, Version => Version, Origin => Origin, Notes => Notes, Dependencies => Dependencies, Equivalences => <>, Pins => <>, Forbidden => Conditional.For_Dependencies.Empty, Properties => Properties, Available => Available); ----------------------- -- New_Empty_Release -- ----------------------- function New_Empty_Release (Name : Crate_Name) return Release is (New_Working_Release (Name => Name, Properties => Conditional.No_Properties)); ------------------------- -- New_Working_Release -- ------------------------- function New_Working_Release (Name : Crate_Name; Origin : Origins.Origin := Origins.New_Filesystem ("."); Dependencies : Conditional.Dependencies := Conditional.For_Dependencies.Empty; Properties : Conditional.Properties := Default_Properties) return Release is (Prj_Len => Name.Length, Notes_Len => 0, Name => Name, Version => +"0.0.0", Origin => Origin, Notes => "", Dependencies => Dependencies, Equivalences => <>, Pins => <>, Forbidden => Conditional.For_Dependencies.Empty, Properties => Properties, Available => Conditional.Empty ); ------------------------- -- On_Platform_Actions -- ------------------------- function On_Platform_Actions (R : Release; P : Alire.Properties.Vector; Moments : Moment_Array := (others => True)) return Alire.Properties.Vector is use Alire.Properties.Actions; begin return Filtered : Alire.Properties.Vector do for Prop of R.On_Platform_Properties (P, Alire.Properties.Actions.Action'Tag) loop if Moments (Action'Class (Prop).Moment) then Filtered.Append (Prop); end if; end loop; end return; end On_Platform_Actions; ---------------------------- -- On_Platform_Properties -- ---------------------------- function On_Platform_Properties (R : Release; P : Alire.Properties.Vector; Descendant_Of : Ada.Tags.Tag := Ada.Tags.No_Tag) return Alire.Properties.Vector is use Ada.Tags; begin if Descendant_Of = No_Tag then return Materialize (R.Properties, P); else declare Props : constant Alire.Properties.Vector := R.On_Platform_Properties (P); begin return Result : Alire.Properties.Vector do for P of Props loop if Is_Descendant_At_Same_Level (P'Tag, Descendant_Of) then Result.Append (P); end if; end loop; end return; end; end if; end On_Platform_Properties; ---------------------- -- Props_To_Strings -- ---------------------- function Props_To_Strings (Props : Alire.Properties.Vector; Label : Alire.Properties.Labeled.Labels) return AAA.Strings.Vector is -- Extract values of a particular label Filtered : constant Alire.Properties.Vector := Alire.Properties.Labeled.Filter (Props, Label); begin return Strs : AAA.Strings.Vector do for P of Filtered loop Strs.Append (Alire.Properties.Labeled.Label (P).Value); end loop; end return; end Props_To_Strings; ----------------- -- Environment -- ----------------- function Environment (R : Release; P : Alire.Properties.Vector) return Env_Maps.Map is package Env renames Alire.Properties.Environment; begin return Map : Env_Maps.Map do for Prop of R.On_Platform_Properties (P, Env.Variable'Tag) loop Map.Insert (Env.Variable (Prop).Name, Env.Variable (Prop)); end loop; end return; end Environment; ----------------- -- Executables -- ---------------- function Executables (R : Release; P : Alire.Properties.Vector) return AAA.Strings.Vector is Exes : constant AAA.Strings.Vector := Props_To_Strings (R.All_Properties (P), Executable); begin if OS_Lib.Exe_Suffix /= "" then declare With_Suffix : AAA.Strings.Vector; begin for I in Exes.Iterate loop With_Suffix.Append (Exes (I) & OS_Lib.Exe_Suffix); end loop; return With_Suffix; end; end if; return Exes; end Executables; ------------------- -- Project_Files -- ------------------- function Project_Files (R : Release; P : Alire.Properties.Vector; With_Path : Boolean) return AAA.Strings.Vector is use AAA.Strings; With_Paths : AAA.Strings.Vector := Props_To_Strings (R.All_Properties (P), Project_File); Without : AAA.Strings.Vector; begin if With_Paths.Is_Empty and then R.Origin.Kind not in Origins.External | Origins.System then -- Default project file if no one is specified by the crate. Only if -- the create is not external nor system. With_Paths.Append (String'((+R.Name) & ".gpr")); end if; if With_Path then return With_Paths; else for File of With_Paths loop -- Basename Without.Append (Split (Text => File, Separator => '/', Side => Tail, From => Tail, Raises => False)); end loop; return Without; end if; end Project_Files; ------------------- -- Project_Paths -- ------------------- function Project_Paths (R : Release; P : Alire.Properties.Vector) return AAA.Strings.Set is use Ada.Strings; use AAA.Strings; Files : constant AAA.Strings.Vector := Project_Files (R, P, With_Path => True); begin return Paths : AAA.Strings.Set do for File of Files loop if Contains (File, "/") then Paths.Include (File (File'First .. Fixed.Index (File, "/", Backward))); else -- The project file is at the root of the release Paths.Include (""); end if; end loop; end return; end Project_Paths; ------------------- -- Auto_GPR_With -- ------------------- function Auto_GPR_With (R : Release) return Boolean is Vect : constant Alire.Properties.Vector := Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Auto_GPR_With); begin if not Vect.Is_Empty then return Alire.Properties.Bool.Property (Vect.First_Element).Value; else -- The default is to enable auto-gpr-with return True; end if; end Auto_GPR_With; ------------------ -- Has_Property -- ------------------ function Has_Property (R : Release; Key : String) return Boolean is (for some Prop of Conditional.Enumerate (R.Properties) => Prop.Key = AAA.Strings.To_Lower_Case (Key)); ------------------------ -- Labeled_Properties -- ------------------------ function Labeled_Properties_Vector (R : Release; P : Alire.Properties.Vector; Label : Alire.Properties.Labeled.Labels) return Alire.Properties.Vector is begin return Alire.Properties.Labeled.Filter (R.All_Properties (P), Label); end Labeled_Properties_Vector; ------------------------ -- Labeled_Properties -- ------------------------ function Labeled_Properties (R : Release; P : Alire.Properties.Vector; Label : Alire.Properties.Labeled.Labels) return AAA.Strings.Vector is begin return Props_To_Strings (R.All_Properties (P), Label); end Labeled_Properties; ----------- -- Print -- ----------- procedure Print (R : Release) is use GNAT.IO; begin -- MILESTONE Put_Line (R.Milestone.TTY_Image & ": " & R.TTY_Description); if not R.Equivalences.Is_Empty then Put_Line ("Provides: " & R.Equivalences.Image_One_Line); end if; if R.Notes /= "" then Put_Line ("Notes: " & R.Notes); end if; -- ORIGIN Put_Line ("Origin: " & R.Origin.Image); -- AVAILABILITY if not R.Available.Is_Empty then Put_Line ("Available when: " & R.Available.Image_One_Line); end if; -- PROPERTIES if not R.Properties.Is_Empty then Put_Line ("Properties:"); R.Properties.Print (" ", And_Or => False, Verbose => Alire.Log_Level >= Detail); end if; -- DEPENDENCIES if not R.Dependencies.Is_Empty then Put_Line ("Dependencies (direct):"); R.Dependencies.Print (" ", Sorted => True, And_Or => R.Dependencies.Contains_ORs); end if; -- PINS if not R.Pins.Is_Empty then Put_Line ("Pins (direct):"); R.Pins.Print (Prefix => " "); end if; end Print; -------------- -- Property -- -------------- function Property (R : Release; Key : Alire.Properties.Labeled.Labels) return String is use Alire.Properties.Labeled; Target : constant Alire.Properties.Vector := Filter (R.Properties, Key); begin if Target.Length not in 1 then raise Constraint_Error with "Unexpected property count:" & Target.Length'Img; end if; return Label (Target.First_Element).Value; end Property; ----------------------- -- Property_Contains -- ----------------------- function Property_Contains (R : Release; Str : String) return Boolean is use AAA.Strings; Search : constant String := To_Lower_Case (Str); begin for P of Conditional.Enumerate (R.Properties) loop declare Text : constant String := To_Lower_Case ((if Contains (P.Image, ":") then Tail (P.Image, ':') else P.Image)); begin if Contains (Text, Search) then return True; end if; end; end loop; return False; end Property_Contains; ------------------- -- From_Manifest -- ------------------- function From_Manifest (File_Name : Any_Path; Source : Manifest.Sources; Strict : Boolean) return Release is begin return From_TOML (TOML_Adapters.From (TOML_Load.Load_File (File_Name), "Loading release from manifest: " & File_Name), Source, Strict, File_Name); exception when E : others => Log_Exception (E); -- As this file is edited manually, it may not load for many reasons Raise_Checked_Error (Errors.Wrap ("Failed to load " & File_Name, Errors.Get (E))); end From_Manifest; --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue; Source : Manifest.Sources; Strict : Boolean; File : Any_Path := "") return Release is begin From.Assert_Key (TOML_Keys.Name, TOML.TOML_String); return This : Release := New_Empty_Release (Name => +From.Unwrap.Get (TOML_Keys.Name).As_String) do Assert (This.From_TOML (From, Source, Strict, File)); end return; end From_TOML; --------------- -- From_TOML -- --------------- function From_TOML (This : in out Release; From : TOML_Adapters.Key_Queue; Source : Manifest.Sources; Strict : Boolean; File : Any_Path := "") return Outcome is package Dirs renames Ada.Directories; package Labeled renames Alire.Properties.Labeled; begin Trace.Debug ("Loading release " & This.Milestone.Image); -- Origin case Source is when Manifest.Index => This.Origin.From_TOML (From).Assert; when Manifest.Local => This.Origin := Origins.New_Filesystem (Dirs.Containing_Directory -- same folder as manifest file's (Dirs.Full_Name (File))); -- absolute path -- We don't require an origin for a local release, as the release -- is already in place. end case; -- Properties TOML_Load.Load_Crate_Section (Strict => Strict or else Source in Manifest.Local, Section => (case Source is when Manifest.Index => Crates.Index_Release, when Manifest.Local => Crates.Local_Release), From => From, Props => This.Properties, Deps => This.Dependencies, Equiv => This.Equivalences, Forbids => This.Forbidden, Pins => This.Pins, Avail => This.Available); -- Consolidate/validate some properties as fields: Assert (This.Name_Str = This.Property (Labeled.Name), "Mismatched name property and given name at release creation"); This.Version := Semver.New_Version (This.Property (Labeled.Version)); -- Check for remaining keys, which must be erroneous: return From.Report_Extra_Keys; end From_TOML; ------------------- -- To_Dependency -- ------------------- function To_Dependency (R : Release) return Conditional.Dependencies is (Conditional.For_Dependencies.New_Value (Alire.Dependencies.New_Dependency (R.Name, Semver.Extended.To_Extended (Semver.Basic.Exactly (R.Version))))); ------------- -- To_File -- ------------- procedure To_File (R : Release; Filename : String; Format : Manifest.Sources) is use Ada.Text_IO; File : File_Type; begin Create (File, Out_File, Filename); TOML.File_IO.Dump_To_File (R.To_TOML (Format), File); Close (File); exception when others => if Is_Open (File) then Close (File); end if; raise; end To_File; ------------- -- To_TOML -- ------------- function To_TOML (R : Release; Format : Manifest.Sources) return TOML.TOML_Value is package APL renames Alire.Properties.Labeled; use all type Alire.Properties.Labeled.Cardinalities; use TOML_Adapters; Root : constant TOML.TOML_Value := R.Properties.To_TOML; begin -- Name Root.Set (TOML_Keys.Name, +R.Name_Str); -- Version Root.Set (TOML_Keys.Version, +Semver.Image (R.Version)); -- Provided equivalences if not R.Equivalences.Is_Empty then Root.Set (TOML_Keys.Provides, R.Equivalences.To_TOML); end if; -- Notes if R.Notes'Length > 0 then Root.Set (TOML_Keys.Notes, +R.Notes); end if; -- Ensure atoms are atoms and arrays are arrays for Label in APL.Cardinality'Range loop if Root.Has (APL.Key (Label)) then case APL.Cardinality (Label) is when Unique => pragma Assert (Root.Get (APL.Key (Label)).Kind in TOML.Atom_Value_Kind); when Multiple => Root.Set (APL.Key (Label), TOML_Adapters.To_Array (Root.Get (APL.Key (Label)))); end case; end if; end loop; -- Origin case Format is when Manifest.Index => Root.Set (TOML_Keys.Origin, R.Origin.To_TOML); when Manifest.Local => null; end case; -- Dependencies, wrapped as an array if not R.Dependencies.Is_Empty then declare Dep_Array : constant TOML.TOML_Value := TOML.Create_Array; begin Dep_Array.Append (R.Dependencies.To_TOML); Root.Set (TOML_Keys.Depends_On, Dep_Array); end; end if; -- Forbidden, wrapped as an array if not R.Forbidden.Is_Empty then declare Forbid_Array : constant TOML.TOML_Value := TOML.Create_Array; begin Forbid_Array.Append (R.Forbidden.To_TOML); Root.Set (TOML_Keys.Forbidden, Forbid_Array); end; end if; -- Available if R.Available.Is_Empty or else R.Available.Value.Is_Available then null; -- Do nothing, do not pollute .toml file else Root.Set (TOML_Keys.Available, R.Available.To_TOML); end if; return Root; end To_TOML; ------------- -- To_YAML -- ------------- overriding function To_YAML (R : Release) return String is function Props_To_YAML is new Utils.YAML.To_YAML (Alire.Properties.Property'Class, Alire.Properties.Vectors, Alire.Properties.Vector); Deps : constant String := R.Dependencies.To_YAML; begin return "crate: " & Utils.YAML.YAML_Stringify (R.Name_Str) & ASCII.LF & "authors: " & Props_To_YAML (R.Author) & ASCII.LF & "maintainers: " & Props_To_YAML (R.Maintainer) & ASCII.LF & "licenses: " & Props_To_YAML (R.License) & ASCII.LF & "websites: " & Props_To_YAML (R.Website) & ASCII.LF & "tags: " & Props_To_YAML (R.Tag) & ASCII.LF & "version: " & Utils.YAML.YAML_Stringify (R.Version_Image) & ASCII.LF & "short_description: " & Utils.YAML.YAML_Stringify (R.Description) & ASCII.LF & "dependencies: " & (if Deps'Length = 0 or else Deps (Deps'First) /= '[' then -- Add array brackets when there's only one -- dependency or no dependency. "[" & Deps & "]" else Deps) & ASCII.LF & "configuration_variables: " & Props_To_YAML (R.Config_Variables) & ASCII.LF & "configuration_values: " & Props_To_YAML (R.Config_Settings) & ASCII.LF; end To_YAML; ------------- -- Version -- ------------- function Version (R : Release) return Semantic_Versioning.Version is (R.Version); -------------- -- Whenever -- -------------- function Whenever (R : Release; P : Alire.Properties.Vector) return Release is (Prj_Len => R.Prj_Len, Notes_Len => R.Notes_Len, Name => R.Name, Version => R.Version, Origin => R.Origin.Whenever (P), Notes => R.Notes, Dependencies => R.Dependencies.Evaluate (P), Equivalences => R.Equivalences, Pins => R.Pins, Forbidden => R.Forbidden.Evaluate (P), Properties => R.Properties.Evaluate (P), Available => R.Available.Evaluate (P)); ---------------------- -- Long_Description -- ---------------------- function Long_Description (R : Release) return String is Descr : constant Alire.Properties.Vector := Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Long_Descr); begin if not Descr.Is_Empty then -- Image returns "Description: Blah" so we have to cut. return AAA.Strings.Tail (Descr.First_Element.Image, ' '); else return ""; end if; end Long_Description; -------------------- -- Sort_Compilers -- -------------------- function Sort_Compilers (L, R : Release) return Boolean is ----------------- -- Is_External -- ----------------- function Is_External (This : Release) return Boolean is (This.Name = GNAT_External_Crate); --------------- -- Is_Native -- --------------- function Is_Native (This : Release) return Boolean is begin return AAA.Strings.Has_Suffix (This.Name.As_String, "_native"); -- A lil' bit of magic to recognize the native compilers end Is_Native; begin -- External is preferred to any other compiler. This can be overridden -- by explicitly selecting a compiler with `alr toolchain --select`, or -- by specifying a targeted gnat_xxx compiler. if Is_External (L) xor Is_External (R) then return Is_External (R); end if; -- Native goes next in preferences (preferred to cross-compilers) if Is_Native (L) xor Is_Native (R) then return Is_Native (R); end if; -- otherwise same ordering as regular crates return Standard_Sorting (L, R); end Sort_Compilers; end Alire.Releases; alire-1.2.1/src/alire/alire-releases.ads000066400000000000000000000470421430264165500200750ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; with Ada.Tags; with AAA.Strings; with Alire.Conditional; with Alire.Containers; with Alire.Dependencies.Containers; with Alire.Interfaces; with Alire.Manifest; with Alire.Milestones; with Alire.Origins; with Alire.Properties.Actions; with Alire.Properties.Environment; with Alire.Properties.Labeled; with Alire.Properties.Licenses; with Alire.Provides; with Alire.TOML_Adapters; with Alire.TOML_Keys; with Alire.User_Pins.Maps; with Alire.Utils; with Semantic_Versioning; with TOML; private with Alire.OS_Lib; private with CLIC.TTY; private with Alire.Utils.TTY; package Alire.Releases is type Release (<>) is new Interfaces.Yamlable with private; function "<" (L, R : Release) return Boolean; -- Sorts by name, version, and build within same version function Default_Properties return Conditional.Properties; -- Returns the values in Defaults already wrapped as properties function New_Release (Name : Crate_Name; Version : Semantic_Versioning.Version; Origin : Origins.Origin; Notes : Description_String; Dependencies : Conditional.Dependencies; Properties : Conditional.Properties; Available : Conditional.Availability) return Release; function New_Empty_Release (Name : Crate_Name) return Release; -- Equivalent to calling New_Working_Release with default values BUT with -- empty properties (i.e., defaults are not used). function New_Working_Release (Name : Crate_Name; Origin : Origins.Origin := Origins.New_Filesystem ("."); Dependencies : Conditional.Dependencies := Conditional.For_Dependencies.Empty; Properties : Conditional.Properties := Default_Properties ) return Release; -- For working releases that may have incomplete information. Note that the -- default properties are used by default. function Replacing (Base : Release; Notes : Description_String := "") return Release; -- Takes a release and replaces the given fields function Replacing (Base : Release; Dependencies : Conditional.Dependencies := Conditional.No_Dependencies) return Release; function Replacing (Base : Release; Properties : Conditional.Properties := Conditional.No_Properties) return Release; function Replacing (Base : Release; Origin : Origins.Origin) return Release; function Retagging (Base : Release; Version : Semantic_Versioning.Version) return Release; -- Keep all data but version function Upgrading (Base : Release; Version : Semantic_Versioning.Version; Origin : Origins.Origin) return Release; -- Takes a release and replaces version and origin function Forbidding (Base : Release; Forbidden : Conditional.Forbidden_Dependencies) return Release; -- Add forbidden dependencies to a release function Providing (Base : Release; Targets : Containers.Crate_Name_Sets.Set) return Release; -- Add an equivalence to Target=Base.Version for all Target of Targets -- (which may be empty). function Whenever (R : Release; P : Properties.Vector) return Release; -- Materialize conditions in a Release once the whatever properties are -- known. At present dependencies, properties, and availability. function Name (R : Release) return Crate_Name; function Name_Str (R : Release) return String is (+R.Name); function TTY_Name (R : Release) return String; function Description (R : Release) return Description_String; -- Returns the description for the crate, which is also stored as a -- property of the release. function TTY_Description (R : Release) return String; -- Colorized description function Long_Description (R : Release) return String; -- Returns the long description for the crate, which is also stored as a -- property of the release. function Forbidden (R : Release) return Conditional.Dependencies; -- Get all forbidden dependencies in platform-independent fashion function Forbidden (R : Release; P : Alire.Properties.Vector) return Conditional.Forbidden_Dependencies; -- Get platform-specific forbidden dependencies function Notes (R : Release) return Description_String; -- Specific to release function Version (R : Release) return Semantic_Versioning.Version; function Dependencies (R : Release) return Conditional.Dependencies; -- Retrieve dependencies as-is from the TOML description function Dependencies (R : Release; P : Alire.Properties.Vector) return Conditional.Dependencies; -- Retrieve only the dependencies that apply on platform P function Dependency_On (R : Release; Crate : Crate_Name; P : Alire.Properties.Vector := Alire.Properties.No_Properties) return Alire.Dependencies.Containers.Optional; -- If R.Flat_Dependencies contains Crate, that dependency will be returned, -- Empty otherwise. function Depends_On (R : Release; Crate : Crate_Name; P : Alire.Properties.Vector := Alire.Properties.No_Properties) return Boolean is (R.Dependency_On (Crate, P).Has_Element); function Flat_Dependencies (R : Release; P : Alire.Properties.Vector := Alire.Properties.No_Properties) return Alire.Dependencies.Containers.List; -- Remove any and/or nodes and return dependencies as a simple list. This -- is useful whenever you need to inspect all direct dependencies, no -- matter how they will be solved. If P is not empty, this function -- also works for platform-dependent dependencies only. function Provides (R : Release) return Provides.Equivalences; function Provides (R : Release; Target : Crate_Name) return Boolean; -- Say if one of this release Provides milestones is for Target, in -- addition to R.Name = Target. function Provides (R : Release; Target : Release) return Boolean; -- Check whether R and Target have the same name or provide the same name function Property (R : Release; Key : Alire.Properties.Labeled.Labels) return String; -- Return a property that must exist, be unique, platform-independent, and -- and atomic label: description, version... Raise otherwise. function Properties (R : Release) return Conditional.Properties; function Origin (R : Release) return Origins.Origin; function Available (R : Release) return Conditional.Availability; function Is_Available (R : Release; P : Alire.Properties.Vector) return Boolean; -- Evaluate R.Available under platform properties P function Default_Executable (R : Release) return String; -- We encapsulate here the fixing of platform extension package Env_Maps is new Ada.Containers.Indefinite_Ordered_Maps (String, Alire.Properties.Environment.Variable, "<", Alire.Properties.Environment."="); function Environment (R : Release; P : Alire.Properties.Vector) return Env_Maps.Map; -- Retrieve env vars that are set by this release, key is the var name function Executables (R : Release; P : Alire.Properties.Vector) return AAA.Strings.Vector; -- Only explicitly declared ones -- Under some conditions (usually current platform) function Pins (R : Release) return User_Pins.Maps.Map; function Project_Paths (R : Release; P : Alire.Properties.Vector) return AAA.Strings.Set; -- Deduced from Project_Files function Project_Files (R : Release; P : Alire.Properties.Vector; With_Path : Boolean) return AAA.Strings.Vector; -- with relative path on demand function Deployment_Folder (R : Release) return Folder_String; -- The folder under which the release origin will be deployed function Base_Folder (R : Release) return Relative_Path; -- Deployment_Folder / (if R in monorepo, rel_path to it, else "") -- NOTE: property retrieval functions do not distinguish between -- public/private, since that's merely informative for the users. type Moment_Array is array (Alire.Properties.Actions.Moments) of Boolean; -- Used to select which actions to retrieve function On_Platform_Actions (R : Release; P : Alire.Properties.Vector; Moments : Moment_Array := (others => True)) return Alire.Properties.Vector; -- Get only Action properties for the platform that apply at specific -- moments. function On_Platform_Properties (R : Release; P : Alire.Properties.Vector; Descendant_Of : Ada.Tags.Tag := Ada.Tags.No_Tag) return Alire.Properties.Vector; -- Return properties that apply to R under platform properties P function Labeled_Properties_Vector (R : Release; P : Alire.Properties.Vector; Label : Alire.Properties.Labeled.Labels) return Alire.Properties.Vector; -- Return properties of Labeled class for a particular label function Labeled_Properties (R : Release; P : Alire.Properties.Vector; Label : Alire.Properties.Labeled.Labels) return AAA.Strings.Vector; -- Get all values for a given property for a given platform properties function Author (R : Release) return Alire.Properties.Vector; function License (R : Release) return Alire.Properties.Vector; function Maintainer (R : Release) return Alire.Properties.Vector; function Milestone (R : Release) return Milestones.Milestone; function Website (R : Release) return Alire.Properties.Vector with Post => Natural (Website'Result.Length) <= 1; -- Website is optional and unique in the index spec. function Tag (R : Release) return Alire.Properties.Vector; function Config_Variables (R : Release) return Alire.Properties.Vector; function Config_Settings (R : Release) return Alire.Properties.Vector; function Auto_GPR_With (R : Release) return Boolean; procedure Print (R : Release); -- Dump info to console -- Search helpers function Property_Contains (R : Release; Str : String) return Boolean; -- True if some property contains the given string function Satisfies (R : Release; Dep : Alire.Dependencies.Dependency'Class) return Boolean; -- Ascertain if this release is a valid candidate for Dep function To_Dependency (R : Release) return Conditional.Dependencies; -- Return the dependency that represents this very release (crate=version), -- wrapped as a dependency tree with a single value. function From_Manifest (File_Name : Any_Path; Source : Manifest.Sources; Strict : Boolean) return Release; function From_TOML (From : TOML_Adapters.Key_Queue; Source : Manifest.Sources; Strict : Boolean; File : Any_Path := "") return Release with Pre => Source not in Manifest.Local or else File /= ""; -- Load a release from a TOML table. We require the manifest file for local -- manifests to be able to construct a local filesystem origin. function To_TOML (R : Release; Format : Manifest.Sources) return TOML.TOML_Value; -- Convert the manifest to TOML. This is done currently only for a concrete -- platform, hence R.Whenever should have been already called. overriding function To_YAML (R : Release) return String; procedure To_File (R : Release; Filename : String; Format : Manifest.Sources); -- Directly write the release manifest to a file function Version_Image (R : Release) return String; function Has_Property (R : Release; Key : String) return Boolean; -- Say if the property exists in any branch of the property tree. Key is -- case-insensitive. function Check_Caret_Warning (This : Release) return Boolean; -- Check if this release contains a ^0.x dependency, and warn about it. -- Returns whether a warning was emitted. procedure Deploy (This : Release; Env : Alire.Properties.Vector; Parent_Folder : String; Was_There : out Boolean; Perform_Actions : Boolean := True; Create_Manifest : Boolean := False; Include_Origin : Boolean := False); -- Deploy the sources of this release under the given Parent_Folder. If -- Create_Manifest, any packaged manifest will be moved out of the way -- and an authoritative manifest will be generated from index information. -- The created manifest may optionally Include_Origin information. private use Semantic_Versioning; function Materialize is new Conditional.For_Properties.Materialize (Alire.Properties.Vector, Alire.Properties.Append); function All_Properties (R : Release; P : Alire.Properties.Vector) return Alire.Properties.Vector; -- Properties that R has under platform properties P type Release (Prj_Len, Notes_Len : Natural) is new Interfaces.Yamlable with record Name : Crate_Name (Prj_Len); Version : Semantic_Versioning.Version; Origin : Origins.Origin; Notes : Description_String (1 .. Notes_Len); Equivalences : Alire.Provides.Equivalences; Dependencies : Conditional.Dependencies; Pins : User_Pins.Maps.Map; Forbidden : Conditional.Dependencies; Properties : Conditional.Properties; Available : Conditional.Availability; end record; function From_TOML (This : in out Release; From : TOML_Adapters.Key_Queue; Source : Manifest.Sources; Strict : Boolean; File : Any_Path := "") return Outcome with Pre => Source not in Manifest.Local or else File /= ""; -- Fill in an already existing release. We require the manifest file -- location for local releases to be able to construct a local file origin. use all type Conditional.Properties; function Sort_Compilers (L, R : Release) return Boolean; -- For the special case of crates providing a compiler, we prefer the -- native compilers before the cross-compilers. function Standard_Sorting (L, R : Release) return Boolean is (R.Name < L.Name -- So when going from newest to oldest the order is OK or else (L.Name = R.Name and then L.Version < R.Version) or else (L.Name = R.Name and then L.Version = R.Version and then Build (L.Version) < Build (R.Version))); function Name (R : Release) return Crate_Name is (R.Name); function TTY_Name (R : Release) return String is (Utils.TTY.Name (+R.Name)); function Notes (R : Release) return Description_String is (R.Notes); function Dependencies (R : Release) return Conditional.Dependencies is (R.Dependencies); function Dependencies (R : Release; P : Alire.Properties.Vector) return Conditional.Dependencies is (R.Dependencies.Evaluate (P)); function Provides (R : Release) return Alire.Provides.Equivalences is (R.Equivalences); function Provides (R : Release; Target : Crate_Name) return Boolean is (R.Name = Target or else (for some Mil of R.Equivalences => Mil.Crate = Target)); function Provides (R : Release; Target : Release) return Boolean is (R.Provides (Target.Name) or else Target.Provides (R.Name) or else (for some Mil_1 of R.Equivalences => Mil_1.Crate = Target.Name or else (for some Mil_2 of Target.Equivalences => Mil_2.Crate = R.Name or else Mil_1.Crate = Mil_2.Crate))); function Forbidden (R : Release) return Conditional.Dependencies is (R.Forbidden); function Forbidden (R : Release; P : Alire.Properties.Vector) return Conditional.Forbidden_Dependencies is (R.Forbidden.Evaluate (P)); function Properties (R : Release) return Conditional.Properties is (R.Properties); function Origin (R : Release) return Origins.Origin is (R.Origin); function Available (R : Release) return Conditional.Availability is (R.Available); function Is_Available (R : Release; P : Alire.Properties.Vector) return Boolean is (R.Available.Is_Available (P) and then R.Origin.Is_Available (P)); function Description (R : Release) return Description_String -- Image returns "Description: Blah" so we have to cut. is (AAA.Strings.Tail (Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Description).First_Element.Image, ' ')); function TTY_Description (R : Release) return String is (CLIC.TTY.Description (R.Description)); function Milestone (R : Release) return Milestones.Milestone is (Milestones.New_Milestone (R.Name, R.Version)); function Default_Executable (R : Release) return String is (AAA.Strings.Replace (+R.Name, ":", "_") & OS_Lib.Exe_Suffix); function License (R : Release) return Alire.Properties.Vector is (Conditional.Enumerate (R.Properties).Filter (Alire.Properties.Licenses.License'Tag)); function Author (R : Release) return Alire.Properties.Vector is (Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Author)); function Maintainer (R : Release) return Alire.Properties.Vector is (Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Maintainer)); function Website (R : Release) return Alire.Properties.Vector is (Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Website)); function Tag (R : Release) return Alire.Properties.Vector is (Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Tag)); function Config_Variables (R : Release) return Alire.Properties.Vector is (Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Config_Vars)); function Config_Settings (R : Release) return Alire.Properties.Vector is (Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Config_Values)); function Satisfies (R : Release; Dep : Alire.Dependencies.Dependency'Class) return Boolean is ((R.Name = Dep.Crate and then Dep.Versions.Contains (R.Version)) or else R.Equivalences.Satisfies (Dep)); function Version_Image (R : Release) return String is (Semantic_Versioning.Image (R.Version)); function Pins (R : Release) return User_Pins.Maps.Map is (R.Pins); end Alire.Releases; alire-1.2.1/src/alire/alire-root.adb000066400000000000000000000006201430264165500172230ustar00rootroot00000000000000with Alire.Directories; package body Alire.Root is ------------- -- Current -- ------------- function Current return Roots.Optional.Root is (Roots.Optional.Detect_Root (Directories.Detect_Root_Path)); ------------- -- Current -- ------------- function Current return Roots.Root is (Roots.Optional.Detect_Root (Directories.Detect_Root_Path).Value); end Alire.Root; alire-1.2.1/src/alire/alire-root.ads000066400000000000000000000012231430264165500172440ustar00rootroot00000000000000with Alire.Platforms.Current; with Alire.Properties; with Alire.Roots.Optional; package Alire.Root is -- NOTE: Detecting and loading roots is expensive, so it should be done as -- few times as possible. Once a valid root is obtained, just reuse it. function Current return Roots.Root; -- Returns the current root, that must exist, or raises Checked_Error function Current return Roots.Optional.Root; -- Returns an optional root, that may be empty if none detected, or broken -- if the manifest is not loadable. function Platform_Properties return Properties.Vector renames Platforms.Current.Properties; end Alire.Root; alire-1.2.1/src/alire/alire-roots-editable.adb000066400000000000000000000365551430264165500211750ustar00rootroot00000000000000with Alire.Conditional; with Alire.Dependencies.Diffs; with Alire.Directories; with Alire.Manifest; with Alire.Origins; with Alire.Roots.Optional; with Alire.User_Pins; with Alire.Utils.User_Input; with Alire.VCSs.Git; with Semantic_Versioning.Extended; package body Alire.Roots.Editable is package Semver renames Semantic_Versioning; -------------- -- New_Root -- -------------- function New_Root (Original : in out Roots.Root) return Root is begin return Result : Root do Result.Orig := Original; Result.Edit := Roots.Root (Original.Temporary_Copy); Result.Edit.Sync_Pins_From_Manifest (Exhaustive => False); end return; end New_Root; ------------------------ -- Confirm_And_Commit -- ------------------------ procedure Confirm_And_Commit (This : in out Root) is Original : Roots.Root renames This.Orig; Edited : Roots.Root renames This.Edit; begin declare Dep_Diff : constant Dependencies.Diffs.Diff := Dependencies.Diffs.Between (Former => Release (Original) .Dependencies (Original.Environment), Latter => Release (Edited) .Dependencies (Edited.Environment)); begin -- First show requested changes if Dep_Diff.Contains_Changes then Trace.Info ("Requested changes:"); Trace.Info (""); Dep_Diff.Print; end if; -- Compute the new solution Edited.Set (Solution => Edited.Compute_Update); -- Then show the effects on the solution if Alire.Utils.User_Input.Confirm_Solution_Changes (Original.Solution.Changes (Edited.Solution), Changed_Only => not Alire.Detailed) then Edited.Commit; else Trace.Info ("No changes applied."); end if; end; end Confirm_And_Commit; -------------------- -- Add_Dependency -- -------------------- procedure Add_Dependency (This : in out Root; Dep : Dependencies.Dependency) is -------------------- -- Find_Updatable -- -------------------- function Find_Updatable return Dependencies.Dependency is begin -- Solve with the new dependency and take the updatable set for the -- version in the solution. Trace.Debug ("Attempting to narrow down dependency for new crate " & Dep.TTY_Image); declare use type Conditional.For_Dependencies.Tree; Sol : constant Solutions.Solution := Solver.Resolve (Deps => Release (This.Edit) .Dependencies (This.Edit.Environment) and Dep, Props => This.Edit.Environment, Pins => This.Edit.Pins); begin if Sol.State (Dep.Crate).Has_Release then return Dependencies.New_Dependency (Crate => Dep.Crate, Versions => Semver.Updatable (Sol.State (Dep.Crate).Release.Version)); else return Dep; end if; exception when Query_Unsuccessful => Put_Warning ("No solution found when adding dependency: " & Dep.TTY_Image); return Dep; end; end Find_Updatable; begin -- Do not add if already a direct dependency if Release (This.Edit).Depends_On (Dep.Crate, This.Edit.Environment) then raise Checked_Error with Errors.Set (Utils.TTY.Name (Dep.Crate) & " is already a direct dependency."); end if; -- If we are given an Any dependency, attempt a solving to narrow down -- to a "safely updatable" subset. declare Dep : constant Dependencies.Dependency := (if Add_Dependency.Dep.Versions.Is_Any then Find_Updatable else Add_Dependency.Dep); begin Alire.Manifest.Append (Crate_File (This.Edit), Dep); This.Reload_Manifest; This.Edit.Set (This.Solution.Missing (Dep)); end; end Add_Dependency; ----------------------- -- Remove_Dependency -- ----------------------- procedure Remove_Dependency (This : in out Root; Crate : Crate_Name; Unpin : Boolean := True) is begin -- If dependency is not among dependencies at all, nothing to do if not Release (This.Edit).Depends_On (Crate) then Raise_Checked_Error ("Requested crate is not among direct dependencies."); end if; -- If dependency is not among the top-level direct dependencies, this is -- a dynamic dependency if not Release (This.Edit).Dependencies.Is_Iterable or else not (for some Dep of Release (This.Edit).Dependencies => Dep.Is_Value and then Dep.Value.Crate = Crate) then Raise_Checked_Error ("Crate slated for removal is not among direct static dependencies:" & " " & Utils.TTY.Name (Crate) & "; please remove manually from manifest."); end if; Alire.Manifest.Remove (This.Edit.Crate_File, Crate); This.Reload_Manifest; if Unpin then This.Remove_Pin (Crate); end if; end Remove_Dependency; --------------------- -- Add_Version_Pin -- --------------------- procedure Add_Version_Pin (This : in out Root; Crate : Crate_Name; Version : Semver.Version) is begin -- If nothing in the solution depends on the pinned crate, add it as a -- direct dependency. if not This.Solution.Depends_On (Crate) then This.Add_Dependency (Dependencies.New_Dependency (Crate, Semver.Updatable (Version))); end if; -- Remove any previous pin for this crate This.Remove_Pin (Crate); -- And add the new pin Alire.Manifest.Append (Crate_File (This.Edit), Crate, User_Pins.New_Version (Version)); This.Reload_Manifest; This.Edit.Set (This.Solution.Resetting (Crate).Pinning (Crate, Version)); end Add_Version_Pin; -------------------------- -- Add_Pin_Preparations -- -------------------------- function Add_Pin_Preparations (This : in out Root; Crate : Alire.Optional.Crate_Name; Path : Any_Path) return Crate_Name is Pin_Root : constant Optional.Root := Optional.Detect_Root (Path); begin if Crate.Is_Empty and then not Pin_Root.Is_Valid then Raise_Checked_Error ("No crate name given and link target is not an Alire crate:" & ASCII.LF & " Please provide an explicit crate name."); end if; -- No need to check that Pin_Root.Name and Crate agree, as this will be -- done by the pin loader. declare -- At this point we can be sure of the crate name, so we shadow the -- original argument. Crate : constant Crate_Name := (if Add_Pin_Preparations.Crate.Has_Element then Add_Pin_Preparations.Crate.Element.Ptr.all else Pin_Root.Value.Name); begin -- If nothing in the solution depends on the crate (that is why we -- check the Solution and not the top-level dependencies) requested -- to be pinned, we assume a top-level dependency on the crate would -- be wanted, and add it too. If this is not wanted, the user can -- easily remove the dependency by hand afterwards (or add it, if the -- dependency is in the closure but not in the root crate). if not This.Solution.Depends_On (Crate) then This.Add_Dependency (Dependencies.New_Dependency (Crate, (if Pin_Root.Is_Valid then Pin_Root.Updatable_Dependency.Versions else Semver.Extended.Any))); end if; -- Remove any previous pin for this crate if Release (This.Edit).Pins.Contains (Crate) then This.Remove_Pin (Crate); end if; return Crate; end; end Add_Pin_Preparations; ------------------ -- Add_Path_Pin -- ------------------ procedure Add_Path_Pin (This : in out Root; Crate : Alire.Optional.Crate_Name; Path : Any_Path) is Abs_Path : constant Absolute_Path := Ada.Directories.Full_Name (Path); Added : constant Crate_Name := Add_Pin_Preparations (This, Crate, Abs_Path); New_Pin : constant User_Pins.Pin := User_Pins.New_Path (Abs_Path); begin -- And add the new pin Alire.Manifest.Append (Crate_File (This.Edit), Added, New_Pin); This.Reload_Manifest; This.Edit.Set (This.Solution.Linking (Added, New_Pin)); -- Since link pins can bring in more dependencies, we must also Update. -- Changes will be shown afterwards on the call to Confirm_And_Commit. This.Edit.Update (Allow_All_Crates, Silent => True, Interact => False); end Add_Path_Pin; -------------------- -- Add_Remote_Pin -- -------------------- procedure Add_Remote_Pin (This : in out Root; Crate : Alire.Optional.Crate_Name; Origin : URL; Ref : String := ""; Branch : String := "") is --------------------------- -- Convert_Ref_To_Commit -- --------------------------- procedure Convert_Ref_To_Commit is Ref : constant String := Add_Remote_Pin.Ref; Commit : constant String := VCSs.Git.Handler.Remote_Commit (Origin, Ref); begin if Commit /= "" then Put_Info ("Using commit " & TTY.Emph (Commit) & " for reference " & TTY.Emph (Ref)); This.Add_Remote_Pin (Crate, Origin, Commit, Branch); else Raise_Checked_Error ("Requested remote reference " & TTY.Emph (Ref) & " not found in repository " & TTY.URL (Origin)); end if; end Convert_Ref_To_Commit; Temp_Pin : Directories.Temp_File; -- We'll need to fetch the remote to a temporary location to verify -- crate matches. If all goes well, we will keep the download so there -- is no need to redownload on next run. begin -- We accept any reference that can be converted to a commit, as commit. -- This is a bit of a misnomer really in the command-line interface. if Ref /= "" and then not Origins.Is_Valid_Commit (Ref) then Convert_Ref_To_Commit; return; end if; -- Clone the remote so we can identify the crate and perform other -- validity checks. if not VCSs.Git.Handler.Clone (From => Origin & (if Ref /= "" then "#" & Ref else ""), Into => Temp_Pin.Filename, Branch => Branch, -- May be empty for default branch Depth => 1).Success then Raise_Checked_Error ("Checkout of repository at " & TTY.URL (Origin) & " failed, re-run with -vv -d for details"); end if; -- We can proceed as if it where a local pin now declare Crate : constant Crate_Name := Add_Pin_Preparations (This, Add_Remote_Pin.Crate, Temp_Pin.Filename); New_Pin : User_Pins.Pin := User_Pins.New_Remote (URL => Origin, Commit => Ref, Branch => Branch); Destination : constant Absolute_Path := New_Pin.Deploy_Path (Crate, This.Edit.Pins_Dir); package Adirs renames Ada.Directories; begin -- Put in place the checkout, as it is valid if we reached this point if not Adirs.Exists (This.Edit.Pins_Dir) then Adirs.Create_Path (This.Edit.Pins_Dir); end if; if Adirs.Exists (Destination) then -- Remove a previous pin deployment, which may be obsolete Directories.Delete_Tree (Destination); end if; Adirs.Rename (Old_Name => Temp_Pin.Filename, New_Name => Destination); -- Finally add the new pin to the manifest Alire.Manifest.Append (Crate_File (This.Edit), Crate, User_Pins.New_Remote (URL => Origin, Commit => Ref, Branch => Branch)); This.Reload_Manifest; -- And update lockfile. We need to call Deploy on the pin (although -- it is already deployed) so the pin becomes aware of its own path. New_Pin.Deploy (Crate, This.Edit.Pins_Dir, Online => False); This.Edit.Set (This.Solution.Linking (Crate, New_Pin)); -- Since link pins can bring in more dependencies, we must -- also Update. Changes will be shown afterwards on the call -- to Confirm_And_Commit. This.Edit.Update (Allow_All_Crates, Silent => True, Interact => False); end; end Add_Remote_Pin; ---------------- -- Remove_Pin -- ---------------- procedure Remove_Pin (This : in out Root; Crate : Crate_Name) is begin if Release (This.Edit).Pins.Contains (Crate) then Alire.Manifest.Remove_Pin (This.Edit.Crate_File, Crate); This.Edit.Set (This.Solution.User_Unpinning (Crate)); This.Reload_Manifest; end if; end Remove_Pin; --------------------- -- Reload_Manifest -- --------------------- procedure Reload_Manifest (This : in out Root) is begin This.Edit.Reload_Manifest; end Reload_Manifest; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Root) is procedure Finalize (File : String) is begin if File /= "" then declare Temp : Directories.Temp_File := Directories.With_Name (File) with Unreferenced; begin Trace.Debug ("Discarding temporary root file: " & File); end; end if; end Finalize; begin Finalize (+This.Edit.Manifest); Finalize (+This.Edit.Lockfile); exception when E : others => Log_Exception (E, Warning); end Finalize; --------- -- Set -- --------- procedure Set (This : in out Root; Solution : Solutions.Solution) is begin This.Edit.Set (Solution); end Set; end Alire.Roots.Editable; alire-1.2.1/src/alire/alire-roots-editable.ads000066400000000000000000000136611430264165500212070ustar00rootroot00000000000000private with Ada.Finalization; with Alire.Dependencies; with Alire.Errors; with Alire.Optional; with Alire.Utils.TTY; with Semantic_Versioning; package Alire.Roots.Editable is -- This type mimics manual edition of the manifest. All operations in here -- modify the manifest as if it were done by hand. type Root (<>) is tagged limited private; function New_Root (Original : in out Roots.Root) return Root; -- This creates a temporary root with separate manifest and lockfile, -- but shared cache with the Original. Changes will be forgotten unless -- Confirm_And_Commit is called. procedure Confirm_And_Commit (This : in out Root); -- Present differences in the solutions of Original and Edited and ask -- the user to accept, in which case Edited.Commit is called. Edited -- is expected to be a temporary copy of Original. Performs an -- Edited.Reload_Manifest, so any changes done to the Edited manifest -- about dependency/pin addition/removal are applied. -- A few proxies so useful predicates can be kept function Old (This : Root) return Roots.Root; -- The original root this editable copy was made from type Reference (Element : not null access Roots.Root) is limited null record with Implicit_Dereference => Element; function Current (This : in out Root) return Reference; -- Retrieve the temporary copy. This is read/write because the caching of -- solutions requires it, but it is intended for read-only use. function Name (This : Root) return Crate_Name; function Solution (This : in out Root) return Solutions.Solution; procedure Set (This : in out Root; Solution : Solutions.Solution); -- Bulk replace the solution in the temporary copy -- Edition procedures procedure Reload_Manifest (This : in out Root); -- If changes have been done to the manifest, either via the dependency/pin -- modification procedures, or somehow outside alire after This was -- created, we need to reload the manifest. The solution remains -- untouched (use Update to recompute a fresh solution). procedure Add_Dependency (This : in out Root; Dep : Dependencies.Dependency); -- Add a dependency, or raise Checked_Error is Dep is already among direct -- dependencies. procedure Remove_Dependency (This : in out Root; Crate : Crate_Name; Unpin : Boolean := True); -- Remove any dependency (and pin) on crate; will raise Checked_Error if -- Crate is not a dependency already. function Can_Be_Pinned (This : in out Root; Crate : Crate_Name) return Boolean is (not Release (This.Old).Pins.Contains (Crate) or else Force or else raise Checked_Error with Errors.Set (Utils.TTY.Name (Crate) & " is already pinned with pin " & Release (This.Old).Pins.Element (Crate).Image (User => False))); -- Says if a pin can be added: not already a pin, or Force. As an -- exception, the body is here as this function is intended to serve as -- a precondition, an hence serve as documentation. procedure Add_Version_Pin (This : in out Root; Crate : Crate_Name; Version : Semantic_Versioning.Version) with Pre => This.Can_Be_Pinned (Crate); -- Add a version pin; if the root doesn't depend on it previously, the -- dependency will be added too. procedure Add_Path_Pin (This : in out Root; Crate : Optional.Crate_Name; Path : Any_Path) with Pre => Crate.Is_Empty or else This.Can_Be_Pinned (Crate.Element.Ptr.all); -- Add a pin to a folder; if Crate.Is_Empty then Path must point to an -- Alire workspace from which it can be deduced. If Crate.Has_Element, the -- crates should match. If the root does not depend already on the crate, -- a dependency will be added. procedure Add_Remote_Pin (This : in out Root; Crate : Optional.Crate_Name; Origin : URL; Ref : String := ""; Branch : String := "") with Pre => (not (Ref /= "" and then Branch /= "") or else raise Checked_Error with Errors.Set ("Simultaneous Branch and Ref pins are incompatible")) and then (Crate.Is_Empty or else This.Can_Be_Pinned (Crate.Element)); -- Add a pin to a remote repo, with optional Ref xor Branch. If Ref is -- not a Commit, it will be converted to one using `git ls-remote`. If -- Crate.Is_Empty then Path must point to an Alire workspace for which it -- can be deduced. If Crate.Has_Element, the crates should match. If the -- root does not depend already on the crate, a dependency will be added. procedure Remove_Pin (This : in out Root; Crate : Crate_Name); -- Remove the pin for Crate if existing; otherwise do nothing private type Root is new Ada.Finalization.Limited_Controlled with record Orig : Roots.Root; Edit : aliased Roots.Root; end record; overriding procedure Finalize (This : in out Root); ------------- -- Current -- ------------- function Current (This : in out Root) return Reference is (Element => This.Edit'Unrestricted_Access); -- CE2021 is happy with 'Access but 9.3 complains about a dangling pointer. -- We are returning a short-lived pointer to a limited value so I don't see -- the problem. ---------- -- Name -- ---------- function Name (This : Root) return Crate_Name is (This.Edit.Name); --------- -- Old -- --------- function Old (This : Root) return Roots.Root is (This.Orig); -------------- -- Solution -- -------------- function Solution (This : in out Root) return Solutions.Solution is (This.Edit.Solution); end Alire.Roots.Editable; alire-1.2.1/src/alire/alire-roots-optional.adb000066400000000000000000000124241430264165500212360ustar00rootroot00000000000000with Ada.Directories; with Alire.Directories; with Alire.Errors; with Alire.Manifest; with Alire.Root; with GNAT.OS_Lib; with Semantic_Versioning; package body Alire.Roots.Optional is Root_Not_Detected : constant Root := (Alire.Outcome_Failure ("Could not detect a session folder" & " at current or parent locations", Report => False) with Data => (Status => Outside)); ---------------- -- Brokenness -- ---------------- function Brokenness (This : Root) return String is (+This.Data.Cause); ----------------- -- Detect_Root -- ----------------- function Detect_Root (Path : Any_Path) return Optional.Root is Crate_File : constant Any_Path := Crate_File_Name; begin if not GNAT.OS_Lib.Is_Directory (Path) then Trace.Debug ("No root can be detected because given path is not a directory: " & Path); return Root_Not_Detected; end if; declare Change_Dir : Directories.Guard (Directories.Enter (Path)) with Unreferenced; -- We need to enter the folder with the possible crate, so stored -- relative paths (e.g. in pins) make sense when loaded. begin if Path /= "" then if GNAT.OS_Lib.Is_Regular_File (Crate_File) then begin return This : constant Root := Outcome_Success (Roots.New_Root (R => Releases.From_Manifest (Crate_File, Manifest.Local, Strict => True), Path => Ada.Directories.Full_Name (Path), Env => Alire.Root.Platform_Properties)) do -- Crate loaded properly, we can return a valid root here Trace.Debug ("Valid root found at " & Path); end return; exception when E : others => Trace.Debug ("Unloadable root found at " & Path); Log_Exception (E); return Outcome_Failure (Errors.Get (E), Broken, Report => False); end; else Trace.Debug ("No root found at " & Path); return Root_Not_Detected; end if; else Trace.Debug ("No root can be detected because given path is empty"); return Root_Not_Detected; -- This happens when detection of session folders in parent -- folders has been already attempted by the caller, so it -- ends calling here with an empty path. end if; end; end Detect_Root; ----------------- -- Search_Root -- ----------------- function Search_Root (From : Any_Path) return Optional.Root is (Detect_Root (Directories.Detect_Root_Path (Ada.Directories.Full_Name (From)))); --------------- -- Is_Broken -- --------------- function Is_Broken (This : Root) return Boolean is (This.Status = Broken); -------------- -- Is_Valid -- -------------- function Is_Valid (This : Root) return Boolean is (This.Status = Valid); ------------- -- Outside -- ------------- function Outside (This : Root) return Boolean is (This.Status = Outside); ------------ -- Status -- ------------ function Status (This : Root) return States is (This.Data.Status); ----------- -- Value -- ----------- function Value (This : aliased Root) return Reference is begin This.Assert; -- The following Unrestricted_Access cannot fail as we just asserted -- the value is stored. return Reference'(Ptr => This.Data.Value'Unrestricted_Access); end Value; --------------------- -- Outcome_Failure -- --------------------- function Outcome_Failure (Message : String; Status : States; Report : Boolean) return Root is (if Status = Outside then (Alire.Outcome_Failure (Message, Report) with Data => (Status => Outside)) elsif Status = Broken then (Alire.Outcome_Failure (Message, Report) with Data => (Status => Broken, Cause => +Message)) else raise Program_Error with "precondition not fulfilled"); --------------------- -- Outcome_Success -- --------------------- function Outcome_Success (This : Roots.Root) return Optional.Root is (Alire.Outcome_Success with Data => (Status => Valid, Value => This)); -------------------------- -- Updatable_Dependency -- -------------------------- function Updatable_Dependency (This : Root) return Dependencies.Dependency is (Dependencies.New_Dependency (This.Value.Release.Element.Name, Semantic_Versioning.Updatable (This.Value.Release.Element.Version))); end Alire.Roots.Optional; alire-1.2.1/src/alire/alire-roots-optional.ads000066400000000000000000000055331430264165500212620ustar00rootroot00000000000000with Alire.Dependencies; package Alire.Roots.Optional is type States is (Outside, -- There is no alire metadata at all Broken, -- There is metadata that cannot be loaded, root is unusable Valid -- There is loadable metadata and the root is usable ); -- Hit a GNAT bug trying to use Outcomes.Indefinite... using custom impl type Root is new Outcome with private; type Reference (Ptr : not null access Roots.Root) is limited null record with Implicit_Dereference => Ptr; -- NOTE: Detecting and loading roots is expensive, so it should be done as -- few times as possible. Once a valid root is obtained, just reuse it. function Detect_Root (Path : Any_Path) return Optional.Root; -- Try to detect a root at the given Path function Search_Root (From : Any_Path) return Optional.Root; -- Try to detect a root at From or any ancestor folder function Status (This : Root) return States; function Is_Broken (This : Root) return Boolean; function Is_Valid (This : Root) return Boolean; function Outside (This : Root) return Boolean; -- True when there is no root at all, broken or valid function Value (This : aliased Root) return Reference with Pre => This.Is_Valid; function Brokenness (This : Root) return String with Pre => This.Is_Broken; function Outcome_Failure (Message : String; Status : States; Report : Boolean) return Root with Pre => Status in Outside | Broken; function Outcome_Success (This : Roots.Root) return Optional.Root; -- UTILITIES function Updatable_Dependency (This : Root) return Dependencies.Dependency with Pre => This.Is_Valid; -- If This.Is_Valid, get the corresponding updatable -- dependency (e.g., ^1.2, ~0.1.2). private type Root_Data (Status : States := Outside) is record case Status is when Valid => Value : aliased Roots.Root; when Broken => Cause : UString; when others => null; end case; end record; type Root is new Outcome with record Data : Root_Data; end record; overriding function Outcome_Failure (Unused_Message : String; Unused_Report : Boolean := True) return Root is (raise Program_Error with "Status must be provided"); overriding function Outcome_Success return Root is (raise Program_Error with "A successful non-trivial outcome requires a result"); overriding function Outcome_From_Exception (Unused_Ex : Ada.Exceptions.Exception_Occurrence; Unused_Msg : String := "") return Root is (raise Program_Error with "Status must be provided"); end Alire.Roots.Optional; alire-1.2.1/src/alire/alire-roots.adb000066400000000000000000001273271430264165500174240ustar00rootroot00000000000000with Alire.Conditional; with Alire.Crate_Configuration; with Alire.Dependencies.Containers; with Alire.Directories; with Alire.Environment; with Alire.Errors; with Alire.Manifest; with Alire.Origins; with Alire.OS_Lib; with Alire.Properties.Actions.Executor; with Alire.Roots.Optional; with Alire.Shared; with Alire.Solutions.Diffs; with Alire.Spawn; with Alire.User_Pins.Maps; with Alire.Utils.TTY; with Alire.Utils.User_Input; with Alire.Utils.Switches; with GNAT.OS_Lib; with Semantic_Versioning.Extended; with CLIC.User_Input; package body Alire.Roots is package Semver renames Semantic_Versioning; use type UString; ----------- -- Build -- ----------- function Build (This : in out Root; Cmd_Args : AAA.Strings.Vector; Export_Build_Env : Boolean) return Boolean is Build_Failed : exception; -------------------------- -- Build_Single_Release -- -------------------------- procedure Build_Single_Release (This : in out Root; Solution : Solutions.Solution; State : Dependencies.States.State) is pragma Unreferenced (Solution); -- Relocate to the release folder CD : Directories.Guard (if State.Has_Release and then State.Release.Origin.Is_Regular then Directories.Enter (This.Release_Base (State.Crate)) else Directories.Stay) with Unreferenced; --------------------------- -- Run_Pre_Build_Actions -- --------------------------- procedure Run_Pre_Build_Actions (Release : Releases.Release) is begin Alire.Properties.Actions.Executor.Execute_Actions (Release, Env => This.Environment, Moment => Alire.Properties.Actions.Pre_Build); exception when E : others => Trace.Warning ("A pre-build action failed, " & "re-run with -vv -d for details"); Log_Exception (E); raise Build_Failed; end Run_Pre_Build_Actions; ---------------------------- -- Run_Post_Build_Actions -- ---------------------------- procedure Run_Post_Build_Actions (Release : Releases.Release) is begin Alire.Properties.Actions.Executor.Execute_Actions (Release, Env => This.Environment, Moment => Alire.Properties.Actions.Post_Build); exception when E : others => Trace.Warning ("A post-build action failed, " & "re-run with -vv -d for details"); Log_Exception (E); raise Build_Failed; end Run_Post_Build_Actions; ------------------- -- Call_Gprbuild -- ------------------- procedure Call_Gprbuild (Release : Releases.Release) is use Directories.Operators; Count : constant Natural := Natural (Release.Project_Files (This.Environment, With_Path => True).Length); Current : Positive := 1; Is_Root : constant Boolean := Release.Name = This.Release.Constant_Reference.Name; begin if not Is_Root and then not Release.Auto_GPR_With then Put_Info (TTY.Bold ("Not") & " pre-building " & Utils.TTY.Name (Release.Name) & " (auto with disabled)", Trace.Detail); elsif not Is_Root and then Release.Executables (This.Environment).Is_Empty then Put_Info (TTY.Bold ("Not") & " pre-building " & Utils.TTY.Name (Release.Name) & " (no executables declared)", Trace.Detail); else -- Build all the project files for Gpr_File of Release.Project_Files (This.Environment, With_Path => True) loop Put_Info ("Building " & Utils.TTY.Name (Release.Name) & "/" & TTY.URL (Gpr_File) & (if Count > 1 then " (" & AAA.Strings.Trim (Current'Image) & "/" & AAA.Strings.Trim (Count'Image) & ")" else "") & "..."); Spawn.Gprbuild (This.Release_Base (Release.Name) / Gpr_File, Extra_Args => Cmd_Args); Current := Current + 1; end loop; end if; exception when E : Alire.Checked_Error => Trace.Error (Errors.Get (E, Clear => False)); Log_Exception (E); raise Build_Failed; when E : others => Log_Exception (E); raise Build_Failed; end Call_Gprbuild; begin if not State.Has_Release then Put_Info (State.As_Dependency.TTY_Image & ": no build needed."); return; end if; declare Release : constant Releases.Release := State.Release; begin Run_Pre_Build_Actions (Release); Call_Gprbuild (Release); Run_Post_Build_Actions (Release); end; end Build_Single_Release; begin -- Check if crate configuration should be re-generated declare use Alire.Utils.Switches; use Alire.Crate_Configuration; begin if Last_Build_Profile /= Root_Build_Profile then This.Generate_Configuration; end if; end; if Export_Build_Env then This.Export_Build_Environment; end if; This.Traverse (Build_Single_Release'Access); return True; exception when Build_Failed => return False; end Build; ------------------- -- Build_Context -- ------------------- function Build_Context (This : in out Root) return Alire.Environment.Context is begin return Context : Alire.Environment.Context do Context.Load (This); end return; end Build_Context; ------------------ -- Direct_Withs -- ------------------ function Direct_Withs (This : in out Root; Dependent : Releases.Release) return AAA.Strings.Set is Sol : Solutions.Solution renames This.Solution; begin return Files : AAA.Strings.Set do -- Traverse direct dependencies of the given release for Dep of Dependent.Flat_Dependencies (This.Environment) loop -- For dependencies that appear in the solution as releases, get -- their project files in the current environment. if Sol.Releases.Contains (Dep.Crate) and then Sol.Releases.Element (Dep.Crate).Auto_GPR_With then for File of Sol.Releases.Element (Dep.Crate).Project_Files (This.Environment, With_Path => False) loop Files.Include (File); end loop; end if; end loop; end return; end Direct_Withs; ---------------------------- -- Generate_Configuration -- ---------------------------- procedure Generate_Configuration (This : in out Root) is Conf : Alire.Crate_Configuration.Global_Config; begin Conf.Load (This); Conf.Generate_Config_Files (This); end Generate_Configuration; ------------------ -- Check_Stored -- ------------------ procedure Check_Stored (This : Root) is Info : constant String := This.Storage_Error; begin if Info /= "" then Raise_Checked_Error (Info); end if; end Check_Stored; ------------------------ -- Create_For_Release -- ------------------------ function Create_For_Release (This : Releases.Release; Parent_Folder : Any_Path; Env : Alire.Properties.Vector; Perform_Actions : Boolean := True) return Root is use Directories; Unused_Was_There : Boolean; begin This.Deploy (Env => Env, Parent_Folder => Parent_Folder, Was_There => Unused_Was_There, Perform_Actions => Perform_Actions, Create_Manifest => True); -- And generate its working files, if they do not exist declare Working_Dir : Guard (Enter (This.Base_Folder)) with Unreferenced; Root : Alire.Roots.Root := Alire.Roots.New_Root (This, Ada.Directories.Current_Directory, Env); begin Ada.Directories.Create_Path (Root.Working_Folder); -- Create a preliminary lockfile (since dependencies are still -- unretrieved). Once they are checked out, the lockfile will -- be replaced with the complete solution. Root.Set (Solution => (if This.Dependencies (Env).Is_Empty then Alire.Solutions.Empty_Valid_Solution else Alire.Solutions.Empty_Invalid_Solution)); return Root; end; end Create_For_Release; ------------------------- -- Deploy_Dependencies -- ------------------------- procedure Deploy_Dependencies (This : in out Roots.Root) is -------------------- -- Deploy_Release -- -------------------- procedure Deploy_Release (This : in out Root; Sol : Solutions.Solution; Dep : Dependencies.States.State) is pragma Unreferenced (Sol); Was_There : Boolean; -------------------- -- Run_Post_Fetch -- -------------------- procedure Run_Post_Fetch (Release : Releases.Release) is CD : Directories.Guard (Directories.Enter (This.Release_Base (Release.Name))) with Unreferenced; begin Alire.Properties.Actions.Executor.Execute_Actions (Release, Env => This.Environment, Moment => Alire.Properties.Actions.Post_Fetch); exception when E : others => Log_Exception (E); Raise_Checked_Error ("A post-fetch action failed, " & "re-run with -vv -d for details"); end Run_Post_Fetch; begin if Dep.Is_Linked then Trace.Debug ("deploy: skip linked release"); -- To allow local workflows to work as in a real fetching, linked -- releases get their post-fetch run whenever there is a change to -- dependencies. This will run them more than once, but is better -- than never running them and breaking something. if Dep.Has_Release then Run_Post_Fetch (Dep.Release); end if; return; elsif Release (This).Provides (Dep.Crate) or else (Dep.Has_Release and then Dep.Release.Name = Release (This).Name) then Trace.Debug ("deploy: skip root"); -- The root release is never really "fetched" (unless for an alr -- get, but e.g. not when cloned). So, we run their post-fetch -- when dependencies are updated. Run_Post_Fetch (Dep.Release); return; elsif not Dep.Has_Release then Trace.Debug ("deploy: skip dependency without release"); return; end if; -- At this point, the state contains a release declare Rel : constant Releases.Release := Dep.Release; begin if Rel.Origin.Kind in Origins.Binary_Archive then -- Binary releases are always installed as shared releases Shared.Share (Rel); elsif Dep.Is_Shared and then not Rel.Origin.Is_Regular then -- Externals shouldn't leave a trace in the binary cache Trace.Debug ("deploy: skip shared external"); else -- Remaining cases expect to receive a Deploy call, even -- externals in the working directory Rel.Deploy (Env => This.Environment, Parent_Folder => This.Dependencies_Dir (Rel.Name), Perform_Actions => False, Was_There => Was_There, Create_Manifest => Dep.Is_Shared, Include_Origin => Dep.Is_Shared); -- Always run the post-fetch on update of dependencies, in -- case there is some interaction with some other updated -- dependency, even for crates that didn't change. Run_Post_Fetch (Rel); end if; end; end Deploy_Release; begin -- Prepare environment for any post-fetch actions. This must be done -- after the lockfile on disk is written, since the root will read -- dependencies from there. This.Export_Build_Environment; -- Visit dependencies in a safe order to be fetched, and their actions -- ran This.Traverse (Doing => Deploy_Release'Access); -- Show hints for missing externals to the user after all the noise of -- dependency post-fetch compilations. This.Solution.Print_Hints (This.Environment); -- Update/Create configuration files This.Generate_Configuration; -- Check that the solution does not contain suspicious dependencies, -- taking advantage that this procedure is called whenever a change -- to dependencies is happening. pragma Assert (Release (This).Check_Caret_Warning or else True); -- We don't care about the return value here end Deploy_Dependencies; ----------------------------- -- Sync_Pins_From_Manifest -- ----------------------------- procedure Sync_Pins_From_Manifest (This : in out Root; Exhaustive : Boolean; Allowed : Containers.Crate_Name_Sets.Set := Containers.Crate_Name_Sets.Empty_Set) is Top_Root : Root renames This; Pins_Dir : constant Any_Path := This.Pins_Dir; Linked : Containers.Crate_Name_Sets.Set; -- And we use this to avoid re-processing the same link target -------------- -- Add_Pins -- -------------- procedure Add_Pins (This : in out Roots.Root; Upstream : Containers.Crate_Name_Sets.Set) -- Upstream contains crates that are in the linking path to this root; -- hence attempting to link to an upstream means a cycle in the graph. is Pins : Solutions.Solution renames Top_Root.Pins; --------------------- -- Add_Version_Pin -- --------------------- procedure Add_Version_Pin (Crate : Crate_Name; Pin : User_Pins.Pin) is use type Semver.Version; begin if Pins.Depends_On (Crate) and then Pins.State (Crate).Is_Pinned and then Pins.State (Crate).Pin_Version /= Pin.Version then Put_Warning ("Incompatible version pins requested for crate " & Utils.TTY.Name (Crate) & "; fix versions or override with a link pin."); end if; if not Pins.Depends_On (Crate) then Pins := Pins.Depending_On (Release (Top_Root) .Dependency_On (Crate) .Or_Else (Dependencies.New_Dependency (Crate, Pin.Version))); end if; Pins := Pins.Pinning (Crate, Pin.Version); end Add_Version_Pin; ------------------ -- Add_Link_Pin -- ------------------ procedure Add_Link_Pin (Crate : Crate_Name; Pin : in out User_Pins.Pin) is use type User_Pins.Pin; begin -- If the target of this link is an upstream crate, we are -- attempting to create a cycle. if Upstream.Contains (Crate) then Raise_Checked_Error ("Pin circularity detected when adding pin " & Utils.TTY.Name (This.Name) & " --> " & Utils.TTY.Name (Crate) & ASCII.LF & "Last manifest in the cycle is " & TTY.URL (This.Crate_File)); end if; -- Just in case this is a remote pin, deploy it. Deploy is -- conservative (unless Online), but it will detect local -- inexpensive changes like a missing checkout, changed commit -- or branch. if Allowed.Is_Empty or else Allowed.Contains (Crate) then Pin.Deploy (Crate => Crate, Under => Pins_Dir, Online => Exhaustive); end if; -- At this point, we can detect that a link is conflicting with -- another one. if Pins.Depends_On (Crate) and then Pins.State (Crate).Is_Linked and then Pins.State (Crate).Link /= Pin then Raise_Checked_Error ("Conflicting pin links for crate " & Utils.TTY.Name (Crate) & ": Crate " & Utils.TTY.Name (Release (This).Name) & " wants to link " & TTY.URL (Pin.Image (User => True)) & ", but a previous link exists to " & TTY.URL (Pins.State (Crate).Link.Image (User => True))); end if; -- If the link target has already been seen, we do not need to -- reprocess it if Linked.Contains (Crate) then Trace.Debug ("Skipping adding of already added link target: " & Utils.TTY.Name (Crate)); return; else Linked.Insert (Crate); end if; -- We have a new target root to load declare use Containers.Crate_Name_Sets; use Semver.Extended; Target : constant Optional.Root := Optional.Detect_Root (Pin.Path); begin -- Verify matching crate at the target location if Target.Is_Valid then Trace.Debug ("Crate found at pin location " & Pin.Relative_Path); if Target.Value.Name /= Crate then Raise_Checked_Error ("Mismatched crates for pin linking to " & TTY.URL (Pin.Path) & ": expected " & Utils.TTY.Name (Crate) & " but found " & Utils.TTY.Name (Target.Value.Name)); end if; else Trace.Debug ("No crate found at pin location " & Pin.Relative_Path); end if; Pins := Pins.Depending_On (Release (Top_Root).Dependency_On (Crate) .Or_Else (if Target.Is_Valid then Target.Updatable_Dependency else Dependencies.New_Dependency (Crate, Any))) .Linking (Crate, Pin); -- Add possible pins at the link target if Target.Is_Valid then Add_Pins (Target.Value, Upstream => Union (Upstream, To_Set (This.Name))); end if; end; end Add_Link_Pin; New_Pins : constant User_Pins.Maps.Map := Release (This).Pins; begin -- Iterate over this root pins. Any pin that links to another root -- will cause recursive pin loading. Remote pins are fetched in the -- process, so they're available for use immediately. All link pins -- have a proper path once this process completes. for I in New_Pins.Iterate loop declare use all type User_Pins.Kinds; use User_Pins.Maps.Pin_Maps; Crate : constant Crate_Name := Key (I); Pin : User_Pins.Pin := Element (I); begin -- Avoid obvious self-pinning Trace.Debug ("Crate " & Utils.TTY.Name (This.Name) & " adds pin for crate " & Utils.TTY.Name (Crate)); case Pin.Kind is when To_Version => Add_Version_Pin (Crate, Pin); when To_Path | To_Git => Add_Link_Pin (Crate, Pin); end case; Trace.Detail ("Crate " & Utils.TTY.Name (This.Name) & " adds pin " & Pins.State (Crate).TTY_Image); end; end loop; end Add_Pins; begin -- Remove any existing pins in the stored solution, to avoid conflicts -- between old and new definitions of the same pin, and to discard -- removed pins. This.Pins := Solutions.Empty_Valid_Solution; -- Recursively add all pins from this workspace and other linked ones Add_Pins (This, Upstream => Containers.Crate_Name_Sets.To_Set (This.Name)); exception when others => -- In the event that the manifest contains bad pins, we ensure the -- lockfile is outdated so the manifest is not ignored on next run. if Ada.Directories.Exists (This.Lock_File) then Trace.Debug ("Removing lockfile because of bad pins in manifest"); Ada.Directories.Delete_File (This.Lock_File); end if; raise; end Sync_Pins_From_Manifest; --------------- -- Is_Stored -- --------------- function Storage_Error (This : Root) return String is use Ada.Directories; begin -- Checks on the alire folder if not Exists (This.Working_Folder) then Trace.Debug ("No alire folder found under " & (+This.Path)); -- This ceased to be an error when the manifest was moved up elsif Kind (This.Working_Folder) /= Directory then return "Expected alire folder but found a: " & Kind (This.Working_Folder)'Img; end if; -- Checks on the manifest file if not Exists (This.Crate_File) then return "Manifest file not found in alire folder"; elsif Kind (This.Crate_File) /= Ordinary_File then return "Expected ordinary manifest file but found a: " & Kind (This.Crate_File)'Img; elsif not Alire.Manifest.Is_Valid (This.Crate_File, Alire.Manifest.Local) then return "Manifest is not loadable: " & This.Crate_File; end if; return ""; end Storage_Error; --------------- -- Load_Root -- --------------- function Load_Root (Path : Any_Path) return Root is (Roots.Optional.Detect_Root (Path).Value); ------------------------------ -- Export_Build_Environment -- ------------------------------ procedure Export_Build_Environment (This : in out Root) is Context : Alire.Environment.Context; begin Context.Load (This); Context.Export; end Export_Build_Environment; ------------------- -- Project_Paths -- ------------------- function Project_Paths (This : in out Root) return AAA.Strings.Set is use Alire.OS_Lib; Paths : AAA.Strings.Set; begin for Rel of This.Solution.Releases.Including (Release (This)) loop -- Add project paths from each release for Path of Rel.Project_Paths (This.Environment) loop Paths.Include (This.Release_Base (Rel.Name) / Path); end loop; end loop; -- Add paths for raw pinned folders for Linked of This.Solution.Links loop if not This.Solution.State (Linked.Crate).Has_Release then Paths.Include (This.Solution.State (Linked.Crate).Link.Path); end if; end loop; -- To match the output of root crate paths and Ada.Directories full path -- normalization, a path separator in the last position is removed. return Result : AAA.Strings.Set do for Path of Paths loop if Path'Length /= 0 and then -- The paths provided by crates manifests are expected to use -- UNIX directory separator. So we need to handle both UNIX and -- OS separators. Path (Path'Last) in '/' | GNAT.OS_Lib.Directory_Separator then Result.Include (Path (Path'First .. Path'Last - 1)); else Result.Include (Path); end if; end loop; end return; end Project_Paths; --------- -- Set -- --------- procedure Set (This : in out Root; Solution : Solutions.Solution) is begin This.Cached_Solution.Set (Solution, This.Lock_File); end Set; -------------- -- Solution -- -------------- function Solution (This : in out Root) return Solutions.Solution is (This.Cached_Solution.Element (This.Lock_File)); ----------------- -- Environment -- ----------------- function Environment (This : Root) return Properties.Vector is (This.Environment); -------------- -- New_Root -- -------------- function New_Root (Name : Crate_Name; Path : Absolute_Path; Env : Properties.Vector) return Root is (New_Root (Releases.New_Working_Release (Name), Path, Env)); -------------- -- New_Root -- -------------- function New_Root (R : Releases.Release; Path : Absolute_Path; Env : Properties.Vector) return Root is (Ada.Finalization.Controlled with Environment => Env, Path => +Path, Release => Releases.Containers.To_Release_H (R), Cached_Solution => <>, Pins => <>, Lockfile => <>, Manifest => <>); ---------- -- Name -- ---------- function Name (This : Root) return Crate_Name is (This.Release.Constant_Reference.Name); ---------- -- Path -- ---------- function Path (This : Root) return Absolute_Path is (+This.Path); ------------- -- Release -- ------------- function Release (This : Root) return Releases.Release is (This.Release.Element); ------------- -- Release -- ------------- function Release (This : in out Root; Crate : Crate_Name) return Releases.Release is (if This.Release.Element.Name = Crate then This.Release.Element else This.Solution.State (Crate).Release); use OS_Lib; ---------------------- -- Dependencies_Dir -- ---------------------- function Dependencies_Dir (This : in out Root; Crate : Crate_Name) return Any_Path is begin if This.Solution.State (Crate).Is_Solved then if This.Solution.State (Crate).Is_Shared then return Shared.Install_Path; else return This.Cache_Dir / Paths.Deps_Folder_Inside_Cache_Folder; end if; else raise Program_Error with "deploy base only applies to solved releases"; end if; end Dependencies_Dir; ------------------ -- Release_Base -- ------------------ function Release_Base (This : in out Root; Crate : Crate_Name) return Any_Path is begin if This.Release.Element.Name = Crate then return +This.Path; elsif This.Solution.State (Crate).Is_Solved then declare Rel : constant Releases.Release := Release (This, Crate); begin return This.Dependencies_Dir (Crate) / Rel.Base_Folder; end; elsif This.Solution.State (Crate).Is_Linked then return This.Solution.State (Crate).Link.Path; else raise Program_Error with "release must be either solved or linked"; end if; end Release_Base; ---------------------- -- Migrate_Lockfile -- ---------------------- -- This function is intended to migrate lockfiles in the old root location -- to inside the alire folder. It could be conceivably removed down the -- line during a major release. function Migrate_Lockfile (This : Root; Path : Any_Path) return Any_Path is package Adirs renames Ada.Directories; Old_Path : constant Any_Path := Adirs.Containing_Directory (Adirs.Containing_Directory (Path)) / Lockfiles.Simple_Name; begin if Adirs.Exists (Old_Path) then Directories.Backup_If_Existing (Old_Path, Base_Dir => This.Working_Folder); if Adirs.Exists (Path) then Put_Info ("Removing old lockfile at " & TTY.URL (Old_Path)); Adirs.Delete_File (Old_Path); else Put_Info ("Migrating lockfile from " & TTY.URL (Old_Path) & " to " & TTY.URL (Path)); Adirs.Rename (Old_Path, Path); end if; end if; return Path; end Migrate_Lockfile; --------------- -- Lock_File -- --------------- function Lock_File (This : Root) return Absolute_Path is (if This.Lockfile /= "" then +This.Lockfile else Migrate_Lockfile (This, Lockfiles.File_Name (+This.Path))); ---------------- -- Crate_File -- ---------------- function Crate_File (This : Root) return Absolute_Path is (if This.Manifest /= "" then +This.Manifest else Path (This) / Crate_File_Name); --------------- -- Cache_Dir -- --------------- function Cache_Dir (This : Root) return Absolute_Path is (This.Working_Folder / Paths.Cache_Folder_Inside_Working_Folder); -------------- -- Pins_Dir -- -------------- function Pins_Dir (This : Root) return Absolute_Path is (This.Cache_Dir / "pins"); -------------------- -- Working_Folder -- -------------------- function Working_Folder (This : Root) return Absolute_Path is ((+This.Path) / "alire"); -------------------- -- Write_Manifest -- -------------------- procedure Write_Manifest (This : Root) is Release : constant Releases.Release := Roots.Release (This); begin Trace.Debug ("Generating manifest file for " & Release.Milestone.TTY_Image & " with" & Release.Dependencies.Leaf_Count'Img & " dependencies"); Directories.Backup_If_Existing (File => This.Crate_File, Base_Dir => This.Working_Folder); Release.Whenever (This.Environment) .To_File (Filename => This.Crate_File, Format => Manifest.Local); end Write_Manifest; -------------------- -- Write_Solution -- -------------------- procedure Write_Solution (Solution : Solutions.Solution; Lockfile : String) is begin Lockfiles.Write (Contents => (Solution => Solution), Filename => Lockfile); end Write_Solution; ------------------ -- Has_Lockfile -- ------------------ function Has_Lockfile (This : Root; Check_Valid : Boolean := False) return Boolean is (This.Cached_Solution.Has_Element -- The following validity check is very expensive. This shortcut -- speeds up things greatly and both should be in sync if things -- are as they should. or else (if Check_Valid then Lockfiles.Validity (This.Lock_File) in Lockfiles.Valid else Ada.Directories.Exists (This.Lock_File))); -------------------------- -- Is_Lockfile_Outdated -- -------------------------- function Is_Lockfile_Outdated (This : Root) return Boolean is use GNAT.OS_Lib; begin return File_Time_Stamp (This.Crate_File) > File_Time_Stamp (This.Lock_File); end Is_Lockfile_Outdated; ------------------------ -- Sync_From_Manifest -- ------------------------ procedure Sync_From_Manifest (This : in out Root; Silent : Boolean; Interact : Boolean; Force : Boolean := False) is begin if Force or else This.Is_Lockfile_Outdated then -- TODO: we may want to recursively check manifest timestamps of -- linked crates to detect changes in these manifests and re-resolve. -- Otherwise a manual `alr update` is needed to detect these changes. -- This would imply to store the timestamps in our lockfile for -- linked crates with a manifest. Put_Info ("Synchronizing workspace..."); This.Sync_Pins_From_Manifest (Exhaustive => False); -- Normally we do not want to re-fetch remote pins, so we request -- a non-exhaustive sync of pins, that will anyway detect evident -- changes (new/removed pins, changed explicit commits). This.Sync_Dependencies (Silent => Silent, Interact => Interact); -- Don't ask for confirmation as this is an automatic update in -- reaction to a manually edited manifest, and we need the lockfile -- to match the manifest. As any change in dependencies will be -- printed, the user will have to re-edit the manifest if not -- satisfied with the result of the previous edition. This.Sync_Manifest_And_Lockfile_Timestamps; -- It may happen that the solution didn't change (edition of -- manifest is not related to dependencies), in which case we need -- to manually mark the lockfile as older. Trace.Info (""); -- Separate changes from what caused the sync end if; -- The following checks may only succeed if the user has deleted -- something externally, or after running `alr clean --cache`. -- Detect remote pins that are not at the expected location if (for some Dep of This.Solution.Links => This.Solution.State (Dep.Crate).Link.Is_Broken) then This.Sync_Pins_From_Manifest (Exhaustive => False); end if; -- Detect dependencies that are not at the expected location if (for some Rel of This.Solution.Releases => This.Solution.State (Rel.Name).Is_Solved and then not GNAT.OS_Lib.Is_Directory (This.Release_Base (Rel.Name))) then Trace.Detail ("Detected missing dependency sources, updating workspace..."); -- Some dependency is missing; redeploy. Should we clean first ??? This.Deploy_Dependencies; end if; end Sync_From_Manifest; ------------------------------------------- -- Sync_Manifest_And_Lockfile_Timestamps -- ------------------------------------------- procedure Sync_Manifest_And_Lockfile_Timestamps (This : Root) is package OS renames GNAT.OS_Lib; begin if This.Is_Lockfile_Outdated then Trace.Debug ("Touching lock file time after manifest manual edition"); OS.Set_File_Last_Modify_Time_Stamp (This.Lock_File, OS.File_Time_Stamp (This.Crate_File)); end if; end Sync_Manifest_And_Lockfile_Timestamps; ------------ -- Update -- ------------ procedure Update (This : in out Root; Allowed : Containers.Crate_Name_Sets.Set; Silent : Boolean; Interact : Boolean) is begin This.Sync_Pins_From_Manifest (Exhaustive => True, Allowed => Allowed); -- Just in case, retry all pins. This is necessary so pins without an -- explicit commit are updated to HEAD. -- And look for updates in dependencies This.Sync_Dependencies (Allowed => Allowed, Silent => Silent, Interact => Interact and not CLIC.User_Input.Not_Interactive); end Update; -------------------- -- Compute_Update -- -------------------- function Compute_Update (This : in out Root; Allowed : Containers.Crate_Name_Sets.Set := Containers.Crate_Name_Sets.Empty_Set; Options : Solver.Query_Options := Solver.Default_Options) return Solutions.Solution is use type Conditional.Dependencies; Deps : Conditional.Dependencies := Release (This).Dependencies (This.Environment); begin -- Identify crates that must be held back if not Allowed.Is_Empty then for Release of This.Solution.Releases loop if not Allowed.Contains (Release.Name) then Trace.Debug ("Forcing release in solution: " & Release.Version.Image); Deps := Release.To_Dependency and Deps; end if; end loop; end if; -- Ensure we have complete pin information This.Sync_Pins_From_Manifest (Exhaustive => False); -- And solve return Solver.Resolve (Deps => Deps, Props => This.Environment, Pins => This.Pins, Options => Options); end Compute_Update; ----------------------- -- Sync_Dependencies -- ----------------------- procedure Sync_Dependencies (This : in out Root; Silent : Boolean; -- Do not output anything Interact : Boolean; -- Request confirmation from the user Options : Solver.Query_Options := Solver.Default_Options; Allowed : Containers.Crate_Name_Sets.Set := Alire.Containers.Crate_Name_Sets.Empty_Set) is Old : constant Solutions.Solution := (if This.Has_Lockfile then This.Solution else Solutions.Empty_Valid_Solution); begin -- Ensure requested crates are in solution first. for Crate of Allowed loop if not Old.Depends_On (Crate) then Raise_Checked_Error ("Requested crate is not a dependency: " & Utils.TTY.Name (Crate)); end if; if Old.Pins.Contains (Crate) then -- The solver will never update a pinned crate, so we may allow -- this to be attempted but it will have no effect. Recoverable_Error ("Requested crate is pinned and cannot be updated: " & Alire.Utils.TTY.Name (Crate)); end if; end loop; declare Needed : constant Solutions.Solution := This.Compute_Update (Allowed, Options); Diff : constant Solutions.Diffs.Diff := Old.Changes (Needed); begin -- Early exit when there are no changes if not Alire.Force and not Diff.Contains_Changes then if not Needed.Is_Complete then Trace.Warning ("There are missing dependencies" & " (use `alr with --solve` for details)."); end if; This.Sync_Manifest_And_Lockfile_Timestamps; -- In case manual changes in manifest do not modify the -- solution. if not Silent then Trace.Info ("Nothing to update."); end if; else -- Show changes and optionally ask user to apply them if not Interact then declare Level : constant Trace.Levels := (if Silent then Debug else Info); begin Trace.Log ("Dependencies automatically updated as follows:", Level); Diff.Print (Level => Level); end; elsif not Utils.User_Input.Confirm_Solution_Changes (Diff) then Trace.Detail ("Update abandoned."); return; end if; end if; -- Apply the update. We do this even when no changes were -- detected, as pin evaluation may have temporarily stored -- unsolved dependencies which have been re-solved now. This.Set (Solution => Needed); This.Deploy_Dependencies; -- Update/Create configuration files This.Generate_Configuration; Trace.Detail ("Update completed"); end; end Sync_Dependencies; -------------------- -- Temporary_Copy -- -------------------- function Temporary_Copy (This : in out Root) return Root'Class is Copy : Root := This; Temp_Manifest : Directories.Temp_File; Temp_Lockfile : Directories.Temp_File; begin Temp_Manifest.Keep; Temp_Lockfile.Keep; Copy.Manifest := +Temp_Manifest.Filename; Ada.Directories.Copy_File (Source_Name => This.Crate_File, Target_Name => +Copy.Manifest); Copy.Lockfile := +Temp_Lockfile.Filename; Copy.Set (Solution => This.Solution); return Copy; end Temporary_Copy; ------------ -- Commit -- ------------ procedure Commit (This : in out Root) is Regular_Root : constant Root := Load_Root (Path (This)); -- We use a regular root to extract the paths of manifest and lockfile. -- A bit overkill but entirely more readable than messing with paths. procedure Commit (Source, Target : Absolute_File) is begin if Source /= "" then Directories.Backup_If_Existing (Target, Base_Dir => This.Working_Folder); Ada.Directories.Copy_File (Source_Name => Source, Target_Name => Target); Ada.Directories.Delete_File (Source); end if; end Commit; begin Commit (+This.Manifest, Crate_File (Regular_Root)); This.Manifest := +""; Commit (+This.Lockfile, Lock_File (Regular_Root)); This.Lockfile := +""; This.Sync_From_Manifest (Silent => True, Interact => False); end Commit; --------------------- -- Reload_Manifest -- --------------------- procedure Reload_Manifest (This : in out Root) is begin -- Load our manifest This.Release.Hold (Releases.From_Manifest (This.Crate_File, Manifest.Local, Strict => True)); -- And our pins This.Sync_Pins_From_Manifest (Exhaustive => False); end Reload_Manifest; -------------- -- Traverse -- -------------- procedure Traverse (This : in out Root; Doing : access procedure (This : in out Root; Solution : Solutions.Solution; State : Dependencies.States.State)) is ------------------- -- Traverse_Wrap -- ------------------- procedure Traverse_Wrap (Solution : Solutions.Solution; State : Dependencies.States.State) is begin Doing (This, Solution, State); end Traverse_Wrap; begin This.Solution.Traverse (Traverse_Wrap'Access, Root => Releases.Containers.Optional_Releases.Unit (Release (This))); end Traverse; end Alire.Roots; alire-1.2.1/src/alire/alire-roots.ads000066400000000000000000000325121430264165500174340ustar00rootroot00000000000000private with AAA.Caches.Files; with Ada.Directories; private with Ada.Finalization; with AAA.Strings; with Alire.Containers; with Alire.Dependencies.States; limited with Alire.Environment; private with Alire.Lockfiles; with Alire.Paths; with Alire.Properties; with Alire.Releases.Containers; with Alire.Solutions; with Alire.Solver; package Alire.Roots is Crate_File_Name : String renames Paths.Crate_File_Name; -- Type used to encapsulate the information about the working context. -- A valid alire working dir is one containing an alire/crate.toml file. type Root (<>) is tagged private; function Create_For_Release (This : Releases.Release; Parent_Folder : Any_Path; Env : Properties.Vector; Perform_Actions : Boolean := True) return Root; -- Prepare a workspace with This release as the root one, with manifest and -- lock files. IOWs, does everything but deploying dependencies. Intended -- to be called before a root exists, to build it. After this call, -- the Root is usable. For when retrieval is with --only (e.g., in a -- platform where it is unavailable, but we want to inspect the sources), -- Perform_Actions allow disabling these operations that make no sense for -- the Release on isolation. function Load_Root (Path : Any_Path) return Root; -- Attempt to detect a root at the given path. The root will be valid if -- path/alire exists, path/alire/*.toml is unique and loadable as a crate -- containing a single release. Otherwise, Checked_Error. -- See Alire.Directories.Detect_Root_Path to use with the following function New_Root (Name : Crate_Name; Path : Absolute_Path; Env : Properties.Vector) return Root; -- New unreleased release (not indexed, working copy) function New_Root (R : Releases.Release; Path : Absolute_Path; Env : Properties.Vector) return Root; -- From existing release -- Path must point to the session folder (parent of alire metadata folder) procedure Set (This : in out Root; Solution : Solutions.Solution) with Post => This.Has_Lockfile; -- Set Solution as the new solution for This, also storing it on disk procedure Check_Stored (This : Root); -- Check that the Root information exists on disk (paths exist, manifest -- file is at expected place...); otherwise Checked_Error. Does not check -- for lockfile existence. function Storage_Error (This : Root) return String; -- Returns the error that Check_Stored_Metadata would raise or "" otherwise function Is_Stored (This : Root) return Boolean is (This.Storage_Error = ""); -- Check that a root is properly stored (manifest on disk is loadable) function Direct_Withs (This : in out Root; Dependent : Releases.Release) return AAA.Strings.Set; -- Obtain the project files required by Dependent in This.Solution function Environment (This : Root) return Properties.Vector; -- Retrieve the environment stored within this root. Environment here -- refers to the platform properties. function Build_Context (This : in out Root) return Alire.Environment.Context; procedure Export_Build_Environment (This : in out Root); -- Export the build environment (PATH, GPR_PROJECT_PATH) of the given root function Name (This : Root) return Crate_Name; -- Crate name of the root release function Path (This : Root) return Absolute_Path; function Project_Paths (This : in out Root) return AAA.Strings.Set; -- Return all the paths that should be set in GPR_PROJECT_PATH for the -- solution in this root. This includes all releases' paths and any linked -- directories. function Release (This : Root) return Releases.Release; -- Retrieve a the root release, i.e., the one described in the manifest function Release (This : in out Root; Crate : Crate_Name) return Releases.Release with Pre => (Crate = This.Release.Name or else This.Solution.Depends_On (Crate)), Post => Release'Result.Provides (Crate); -- Retrieve a release, that can be either the root or any in the solution function Release_Base (This : in out Root; Crate : Crate_Name) return Any_Path; -- Find the base folder in which a release can be found for the given root function Solution (This : in out Root) return Solutions.Solution with Pre => This.Has_Lockfile; -- Returns the solution stored in the lockfile function Has_Lockfile (This : Root; Check_Valid : Boolean := False) return Boolean; -- Check the corresponding lockfile storing a solution for the root -- dependencies exists and (optionally, expensive) whether it is loadable. function Is_Lockfile_Outdated (This : Root) return Boolean with Pre => This.Has_Lockfile; -- Says whether the manifest has been manually edited, and so the lockfile -- requires being updated. This currently relies on timestamps, but (TODO) -- conceivably we could use checksums to make it more robust against -- automated changes within the same second. procedure Sync_From_Manifest (This : in out Root; Silent : Boolean; Interact : Boolean; Force : Boolean := False); -- If the lockfile timestamp is outdated w.r.t the manifest, or Force, do -- as follows: 1) Pre-deploy any remote pins in the manifest so they are -- usable when solving, and apply any local/version pins. 2) Ensure that -- dependencies are up to date in regard to the lockfile and manifest: if -- the manifest is newer than the lockfile, resolve again, as dependencies -- may have been edited by hand. 3) Ensure that releases in the lockfile -- are actually on disk (may be missing if cache was deleted, or the crate -- was just cloned). When Silent, downgrade log level of some output. When -- not Interact, run as if --non-interactive were in effect. procedure Sync_Manifest_And_Lockfile_Timestamps (This : Root) with Post => not This.Is_Lockfile_Outdated; -- If the lockfile is older than the manifest, sync their timestamps, do -- nothing otherwise. We want this when the manifest has been manually -- edited but the solution hasn't changed (and so the lockfile hasn't been -- regenerated). This way we know the lockfile is valid for the manifest. Allow_All_Crates : Containers.Crate_Name_Sets.Set renames Containers.Crate_Name_Sets.Empty_Set; procedure Update (This : in out Root; Allowed : Containers.Crate_Name_Sets.Set; Silent : Boolean; Interact : Boolean); -- Full update, explicitly requested. Will fetch/prune pins, update any -- updatable crates. Equivalent to `alr update`. Allowed is an optionally -- empty set of crates to which the update will be limited. Everything is -- updatable if Allowed.Is_Empty. procedure Deploy_Dependencies (This : in out Root); -- Download all dependencies not already on disk from This.Solution procedure Sync_Dependencies (This : in out Root; Silent : Boolean; -- Do not output anything Interact : Boolean; -- Request confirmation from the user Options : Solver.Query_Options := Solver.Default_Options; Allowed : Containers.Crate_Name_Sets.Set := Alire.Containers.Crate_Name_Sets.Empty_Set); -- Resolve and update all or given crates in a root, and regenerate -- configuration. When Silent, run as in non-interactive mode as this is an -- automatically-triggered update. procedure Sync_Pins_From_Manifest (This : in out Root; Exhaustive : Boolean; Allowed : Containers.Crate_Name_Sets.Set := Containers.Crate_Name_Sets.Empty_Set); -- Checks additions/removals of pins, and fetches remote pins. When not -- Exhaustive, a pin that is already in the solution is not re-downloaded. -- This is to avoid re-fetching all pins after each manifest edition. -- New pins, or pins with a changed commit are always downloaded. An update -- requested by the user (`alr update`) will be exhaustive. Allowed -- restricts which crates are affected. procedure Write_Manifest (This : Root); -- Generates the crate.toml manifest at the appropriate location for Root procedure Reload_Manifest (This : in out Root) with Pre => This.Path = Ada.Directories.Current_Directory; -- If changes have been done to the manifest, either via the dependency/pin -- modification procedures, or somehow outside alire after This was -- created, we need to reload the manifest. The solution remains -- untouched (use Update to recompute a fresh solution). procedure Traverse (This : in out Root; Doing : access procedure (This : in out Root; Solution : Solutions.Solution; State : Dependencies.States.State)); -- Recursively visit all dependencies in a safe order, ending with the root function Build (This : in out Root; Cmd_Args : AAA.Strings.Vector; Export_Build_Env : Boolean) return Boolean; -- Recursively build all dependencies that declare executables, and finally -- the root release. Also executes all pre-build/post-build actions for -- all releases in the solution (even those not built). Returns True on -- successful build. procedure Generate_Configuration (This : in out Root); -- Generate or re-generate the crate configuration files -- Files and folders derived from the root path (this obsoletes Alr.Paths): function Working_Folder (This : Root) return Absolute_Path; -- The "alire" folder inside the root path function Cache_Dir (This : Root) return Absolute_Path; -- The "alire/cache" dir inside the root path, containing releases and pins function Crate_File (This : Root) return Absolute_Path; -- The "/path/to/alire.toml" file inside Working_Folder function Pins_Dir (This : Root) return Absolute_Path; -- The folder where remote pins are checked out for this root function Lock_File (This : Root) return Absolute_Path; -- The "/path/to/alire.lock" file inside Working_Folder private function Load_Solution (Lockfile : String) return Solutions.Solution is (Lockfiles.Read (Lockfile).Solution); procedure Write_Solution (Solution : Solutions.Solution; Lockfile : String); -- Wrapper for use with Cached_Solutions package Cached_Solutions is new AAA.Caches.Files (Cached => Solutions.Solution, Load => Load_Solution, Write => Write_Solution); type Root is new Ada.Finalization.Controlled with record Environment : Properties.Vector; Path : UString; Release : Releases.Containers.Release_H; Cached_Solution : Cached_Solutions.Cache; Pins : Solutions.Solution; -- Closure of all pins that are recursively found -- These values, if different from "", mean this is a temporary root Manifest : Unbounded_Absolute_Path; Lockfile : Unbounded_Absolute_Path; end record; -- Support for editable roots begins here. These are not expected to be -- directly useful to clients, so better kept them under wraps. function Compute_Update (This : in out Root; Allowed : Containers.Crate_Name_Sets.Set := Containers.Crate_Name_Sets.Empty_Set; Options : Solver.Query_Options := Solver.Default_Options) return Solutions.Solution; -- Compute a new solution for the workspace. If Allowed is not empty, -- crates not appearing in Allowed are held back at their current version. -- This function loads configured indexes from disk. No changes are applied -- to This root. NOTE: pins have to be added to This.Solution beforehand, -- or they will not be applied. function Temporary_Copy (This : in out Root) return Root'Class; -- Obtain a temporary copy of This root, in the sense that it uses temp -- names for the manifest and lockfile. The cache is shared, so any -- pins/dependencies added to the temporary copy are ready if the copy is -- committed (see Commit call). The intended use is to be able to modify -- the temporary manifest, and finally compare the solutions between This -- and its copy. This way, no logic remains in `alr with`/`alr pin`, for -- example, as they simply edit the manifest as if the user did it by hand. procedure Commit (This : in out Root); -- Renames the manifest and lockfile to their regular places, making this -- root a regular one to all effects. function Dependencies_Dir (This : in out Root; Crate : Crate_Name) return Any_Path; -- The path at which dependencies have to be deployed, which for regular -- releases is simply ./alire/cache/dependencies. end Alire.Roots; alire-1.2.1/src/alire/alire-selftest.adb000066400000000000000000000111571430264165500201000ustar00rootroot00000000000000with Alire.Utils; with Alire.Config.Edit; with Alire.VCSs.Git; package body Alire.Selftest is -- Tests are Check_* procedures that end normally or raise some exception. procedure Check_Config_Changes is -- Ensure that configuration set in a run is also stored in memory Key : constant String := "test_key"; Val : constant String := "nominal"; begin Config.Edit.Set_Globally (Key, Val); pragma Assert (Config.DB.Defined (Key)); pragma Assert (Config.DB.Get (Key, "snafu") = Val); end Check_Config_Changes; ------------------------ -- Check_Email_Checks -- ------------------------ procedure Check_Email_Checks is use Utils; begin -- Check valid emails that must be accepted: pragma Assert (Could_Be_An_Email ("first@last.com", With_Name => False)); pragma Assert (Could_Be_An_Email ("first@last.es", With_Name => False)); pragma Assert (Could_Be_An_Email ("first@a-bcd--ef.com", With_Name => False)); pragma Assert (Could_Be_An_Email ("a@xn--espaa-rta.com.es", With_Name => False)); -- españa as IDN pragma Assert (Could_Be_An_Email ("first+middle@last.es", With_Name => False)); pragma Assert (Could_Be_An_Email ("+++___@last.es", With_Name => False)); pragma Assert (Could_Be_An_Email ("al.ej.an.dro.@last.com", With_Name => False)); pragma Assert (Could_Be_An_Email ("alan%$dro@last.com", With_Name => False)); pragma Assert (Could_Be_An_Email ("Ãlex ", With_Name => True)); -- Non-ascii in name. pragma Assert (Could_Be_An_Email ("First M. Last ", With_Name => True)); -- Check invalid emails that should be rejected: pragma Assert (not Could_Be_An_Email ("first@last", With_Name => False)); -- Missing at least 2 subdomains pragma Assert (not Could_Be_An_Email ("first@-last.com", With_Name => False)); -- Leading dash pragma Assert (not Could_Be_An_Email ("first@la False)); -- Invalid char in domain pragma Assert (not Could_Be_An_Email ("First ", With_Name => False)); -- With_Name should be true pragma Assert (not Could_Be_An_Email ("Ãlex", With_Name => True)); -- Missing space before '<' end Check_Email_Checks; ------------------------- -- Check_GitHub_Logins -- ------------------------- procedure Check_GitHub_Logins is function Valid (User : String) return Boolean renames Utils.Is_Valid_GitHub_Username; begin -- Examples taken from https://github.com/shinnn/github-username-regex pragma Assert (Valid ("a")); pragma Assert (Valid ("0")); pragma Assert (Valid ("a-b")); pragma Assert (Valid ("a-b-123")); pragma Assert (Valid ((1 .. 39 => 'a'))); pragma Assert (not Valid ("")); pragma Assert (not Valid ("a_b")); pragma Assert (not Valid ("a--b")); pragma Assert (not Valid ("a-b-")); pragma Assert (not Valid ("-a-b")); pragma Assert (not Valid ((1 .. 40 => 'a'))); end Check_GitHub_Logins; ----------------------- -- Check_Git_To_HTTP -- ----------------------- procedure Check_Git_To_HTTP is use VCSs.Git; begin -- Proper transform starting without .git pragma Assert (Transform_To_Public ("git@github.com:user/project") = "https://github.com/user/project.git"); -- Proper transform starting with .git pragma Assert (Transform_To_Public ("git@github.com:user/project.git") = "https://github.com/user/project.git"); -- GitLab pragma Assert (Transform_To_Public ("git@gitlab.com:user/project") = "https://gitlab.com/user/project.git"); -- Unknown site, not transformed pragma Assert (Transform_To_Public ("git@ggithub.com:user/project") = "git@ggithub.com:user/project"); -- No-op for HTTPS pragma Assert (Transform_To_Public ("https://github.com/user/project") = "https://github.com/user/project"); end Check_Git_To_HTTP; --------- -- Run -- --------- procedure Run is begin Check_Config_Changes; Check_Email_Checks; Check_GitHub_Logins; Check_Git_To_HTTP; Trace.Detail ("Self-checks passed"); exception when others => Trace.Error ("Self-checks failed"); raise; end Run; end Alire.Selftest; alire-1.2.1/src/alire/alire-selftest.ads000066400000000000000000000002351430264165500201140ustar00rootroot00000000000000package Alire.Selftest is procedure Run; -- Runs all self-tests. Should end silently or raise some exception on -- failure. end Alire.Selftest; alire-1.2.1/src/alire/alire-shared.adb000066400000000000000000000213401430264165500175100ustar00rootroot00000000000000with Ada.Directories; with Alire.Config.Edit; with Alire.Containers; with Alire.Directories; with Alire.Index; with Alire.Manifest; with Alire.Origins; with Alire.Paths; with Alire.Properties.Actions; with Alire.Root; with Alire.Toolchains.Solutions; with Alire.Warnings; package body Alire.Shared is use Directories.Operators; use type Milestones.Milestone; --------------- -- Available -- --------------- function Available (Detect_Externals : Boolean := True) return Releases.Containers.Release_Set is Result : Releases.Containers.Release_Set; ------------ -- Detect -- ------------ procedure Detect (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean) is use Ada.Directories; begin Stop := False; if Kind (Item) = Directory then if Exists (Full_Name (Item) / Paths.Crate_File_Name) then Trace.Debug ("Detected shared release at " & TTY.URL (Full_Name (Item))); Result.Include (Releases.From_Manifest (File_Name => Full_Name (Item) / Paths.Crate_File_Name, Source => Manifest.Index, Strict => True)); else Warnings.Warn_Once ("Unexpected folder in shared crates path: " & TTY.URL (Full_Name (Item))); end if; else Warnings.Warn_Once ("Unexpected file in shared crates path: " & TTY.URL (Full_Name (Item))); end if; end Detect; begin if Ada.Directories.Exists (Install_Path) then Directories.Traverse_Tree (Start => Install_Path, Doing => Detect'Access); end if; -- Include external toolchain members if Detect_Externals then Index.Detect_Externals (GNAT_External_Crate, Root.Platform_Properties); end if; for Tool of Toolchains.Tools loop if Detect_Externals then Index.Detect_Externals (Tool, Root.Platform_Properties); end if; for Release of Index.Releases_Satisfying (Toolchains.Any_Tool (Tool), Root.Platform_Properties) loop if not Release.Origin.Is_Regular then Result.Include (Release); end if; end loop; end loop; return Result; end Available; ------------------ -- Install_Path -- ------------------ function Install_Path return String is (Config.Edit.Path / Paths.Cache_Folder_Inside_Working_Folder / Paths.Deps_Folder_Inside_Cache_Folder); ----------- -- Share -- ----------- procedure Share (Release : Releases.Release; Location : Any_Path := Install_Path) is Already_Installed : Boolean := False; -------------------- -- Is_Installable -- -------------------- function Is_Installable return Boolean is -- We can install only regular releases. Also, releases that do not -- have post-fetch actions (as they might involve using dependencies) -- and dependencies simultaneously. I.e., post-fetch without -- dependencies is OK, as it is having dependencies and no -- post-fetch. Since "make" can be a pretty common single dependency -- that does not cause problems, we make an exception for it. use Containers.Crate_Name_Sets; Allowed_Dependencies : constant Containers.Crate_Name_Sets.Set := To_Set (To_Name ("make")); begin if Release.Dependencies.Is_Empty or else (for all Dep of Release.Flat_Dependencies (Root.Platform_Properties) => Allowed_Dependencies.Contains (Dep.Crate)) then return True; end if; if Release.On_Platform_Actions (Root.Platform_Properties, (Properties.Actions.Post_Fetch => True, others => False)).Is_Empty then return True; end if; return False; end Is_Installable; begin -- See if it is a valid installable origin if Release.Origin.Kind in Origins.External_Kinds then Raise_Checked_Error ("Only regular releases can be installed, but the requested release" & " has origin of kind " & Release.Origin.Kind'Image); end if; if not Is_Installable then Recoverable_Error ("Releases with both dependencies and post-fetch actions are not " & " yet supported. (Use `" & TTY.Terminal ("alr show ") & "` to examine " & "release properties.)"); end if; -- See if it can be skipped if Location = Install_Path and then Available.Contains (Release) then Trace.Detail ("Skipping installation of already available release: " & Release.Milestone.TTY_Image); return; end if; -- Deploy at the install location Release.Deploy (Env => Root.Platform_Properties, Parent_Folder => Location, Was_There => Already_Installed, Perform_Actions => True, Create_Manifest => True, Include_Origin => True); -- We need the origin to be included for the release to be recognized as -- a binary-origin release. if Already_Installed then Trace.Warning ("Reused previous installation for existing release: " & Release.Milestone.TTY_Image); end if; Put_Info (Release.Milestone.TTY_Image & " installed successfully."); end Share; ------------ -- Remove -- ------------ procedure Remove (Release : Releases.Release; Confirm : Boolean := not CLIC.User_Input.Not_Interactive) is use CLIC.User_Input; Path : constant Absolute_Path := Install_Path / Release.Deployment_Folder; begin if not Release.Origin.Is_Regular then Raise_Checked_Error ("Only regular releases deployed through Alire can be removed."); end if; if not Ada.Directories.Exists (Path) then Raise_Checked_Error ("Directory slated for removal does not exist: " & TTY.URL (Path)); end if; if Toolchains.Solutions.Is_In_Toolchain (Release) then Recoverable_Error ("The release to be removed (" & Release.Milestone.TTY_Image & ") is part of the " & "configured default toolchain."); -- If forced: Put_Warning ("Removing it anyway; it will be also removed from the " & "default toolchain."); -- So remove it at any level. We currently do not have a way to know -- from which level we have to remove this configuration. Toolchains.Unconfigure (Release.Name, Config.Global, Fail_If_Unset => False); Toolchains.Unconfigure (Release.Name, Config.Local, Fail_If_Unset => False); end if; if not Confirm or else Query (Question => "Release " & Release.Milestone.TTY_Image & " is going to " & "be removed, freeing " & Directories.TTY_Image (Directories.Tree_Size (Path)) & ". Do you want to proceed?", Valid => (No | Yes => True, others => False), Default => Yes) = Yes then Directories.Force_Delete (Path); Put_Success ("Release " & Release.Milestone.TTY_Image & " removed successfully"); end if; end Remove; ------------ -- Remove -- ------------ procedure Remove (Target : Milestones.Milestone; Confirm : Boolean := not CLIC.User_Input.Not_Interactive) is begin for Release of Available loop if Release.Milestone = Target then Remove (Release, Confirm); return; end if; end loop; Raise_Checked_Error ("Requested release is not installed: " & Target.TTY_Image); end Remove; ------------- -- Release -- ------------- function Release (Target : Milestones.Milestone; Detect_Externals : Boolean := True) return Releases.Release is begin for Release of Available (Detect_Externals) loop if Release.Milestone = Target then return Release; end if; end loop; raise Constraint_Error with "Not installed: " & Target.TTY_Image; end Release; end Alire.Shared; alire-1.2.1/src/alire/alire-shared.ads000066400000000000000000000030161430264165500175310ustar00rootroot00000000000000with Alire.Errors; with Alire.Milestones; with Alire.Releases.Containers; with CLIC.User_Input; package Alire.Shared is -- Stuff about shared/binary crates that are deployed not in the local -- workspace but in the shared configuration folder. function Available (Detect_Externals : Boolean := True) return Releases.Containers.Release_Set; -- Returns the releases installed at the shared location function Release (Target : Milestones.Milestone; Detect_Externals : Boolean := True) return Releases.Release; -- Retrieve the release corresponding to Target, if it exists. Will raise -- Constraint_Error if not among Available. function Install_Path return Any_Path; -- Returns the base folder in which all shared releases live procedure Share (Release : Releases.Release; Location : Any_Path := Install_Path); -- Deploy a release in the specified location procedure Remove (Release : Releases.Release; Confirm : Boolean := not CLIC.User_Input.Not_Interactive) with Pre => Available.Contains (Release) or else raise Checked_Error with Errors.Set ("Requested release is not installed: " & Release.Milestone.TTY_Image); -- Remove a release from the shared location for the configuration procedure Remove (Target : Milestones.Milestone; Confirm : Boolean := not CLIC.User_Input.Not_Interactive); -- Behaves as the previous Remove end Alire.Shared; alire-1.2.1/src/alire/alire-solutions-diffs.adb000066400000000000000000000320201430264165500213670ustar00rootroot00000000000000with Alire.Utils.Tables; with Alire.User_Pins; with Alire.Utils.TTY; with AAA.Strings; use AAA.Strings; package body Alire.Solutions.Diffs is -- TODO: with the new solution tracking of all dependencies status, this -- type could be made much simpler, even not needing to preprocess the -- solutions. To keep in mind for any future large refactoring needed here. -- Define all changes we can detect, to simplify retrieving their -- icon/text. These are not exclusive to each other. type Changes is (Added, -- A new release Removed, -- A removed dependency of any kind Hinted, -- An undetected external dependency Upgraded, -- An upgraded release Downgraded, -- A downgraded release Pinned, -- A release being pinned Unpinned, -- A release being unpinned Unchanged, -- An unchanged dependency/release Missing, -- A missing dependency Shared -- A release used from the shared installed releases ); ---------- -- Icon -- ---------- function Icon (Change : Changes) return String is (if TTY.Color_Enabled then (case Change is when Added => TTY.OK ("+"), when Removed => TTY.Emph ("✗"), when Hinted => TTY.Warn ("↪"), when Upgraded => TTY.OK ("â­§"), when Downgraded => TTY.Warn ("â­¨"), when Pinned => TTY.OK ("⊙"), when Unpinned => TTY.Emph ("ð©’"), when Unchanged => TTY.OK ("="), when Missing => TTY.Error ("âš "), when Shared => TTY.Emph ("♼")) else (case Change is when Added => "+", when Removed => "-", when Hinted => "~", when Upgraded => "^", when Downgraded => "v", when Pinned => "·", when Unpinned => "o", when Unchanged => "=", when Missing => "!", when Shared => "i" )); -- This type is used to summarize every detected change type Crate_Changes is record Icon, Best_Version : UString; Detail : AAA.Strings.Vector; end record; ---------------- -- Add_Change -- ---------------- procedure Add_Change (Change : in out Crate_Changes; Icon, Detail : String) is use UStrings; begin if Icon /= "" and then not Contains (+Change.Icon, Icon) then Append (Change.Icon, Icon); end if; if Detail /= "" then Change.Detail.Append (Detail); end if; end Add_Change; ------------- -- Between -- ------------- function Between (Former, Latter : Solution) return Diff is (Former => Former, Latter => Latter); ---------------------- -- Contains_Changes -- ---------------------- function Contains_Changes (This : Diff) return Boolean is (This.Former /= This.Latter); ------------------ -- Find_Changes -- ------------------ function Find_Changes (This : Diff; Crate : Crate_Name) return Crate_Changes is Chg : Crate_Changes; use UStrings; use all type Dependencies.States.Fulfillments; use all type Dependencies.States.Transitivities; use all type Semantic_Versioning.Version; Has_Former : constant Boolean := This.Former.Depends_On (Crate); Has_Latter : constant Boolean := This.Latter.Depends_On (Crate); function Former return Dependencies.States.State is (This.Former.State (Crate)); function Latter return Dependencies.States.State is (This.Latter.State (Crate)); ------------------- -- Add_Or_Remove -- ------------------- procedure Add_Or_Remove is begin if not Has_Former and then Has_Latter then Add_Change (Chg, Icon (Added), "new"); elsif Has_Former and then not Has_Latter then Add_Change (Chg, Icon (Removed), "removed"); end if; end Add_Or_Remove; ------------------- -- Fulfil_Change -- ------------------- procedure Fulfil_Change is ----------------- -- Gains_State -- ----------------- function Gains_State (Fulfilment : Dependencies.States.Fulfillments) return Boolean is ((not Has_Former or else Former.Fulfilment not in Fulfilment) and then Has_Latter and then Latter.Fulfilment in Fulfilment); use type Alire.User_Pins.Pin; begin -- New hint if Gains_State (Hinted) then Add_Change (Chg, Icon (Hinted), TTY.Warn ("external")); -- Changed linked dir elsif Has_Latter and then Latter.Is_Linked and then (not Has_Former or else not Former.Is_Linked or else Former.Link /= Latter.Link) then Add_Change (Chg, Icon (Pinned), Latter.Link.Image (User => True)); -- New unsolvable elsif Gains_State (Missed) then Add_Change (Chg, Icon (Missing), TTY.Error ("missing")); -- From hint to proper release elsif Has_Former and then Former.Is_Hinted and then Gains_State (Solved) then -- The crate was formerly in the solution, but not as regular -- release. Pinning is reported separately, so warn only when -- it was formerly an external. Add_Change (Chg, Icon (Added), TTY.OK ("solved")); end if; end Fulfil_Change; -------------------- -- Sharing_Change -- -------------------- procedure Sharing_Change is begin if (not Has_Former or else not Former.Is_Shared) and then Has_Latter and then Latter.Is_Shared then Add_Change (Chg, Icon (Shared), TTY.Emph ("installed")); elsif Has_Former and then Former.Is_Shared and then Has_Latter and then not Latter.Is_Shared then Add_Change (Chg, "", TTY.Emph ("local")); end if; end Sharing_Change; -------------------------- -- transitivity_changed -- -------------------------- procedure Transitivity_Changed is begin -- Inform only when changing from direct to indirect or viceversa. -- A new direct dependency merits no highlight since it is trivially -- expected. if (not Has_Former or else Former.Transitivity = Direct) and then Has_Latter and then Latter.Transitivity = Indirect then Add_Change (Chg, "", "indirect"); elsif Has_Former and then Has_Latter and then Former.Transitivity /= Latter.Transitivity then Add_Change (Chg, "", AAA.Strings.To_Lower_Case (Latter.Transitivity'Img)); end if; end Transitivity_Changed; ------------------------ -- Pinned_Or_Unpinned -- ------------------------ procedure Pinned_Or_Unpinned is begin if (not Has_Former or else not Former.Is_User_Pinned) and then Has_Latter and then Latter.Is_User_Pinned then -- The actual pin change will be shown via version/target Add_Change (Chg, Icon (Pinned), ""); elsif Has_Former and then Former.Is_User_Pinned and then Has_Latter and then not Latter.Is_User_Pinned then Add_Change (Chg, Icon (Unpinned), "unpinned"); end if; -- Report pin version when new/changed. Link target already reported -- in Fulfil_Change. if Has_Latter and then Latter.Is_Pinned and then (not Has_Former or else not Former.Is_Pinned or else Former.Pin_Version /= Latter.Pin_Version) then Add_Change (Chg, Icon (Pinned), "pin=" & TTY.Version (Latter.Pin_Version.Image)); end if; end Pinned_Or_Unpinned; --------------------- -- Provider_Change -- --------------------- procedure Provider_Change is begin if Has_Latter and then Latter.Is_Provided then Add_Change (Chg, "", TTY.Italic (Latter.Release.Name.As_String)); end if; end Provider_Change; --------------------- -- Up_Or_Downgrade -- --------------------- procedure Up_Or_Downgrade is begin if Has_Former and then Former.Has_Release and then Has_Latter and then Latter.Has_Release then if Former.Release.Version < Latter.Release.Version then Add_Change (Chg, Icon (Upgraded), "upgraded from " & TTY.Version (Former.Release.Version.Image)); elsif Latter.Release.Version < Former.Release.Version then Add_Change (Chg, Icon (Downgraded), "downgraded from " & TTY.Version (Former.Release.Version.Image)); end if; end if; end Up_Or_Downgrade; -------------------------------- -- Determine_Relevant_Version -- -------------------------------- procedure Determine_Relevant_Version is ------------------ -- Best_Version -- ------------------ function Best_Version (State : Dependencies.States.State) return String is (if State.Has_Release then TTY.Version (State.Release.Version.Image) elsif State.Is_Linked then -- linked dir without alire metadata TTY.Warn ("unknown") elsif State.Is_Hinted then -- undetected external, show dep TTY.Version (State.Versions.Image) else -- Not used, but just in case, the crate is in missing state: TTY.Error (State.Versions.Image)); begin -- Default to unknown Chg.Best_Version := +TTY.Error ("unknown"); -- Find something better if Has_Latter then Chg.Best_Version := +Best_Version (Latter); elsif Has_Former then -- Crate is gone, so it has no current version, show the one -- disappearing from the solutions. Chg.Best_Version := +Best_Version (Former); else raise Program_Error with "crate is neither in former or latter"; end if; end Determine_Relevant_Version; begin -- Go through possible changes and add each marker Add_Or_Remove; Pinned_Or_Unpinned; Fulfil_Change; Sharing_Change; Provider_Change; Transitivity_Changed; Up_Or_Downgrade; Determine_Relevant_Version; -- Final fill-in for no changes if Length (Chg.Icon) = 0 then Add_Change (Chg, Icon (Unchanged), ""); end if; if Chg.Detail.Is_Empty then Add_Change (Chg, "", "unchanged"); end if; return Chg; end Find_Changes; ------------------------ -- Latter_Is_Complete -- ------------------------ function Latter_Is_Complete (This : Diff) return Boolean is (This.Latter.Is_Complete); ----------- -- Print -- ----------- procedure Print (This : Diff; Changed_Only : Boolean := not Alire.Detailed; Prefix : String := " "; Level : Trace.Levels := Trace.Info) is Table : Utils.Tables.Table; Changed : Boolean := False; begin -- Start with an empty line to separate from previous output Trace.Log ("", Level); if not This.Latter.Is_Complete then Trace.Log (Prefix & "New solution is " & TTY.Warn ("incomplete."), Level); elsif This.Latter.Is_Complete and then not This.Former.Is_Complete then Trace.Log (Prefix & "New solution is " & TTY.OK ("complete."), Level); end if; -- Detailed changes otherwise for Crate of This.Former.Crates.Union (This.Latter.Crates) loop declare Changes : constant Crate_Changes := Find_Changes (This, Crate); begin if not Changed_Only or else Changes.Detail.Flatten /= "unchanged" then Changed := Changed or True; -- Show icon of change Table.Append (Prefix & (+Changes.Icon)); -- Always show crate name Table.Append (Utils.TTY.Name (Crate)); -- Show most precise version available Table.Append (+Changes.Best_Version); -- Finally show an explanation of the change depending on -- status changes. Table.Append ("(" & Changes.Detail.Flatten (",") & ")"); Table.New_Row; end if; end; end loop; if Changed then Table.Print (Level); else Trace.Log (Prefix & "No changes between former and new solution.", Level); end if; end Print; end Alire.Solutions.Diffs; alire-1.2.1/src/alire/alire-solutions-diffs.ads000066400000000000000000000016141430264165500214150ustar00rootroot00000000000000package Alire.Solutions.Diffs is type Diff is tagged private; -- Encapsulates the differences between two solutions function Between (Former, Latter : Solution) return Diff; -- Create a Diff from two solutions function Contains_Changes (This : Diff) return Boolean; -- Says if there are, in fact, changes between both solutions function Latter_Is_Complete (This : Diff) return Boolean; -- Says if the new solution is complete procedure Print (This : Diff; Changed_Only : Boolean := not Alire.Detailed; Prefix : String := " "; Level : Trace.Levels := Trace.Info); -- Print a summary of changes between two solutions. Prefix is prepended to -- every line. private type Diff is tagged record Former, Latter : Solution; end record; end Alire.Solutions.Diffs; alire-1.2.1/src/alire/alire-solutions.adb000066400000000000000000001347221430264165500203120ustar00rootroot00000000000000with Ada.Containers; with Alire.Config; with Alire.Crates; with Alire.Dependencies.Diffs; with Alire.Dependencies.Graphs; with Alire.Errors; with Alire.Index; with Alire.Milestones; with Alire.Root; with Alire.Solutions.Diffs; with Alire.Utils.Tables; with Alire.Utils.Tools; with Alire.Utils.TTY; with Semantic_Versioning.Extended; package body Alire.Solutions is package Semver renames Semantic_Versioning; use type Ada.Containers.Count_Type; use type Semantic_Versioning.Version; ---------------------- -- All_Dependencies -- ---------------------- function All_Dependencies (This : Solution) return State_Map is (This.Dependencies); ----------------- -- Composition -- ----------------- function Composition (This : Solution) return Compositions is (if not This.Solved then Unsolved elsif This.Dependencies.Is_Empty then Empty elsif (for all Dep of This.Dependencies => Dep.Is_Solved or else Dep.Is_Linked) then Releases elsif (for all Dep of This.Dependencies => Dep.Is_Hinted) then Hints elsif (for some Dep of This.Dependencies => Dep.Is_Missing) then Partial else Mixed); ---------------------- -- Contains_Release -- ---------------------- function Contains_Release (This : Solution; Crate : Crate_Name) return Boolean is (This.Depends_On (Crate) and then This.State (Crate).Is_Solved); ---------------- -- Dependency -- ---------------- function Dependency (This : Solution; Crate : Crate_Name) return Alire.Dependencies.Dependency is (This.Dependencies (Crate).As_Dependency); ------------------ -- Depending_On -- ------------------ function Depending_On (This : Solution; Dep : Dependencies.Dependency) return Solution is (Solution'(Solved => True, Dependencies => This.Dependencies.Merging (Dep))); ---------------- -- Depends_On -- ---------------- function Depends_On (This : Solution; Name : Crate_Name) return Boolean is (This.Dependencies.Contains (Name) or else (for some Dep of This.Dependencies => Dep.Has_Release and then Dep.Release.Provides (Name))); ---------------- -- Depends_On -- ---------------- function Depends_On (This : Solution; Release : Alire.Releases.Release) return Boolean is (for some Dep of This.Dependencies => Release.Provides (Dep.Crate)); ------------------------------ -- Depends_On_Specific_GNAT -- ------------------------------ function Depends_On_Specific_GNAT (This : Solution) return Boolean is (This.Releases.Contains_Or_Provides (GNAT_Crate) and then (for some Rel of This.Releases.Elements_Providing (GNAT_Crate) => Rel.Name /= GNAT_Crate)); ---------------------------- -- Empty_Invalid_Solution -- ---------------------------- function Empty_Invalid_Solution return Solution is (Solved => False, others => <>); -------------------------- -- Empty_Valid_Solution -- -------------------------- function Empty_Valid_Solution return Solution is (Solved => True, others => <>); ------------- -- Hinting -- ------------- function Hinting (This : Solution; Dep : Dependencies.Dependency) return Solution is (if This.Depends_On (Dep.Crate) then (Solved => True, Dependencies => This.Dependencies.Including (This.State (Dep.Crate).Hinting)) else (Solved => True, Dependencies => This.Dependencies.Including (States.New_State (Dep).Hinting))); ----------- -- Hints -- ----------- function Hints (This : Solution) return Dependency_Map is (This.Dependencies_That (States.Is_Hinted'Access)); ------------------ -- Is_Attempted -- ------------------ function Is_Attempted (This : Solution) return Boolean is (This.Composition /= Unsolved); ----------------- -- Is_Complete -- ----------------- function Is_Complete (This : Solution) return Boolean is (This.Composition <= Releases); ----------- -- Links -- ----------- function Links (This : Solution) return Dependency_Map is (This.Dependencies_That (States.Is_Linked'Access)); ------------ -- Misses -- ------------ function Misses (This : Solution) return Dependency_Map is (This.Dependencies_That (States.Is_Missing'Access)); ------------- -- Missing -- ------------- function Missing (This : Solution; Dep : Dependencies.Dependency) return Solution is (if This.Depends_On (Dep.Crate) then (Solved => True, Dependencies => This.Dependencies.Including (This.State (Dep.Crate).Missing)) else (Solved => True, Dependencies => This.Dependencies.Including (States.New_State (Dep).Missing))); ------------- -- Missing -- ------------- function Missing (This : Solution; Crate : Crate_Name) return Solution is (if This.Dependencies.Contains (Crate) then (Solved => True, Dependencies => This.Dependencies.Including (This.Dependencies (Crate).Missing)) else This); ------------- -- Pinning -- ------------- function Pinning (This : Solution; Crate : Crate_Name; Version : Semantic_Versioning.Version) return Solution is (Solved => True, Dependencies => This.Dependencies.Including (This.Dependencies (Crate).Pinning (Version))); -------------- -- Provides -- -------------- function Provides (This : Solution; Release : Alire.Releases.Release) return Boolean is (for some Solved of This.Releases => Solved.Provides (Release)); --------------- -- Resetting -- --------------- function Resetting (This : Solution; Crate : Crate_Name) return Solution is (This.Missing (Crate).User_Unpinning (Crate)); ------------- -- Setting -- ------------- function Setting (This : Solution; Crate : Crate_Name; Transitivity : States.Transitivities) return Solution is (Solved => True, Dependencies => This.Dependencies.Including (This.Dependencies (Crate).Setting (Transitivity))); --------------- -- Unlinking -- --------------- function Unlinking (This : Solution; Crate : Crate_Name) return Solution is (if This.Dependencies.Contains (Crate) then (Solved => True, Dependencies => This.Dependencies.Including (This.Dependencies (Crate).Unlinking)) else This); --------------- -- Unpinning -- --------------- function Unpinning (This : Solution; Crate : Crate_Name) return Solution is (if This.Dependencies.Contains (Crate) then (Solved => True, Dependencies => This.Dependencies.Including (This.Dependencies (Crate).Unpinning)) else This); --------------- -- Unsolving -- --------------- function Unsolving (This : Solution; Crate : Crate_Name) return Solution is (if This.Dependencies.Contains (Crate) then (Solved => True, Dependencies => This.Dependencies.Including (This.Dependencies (Crate).Unlinking.Unpinning.Missing)) else This); -------------------- -- User_Unpinning -- -------------------- function User_Unpinning (This : Solution; Crate : Crate_Name) return Solution is (This.Unpinning (Crate).Unlinking (Crate)); ----------------------- -- Dependencies_That -- ----------------------- function Dependencies_That (This : Solution; Check : not null access function (Dep : Dependency_State) return Boolean) return Dependency_Map is begin return Map : Dependency_Map do for Dep of This.Dependencies loop if Check (Dep) then Map.Insert (Dep.Crate, Dep.As_Dependency); end if; end loop; end return; end Dependencies_That; ---------------- -- Dependency -- ---------------- function Dependency (This : Solution; Dependent : Crate_Name; Dependee : Crate_Name) return Dependencies.Dependency is begin -- This is not particularly efficient. An Enumerate version that -- returned a map would serve better here if this proves to be a -- bottleneck in the future. for Dep of Conditional.Enumerate (This.State (Dependent) .Release.Dependencies (Root.Platform_Properties)) loop if Dep.Crate = Dependee then return Dep; end if; end loop; raise Program_Error with "invalid dependency request (body)"; end Dependency; ------------- -- Changes -- ------------- function Changes (Former, Latter : Solution) return Diffs.Diff is (Diffs.Between (Former, Latter)); ------------ -- Crates -- ------------ function Crates (This : Solution) return Containers.Crate_Name_Sets.Set is begin return Set : Containers.Crate_Name_Sets.Set do for Dep of This.Dependencies loop Set.Include (Dep.Crate); end loop; end return; end Crates; --------------- -- Forbidden -- --------------- function Forbidden (This : Solution; Env : Properties.Vector) return Dependency_Map is begin return Map : Dependency_Map do for Rel of This.Releases loop for Dep of Rel.Forbidden (Env) loop Map.Merge (Dep.Value); end loop; end loop; end return; end Forbidden; ------------- -- Forbids -- ------------- function Forbids (This : Solution; Release : Alire.Releases.Release; Env : Properties.Vector) return Boolean is begin pragma Warnings (Off, "disjunct"); -- Newer (12.1) compiler versions say: -- warning: unused variable "Solved" in disjunct [-gnatw.t] -- warning: consider extracting disjunct from quantified expression -- TODO: review in the future when we have moved on for a while. return -- Some of the releases in the solution forbid this one release (for some Solved of This.Releases => (for some Dep of Solved.Forbidden (Env) => Release.Satisfies (Dep.Value)) or else -- The candidate release forbids something in the solution (for some Dep of Release.Forbidden (Env) => (for some Rel of This.Releases => Rel.Satisfies (Dep.Value)))); pragma Warnings (On); end Forbids; --------------- -- Including -- --------------- function Including (This : Solution; Release : Alire.Releases.Release; Env : Properties.Vector; For_Dependency : Optional.Crate_Name := Optional.Crate_Names.Empty; Add_Dependency : Boolean := False; Shared : Boolean := False) return Solution is Dep_Name : constant Crate_Name := (if Add_Dependency then Release.Name else For_Dependency.Value); begin -- Check that there's no conflict with current solution if This.Forbids (Release, Env) then -- The solver should take care, so this is an unexpected error raise Program_Error with "release " & Release.Milestone.TTY_Image & " is forbidden by solution"; end if; return Result : Solution := This do if Add_Dependency and then not This.Depends_On (Release.Name) then Result := Result.Depending_On (Release.To_Dependency.Value); end if; -- Mark dependency solved and store its release. We double check here -- that the release actually is adequate for the dependency. if Release.Satisfies (Result.State (Dep_Name).As_Dependency) then Result.Dependencies := Result.Dependencies.Including (Result.State (Dep_Name).Solving (Release.Whenever (Env), Shared => Shared)); -- TODO: remove this Whenever once dynamic expr can be exported elsif Result.State (Dep_Name).Is_Hinted then Result := Result.Hinting (Result.State (Dep_Name).As_Dependency); else Result := Result.Missing (Result.State (Dep_Name).As_Dependency); end if; -- In addition, mark as solved other deps satisfied via provides for Dep of This.Dependencies loop if Dep.Crate /= Dep_Name and then not Dep.Is_Solved and then Release.Satisfies (Dep) then Trace.Debug ("Marking " & Dep.TTY_Image & " as solved collaterally by " & Release.Milestone.TTY_Image); Result.Dependencies := Result.Dependencies.Including (This.State (Dep.Crate) .Solving (Release.Whenever (Env), Shared => Shared)); end if; end loop; end return; end Including; --------------- -- Is_Better -- --------------- function Is_Better (This, Than : Solution) return Boolean is type Comparison is (Better, Equivalent, Worse); ---------------------- -- Compare_Versions -- ---------------------- function Compare_Versions (This, Than : Solution) return Comparison is begin -- TODO: instead of using the first discrepancy, we should count all -- differences and see which one is globally "newer". -- Check releases in both only for Rel of This.Releases loop if Than.Contains_Release (Rel.Name) then if Than.Releases_Providing (Rel.Name) .First_Element.Version < Rel.Version then return Better; elsif Rel.Version < Than.Releases_Providing (Rel.Name) .First_Element.Version then return Worse; end if; end if; end loop; return Equivalent; end Compare_Versions; ----------------------------- -- Lexicographical_Compare -- ----------------------------- function Lexicographical_Compare (This, Than : Solution) return Boolean is begin for Crate of This.Crates.Union (Than.Crates) loop if This.Depends_On (Crate) and then not Than.Depends_On (Crate) then return True; elsif not This.Depends_On (Crate) and then Than.Depends_On (Crate) then return False; end if; end loop; return False; -- Identical end Lexicographical_Compare; begin -- Prefer better compositions if This.Composition < Than.Composition then return True; elsif This.Composition > Than.Composition then return False; end if; -- Within complete solutions, prefer higher versions if This.Composition = Releases then case Compare_Versions (This, Than) is when Better => return True; when Worse => return False; when Equivalent => case Compare_Versions (This => Than, Than => This) is when Better => return False; when Worse => return True; when Equivalent => null; end case; end case; -- Disambiguate preferring a complete solution with less releases if This.Releases.Length < Than.Releases.Length then return True; elsif This.Releases.Length > Than.Releases.Length then return False; end if; -- At this point they must be identical; just in case keep comparing end if; -- Prefer more fulfilled releases when the solution is incomplete. -- The rationale is that fewer solved releases will mean more unknown -- missing indirect dependencies. if This.Releases.Length > Than.Releases.Length then return True; elsif This.Releases.Length < Than.Releases.Length then return False; end if; -- Prefer more undetected hints; at least we know these dependencies -- exist in some platforms and can be made available somehow. if This.Hints.Length > Than.Hints.Length then return True; elsif This.Hints.Length < Than.Hints.Length then return False; end if; -- Prefer fewer missing crates, although at this point who knows what -- indirect dependencies we are missing through undetected/missing -- dependencies. if This.Misses.Length < Than.Misses.Length then return True; elsif This.Misses.Length > Than.Misses.Length then return False; end if; -- Final disambiguation by any known versions in [partial] solutions case Compare_Versions (This, Than) is when Better => return True; when Worse => return False; when Equivalent => return Lexicographical_Compare (This, Than); -- Final way out is lexicographical ordering of crates, and first -- one missing a crate in the other solution is worse. end case; end Is_Better; ------------- -- Linking -- ------------- function Linking (This : Solution; Crate : Crate_Name; Link : Dependencies.States.Softlink) return Solution is (Solved => True, Dependencies => This.Dependencies.Including (This.State (Crate).Linking (Link))); --------------- -- Link_Pins -- --------------- function Link_Pins (This : Solution) return Conditional.Dependencies is begin return Dependencies : Conditional.Dependencies do for Dep of This.Dependencies loop if Dep.Is_Linked then Dependencies .Append (Conditional.New_Dependency (Dep.As_Dependency)); end if; end loop; end return; end Link_Pins; ---------- -- Pins -- ---------- function Pins (This : Solution) return Conditional.Dependencies is use type Conditional.Dependencies; begin return Dependencies : Conditional.Dependencies do for Dep of This.Dependencies loop if Dep.Is_Pinned then Dependencies := Dependencies and Conditional.New_Dependency (Dep.Crate, Dep.Pin_Version); end if; end loop; end return; end Pins; --------------- -- User_Pins -- --------------- function User_Pins (This : Solution) return Conditional.Dependencies is use type Conditional.Dependencies; begin return This.Pins and This.Link_Pins; end User_Pins; ---------- -- Pins -- ---------- function Pins (This : Solution) return Dependency_Map is begin return Result : Dependency_Map do for State of This.Dependencies loop if State.Is_Pinned then Result.Insert (State.Crate, Alire.Dependencies.New_Dependency (State.Crate, State.Pin_Version)); end if; end loop; end return; end Pins; ----------- -- Print -- ----------- procedure Print (This : Solution; Root : Alire.Releases.Release; Env : Properties.Vector; Detailed : Boolean; Level : Trace.Levels) is begin -- Outta here if nothing to print if not This.Solved then Trace.Log ("Dependencies (solution):", Level); Trace.Log (" No solving attempted", Level); return; elsif This.Dependencies.Is_Empty then return; end if; -- Print all releases first, followed by the rest of dependencies if not This.Releases.Is_Empty then Trace.Log ("Dependencies (solution):", Level); for Dep of This.Dependencies loop if Dep.Has_Release then Trace.Log (" " & Utils.TTY.Name (Dep.Crate) & "=" & TTY.Version (Dep.Release.Version.Image) & (if Dep.Crate /= Dep.Release.Name -- provided by then " (" & TTY.Italic (Utils.TTY.Name (Dep.Release.Name)) & ")" else "") & (if Dep.Is_Pinned or else Dep.Is_Linked then TTY.Emph (" (pinned)") elsif Dep.Is_Shared then TTY.Emph (" (installed)") else "") & (if Detailed then " (origin: " & (if Dep.Is_Linked then Dep.Link.Relative_Path & (if Dep.Link.Is_Remote then " from " & Dep.Link.TTY_URL_With_Reference (Detailed) else "") -- no remote else AAA.Strings.To_Lower_Case (Dep.Release.Origin.Kind'Img)) & ")" -- origin completed else ""), -- no details Level); end if; end loop; end if; -- Show other dependencies with their status and hints -- TODO: show these in line with the previous ones, as most of the info -- is common. Just mark the true external (missing ones) better, see -- #646 and #685. Now, pins without a release are shown here too, -- although they're properly resolved. if (for some Dep of This.Dependencies => not Dep.Has_Release) then Trace.Log ("Dependencies (external):", Level); for Dep of This.Dependencies loop if not This.State (Dep.Crate).Has_Release then Trace.Log (" " & Dep.TTY_Image & (if Dep.Is_Pinned or else Dep.Is_Linked then TTY.Emph (" (pinned)") else "") & (if Detailed and then Dep.Is_Linked then " (origin: " & Dep.Link.Relative_Path & (if Dep.Link.Is_Remote then " from " & Dep.Link.TTY_URL_With_Reference else "") -- no remote & ")" -- origin completed else ""), -- no details Level); -- Look for hints. If we are relying on workspace information -- the index may not be loaded, or have changed, so we need to -- ensure the crate is indexed. if Index.Exists (Dep.Crate) then for Hint of Alire.Index.Crate (Dep.Crate) .Externals.Hints (Name => Dep.Crate, Env => Env) loop Trace.Log (TTY.Emph (" Hint: ") & Hint, Level); end loop; end if; end if; end loop; end if; -- Show forbidden, if any if not This.Forbidden (Env).Is_Empty then Trace.Log ("Dependencies (forbidden):", Level); for Dep of This.Forbidden (Env) loop Trace.Log (" " & Dep.TTY_Image, Level); end loop; end if; -- Textual and graphical dependency graph if not This.Dependencies.Is_Empty then Trace.Log ("Dependencies (graph):", Level); declare With_Root : constant Solution := This.Including (Root, Env, Add_Dependency => True); Graph : constant Alire.Dependencies.Graphs.Graph := Alire.Dependencies.Graphs .From_Solution (With_Root, Env); begin Graph.Print (With_Root, Prefix => " "); end; end if; end Print; ----------------- -- Print_Graph -- ----------------- procedure Print_Graph (This : Solution; Root : Alire.Releases.Release; Env : Properties.Vector) is begin if This.Dependencies.Is_Empty then Trace.Always ("There are no dependencies."); else Utils.Tools.Check_Tool (Utils.Tools.Easy_Graph, Fail => False); if Utils.Tools.Available (Utils.Tools.Easy_Graph) then declare With_Root : constant Solution := This.Including (Root, Env, Add_Dependency => True); Graph : constant Alire.Dependencies.Graphs.Graph := Alire.Dependencies.Graphs .From_Solution (With_Root, Env); begin Graph.Plot (With_Root); end; else Trace.Info ("Defaulting to tree view."); This.Print_Tree (Root); end if; end if; end Print_Graph; ----------------- -- Print_Hints -- ----------------- procedure Print_Hints (This : Solution; Env : Properties.Vector) is begin if not This.Hints.Is_Empty then Trace.Warning ("The following external dependencies " & "are unavailable within Alire:"); for Dep of This.Hints loop Trace.Warning (" " & Dep.Image); if Index.All_Crates.Contains (Dep.Crate) then for Hint of Index.Crate (Dep.Crate) .Externals.Hints (Dep.Crate, Env) loop Trace.Warning (" Hint: " & Hint); end loop; end if; end loop; Trace.Warning ("They should be made available in the environment by the user."); end if; end Print_Hints; ---------------- -- Print_Pins -- ---------------- procedure Print_Pins (This : Solution) is Table : Utils.Tables.Table; begin if This.Links.Is_Empty and then Dependency_Map'(This.Pins).Is_Empty then Trace.Always ("There are no pins"); else for Dep of This.Dependencies loop if Dep.Is_Linked then Table .Append (Utils.TTY.Name (Dep.Crate)) .Append (TTY.URL ("file:") & Dep.Link.Relative_Path) .Append (if Dep.Link.Is_Remote then Dep.Link.TTY_URL_With_Reference (Detailed) else "") .New_Row; elsif Dep.Is_Pinned then Table .Append (Utils.TTY.Name (Dep.Crate)) .Append (TTY.Version (Dep.Pin_Version.Image)) .New_Row; end if; end loop; Table.Print (Always); end if; end Print_Pins; ------------------ -- Print_States -- ------------------ procedure Print_States (This : Solution; Indent : String := " "; Level : Trace.Levels := Trace.Info) is Table : Utils.Tables.Table; begin Table.Header (Indent & "RELEASE"); Table.Header ("DEPENDENCY"); Table.New_Row; for State of This.Dependencies loop if State.Has_Release then Table.Append (Indent & State.Release.Milestone.TTY_Image); else Table.Append (Indent & TTY.Warn ("(none)")); end if; Table.Append (State.TTY_Image); Table.New_Row; end loop; Table.Print (Level => Level); end Print_States; ---------------- -- Print_Tree -- ---------------- procedure Print_Tree (This : Solution; Root : Alire.Releases.Release; Prefix : String := ""; Print_Root : Boolean := True) is Mid_Node : constant String := (if TTY.Color_Enabled then "├── " else "+-- "); Last_Node : constant String := (if TTY.Color_Enabled then "└── " else "+-- "); Branch : constant String := (if TTY.Color_Enabled then "│ " else "| "); No_Branch : constant String := " "; procedure Print (Deps : Dependencies.Containers.Set; Prefix : String := ""; Omit : Boolean := False) -- Omit is used to remove the top-level connectors, for when the tree -- is printed without the root release. is Last : UString; -- Used to store the last dependency name in a subtree, to be able to -- use the proper ASCII connector. See just below. begin -- Find last printable dependency. This is related to OR trees, that -- might cause the last in the enumeration to not really belong to -- the solution. for Dep of Deps loop if This.Depends_On (Dep.Crate) then Last := +(+Dep.Crate); end if; end loop; -- Print each dependency for real for Dep of Deps loop if This.Depends_On (Dep.Crate) then Trace.Always (Prefix -- The prefix is the possible "|" connectors from upper tree -- levels. -- Print the appropriate final connector for the node & (if Omit -- top-level, no prefix then "" else (if +Dep.Crate = +Last then Last_Node -- A └── connector else Mid_Node)) -- A ├── connector -- For a dependency solved by a release, print exact -- version. Otherwise print the state of the dependency. & (if This.State (Dep.Crate).Has_Release then This.State (Dep.Crate).Milestone_Image else This.State (Dep.Crate).TTY_Image) -- And dependency that introduces the crate in the solution & " (" & TTY.Emph (Dep.Versions.Image) & ")"); -- Recurse for further releases if This.State (Dep.Crate).Has_Release then Print (Conditional.Enumerate (This.State (Dep.Crate).Release.Dependencies).To_Set, Prefix => Prefix -- Indent adding the proper running connector & (if Omit then "" else (if +Dep.Crate = +Last then No_Branch -- End of this connector else Branch))); -- "│" over the subtree end if; end if; end loop; end Print; begin if Print_Root then Trace.Always (Prefix & Root.Milestone.TTY_Image); end if; Print (Conditional.Enumerate (Root.Dependencies).To_Set, Prefix, not Print_Root); end Print_Tree; -------------------- -- Print_Versions -- -------------------- procedure Print_Versions (This : Solution; Root : Roots.Root) is use all type Dependencies.States.Fulfillments; Table : Utils.Tables.Table; begin Table .Append (TTY.Bold ("CRATE")) .Append (TTY.Bold ("DEPENDENCY")) .Append (TTY.Bold ("PROVIDER")) .Append (TTY.Bold ("SOLVED")) .Append (TTY.Bold ("LATEST")) .New_Row; for Dep of This.Including (Root.Release, Root.Environment, Add_Dependency => True).Required loop Table.Append (+Dep.Crate); if Dep.Crate = Root.Release.Name then Table.Append (TTY.Version ("(root)")); else Table.Append (TTY.Version (Dep.Versions.Image)); end if; if Dep.Has_Release and then Dep.Crate /= Dep.Release.Name then Table.Append (TTY.Italic (Dep.Release.Name.As_String)); else Table.Append (""); end if; Index.Detect_Externals (Dep.Crate, Root.Environment); -- Detect externals for the crate, in case they add more versions declare Latest_Known : constant Boolean := Index.Exists (Dep.Crate) and then not Index.Crate (Dep.Crate).Releases.Is_Empty; Latest : constant Alire.Releases.Containers.Release_H := (if Latest_Known then Alire.Releases.Containers.To_Release_H (Index.Crate (Dep.Crate).Releases.Last_Element) else Alire.Releases.Containers.Release_Holders .Empty_Holder); begin -- Print release version, colored according to being latest case Dep.Fulfilment is when Solved => if not Latest_Known or else Dep.Release.Version < Latest.Element.Version then Table.Append (TTY.Warn (Dep.Release.Version.Image)); else Table.Append (TTY.OK (Dep.Release.Version.Image)); end if; when Linked => Table.Append (TTY.URL (Dep.Link.Path)); when others => Table.Append (TTY.Error ("missing")); end case; -- Display latest crate version, when known if Latest_Known then Table.Append (TTY.Version (Latest.Element.Version.Image)); else -- For whatever reason the index hasn't a release Table.Append (TTY.Warn ("unindexed")); end if; Table.New_Row; end; end loop; Table.Print (Always); end Print_Versions; -------------- -- Releases -- -------------- function Releases (This : Solution) return Release_Map is begin return Result : Release_Map do for Dep of This.Dependencies loop if Dep.Has_Release then Result.Insert (Dep.Crate, Dep.Release); end if; end loop; end return; end Releases; ---------------------------- -- Dependencies_Providing -- ---------------------------- function Dependencies_Providing (This : Solution; Crate : Crate_Name) return State_Map is Result : State_Map; begin for Dep of This.Dependencies loop if Dep.Has_Release and then Dep.Release.Provides (Crate) then Result.Insert (Dep.Crate, Dep); end if; end loop; return Result; end Dependencies_Providing; ------------------------ -- Releases_Providing -- ------------------------ function Releases_Providing (This : Solution; Crate : Crate_Name) return Alire.Releases.Containers.Release_Set is Result : Alire.Releases.Containers.Release_Set; begin for State of This.Dependencies_Providing (Crate) loop Result.Include (State.Release); end loop; return Result; end Releases_Providing; ------------------------ -- Releases_Providing -- ------------------------ function Releases_Providing (This : Solution; Release : Alire.Releases.Release) return Alire.Releases.Containers.Release_Set is Result : Alire.Releases.Containers.Release_Set; begin for Rel of This.Releases loop if Rel.Provides (Release) then Result.Include (Rel); end if; end loop; return Result; end Releases_Providing; --------- -- Set -- --------- procedure Set (This : in out Solution; Crate : Crate_Name; Transitivity : Dependencies.States.Transitivities) is begin This.Dependencies := This.Dependencies.Including (This.State (Crate).Setting (Transitivity)); end Set; ----------- -- State -- ----------- function State (This : Solution; Crate : Crate_Name) return Dependency_State is begin if This.Dependencies.Contains (Crate) then return This.Dependencies (Crate); end if; for Dep of This.Dependencies loop if Dep.Has_Release and then Dep.Release.Provides (Crate) then return Dep; end if; end loop; raise Program_Error with Errors.Set ("No dependency in solution matches crate " & Utils.TTY.Name (Crate)); end State; ----------- -- State -- ----------- function State (This : Solution; Release : Alire.Releases.Release) return Dependency_State is begin if This.Dependencies.Contains (Release.Name) then return This.Dependencies (Release.Name); end if; for Dep of This.Dependencies loop if Release.Provides (Dep.Crate) then return Dep; end if; end loop; raise Program_Error with Errors.Set ("No dependency in solution matches release " & Release.Milestone.TTY_Image); end State; --------------- -- With_Pins -- --------------- function With_Pins (This, Src : Solution) return Solution is begin return Result : Solution := This do for Dep of Src.Dependencies loop if Dep.Is_Pinned then -- We need to copy the pin version; the solving status might -- have changed, so we do not just blindly copy the old pin -- into the new solution. Result := Result.Pinning (Dep.Crate, Dep.Pin_Version); end if; end loop; end return; end With_Pins; ---------- -- Keys -- ---------- package Keys is -- TOML keys used locally for loading and saving of solutions Context : constant String := "context"; Solved : constant String := "solved"; State : constant String := "state"; end Keys; use TOML; -- The structure used to store a solution is: -- -- [context] -- advisory -- solved = boolean -- version # TBD: for breaking changes -- -- [[state]] -- One per dependency in Solution.Dependencies --------------- -- From_TOML -- --------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Solution is This : Solution; begin Trace.Debug ("Reading solution from TOML..."); -- Context This.Solved := From.Checked_Pop (Keys.Context, TOML_Table) -- [context] .Get (Keys.Solved).As_Boolean; -- solved -- Load dependency statuses if From.Unwrap.Has (Keys.State) then This.Dependencies := States.Maps.From_TOML (From.Descend (From.Checked_Pop (Keys.State, TOML_Array), "states")); end if; From.Report_Extra_Keys; return This; end From_TOML; ------------- -- To_TOML -- ------------- overriding function To_TOML (This : Solution) return TOML.TOML_Value is begin return Root : constant TOML_Value := Create_Table do -- Output advisory and validity declare Context : constant TOML_Value := Create_Table; begin Root.Set (Keys.Context, Context); Context.Set (Keys.Solved, Create_Boolean (This.Solved)); end; -- Output the dependency statuses Root.Set (Keys.State, This.Dependencies.To_TOML); end return; end To_TOML; ----------------------------- -- Narrow_New_Dependencies -- ----------------------------- function Narrow_New_Dependencies (Old_Deps, New_Deps : Conditional.Dependencies; New_Sol : Solution) return Conditional.Dependencies is Releases : constant Release_Map := New_Sol.Releases; use type Conditional.Dependencies; use type Semver.Extended.Version_Set; Diff : constant Dependencies.Diffs.Diff := Dependencies.Diffs.Between (Old_Deps, New_Deps); begin -- Do nothing when deps are being removed. if not Config.DB.Get (Config.Keys.Solver_Autonarrow, True) or else not Diff.Removed.Is_Empty then return New_Deps; end if; return Fixed_Deps : Conditional.Dependencies := Old_Deps do for Added of Diff.Added loop -- Keep as-is any version that is not "*", or is not solved if Added.Versions /= Semver.Extended.Any or else not Releases.Contains (Added.Crate) then Fixed_Deps := Fixed_Deps and Added; else -- Use either caret or tilde to narrow down the version declare Fixed : constant Dependencies.Dependency := Dependencies.New_Dependency (Added.Crate, Semver.Extended.Value ((if Releases (Added.Crate).Version.Major in 0 then "~" else "^") & Releases (Added.Crate).Version.Image)); begin Trace.Detail ("Narrowing down dependency " & Added.TTY_Image & " as " & Fixed.TTY_Image); Fixed_Deps := Fixed_Deps and Fixed; end; end if; end loop; end return; end Narrow_New_Dependencies; -------------- -- Traverse -- -------------- procedure Traverse (This : Solution; Doing : access procedure (This : Solution; State : Dependency_State); Root : Alire.Releases.Containers.Optional := Alire.Releases.Containers.Optional_Releases.Empty) is Pending : State_Map := This.Dependencies; Visited : Containers.Crate_Name_Sets.Set; Round : Natural := 0; ----------- -- Visit -- ----------- procedure Visit (State : Dependency_State) is begin Trace.Debug ("Marking visited: " & Utils.TTY.Name (State.Crate)); Visited.Include (State.Crate); Pending.Exclude (State.Crate); if State.Has_Release then for Mil of State.Release.Provides loop Trace.Debug ("Marking visited (provided): " & Utils.TTY.Name (Mil.Crate)); Visited.Include (Mil.Crate); end loop; end if; Trace.Debug ("Visiting now: " & State.TTY_Image); Doing (This, State); end Visit; begin -- Visit first dependencies that do not have releases (and hence no -- dependencies) or that are preinstalled. for Dep of This.Dependencies loop if not Dep.Has_Release or else Dep.Is_Shared then Visit (Dep); end if; end loop; -- Visit regular resolved dependencies, once their dependencies are -- already visited: while not Pending.Is_Empty loop Round := Round + 1; declare To_Remove : State_Map; begin -- In the 1st step of each round we identify releases that don't -- have unvisited dependencies. for Dep of Pending loop if not Dep.Is_Solved then Trace.Debug ("Round" & Round'Img & ": NOOP " & Dep.Release.Milestone.Image); To_Remove.Insert (Dep.Crate, Dep); elsif (for some Rel_Dep of Dep.Release.Flat_Dependencies (Alire.Root.Platform_Properties) => not Visited.Contains (Rel_Dep.Crate)) then Trace.Debug ("Round" & Round'Img & ": SKIP not-ready " & Dep.Release.Milestone.Image); else Trace.Debug ("Round" & Round'Img & ": VISIT ready " & Dep.Release.Milestone.Image); To_Remove.Insert (Dep.Crate, Dep); end if; end loop; -- In the 2nd step of each round we actually visit all releases -- that were marked as safe to visit in the 1st step of the round. if To_Remove.Is_Empty then raise Program_Error with "No release visited in round" & Round'Img; else for Dep of To_Remove loop Visit (Dep); end loop; end if; end; end loop; -- Finally, visit the root, if given if Root.Has_Element then -- Create a temporary solved state for the root declare Root_State : constant Dependency_State := Dependencies.States.New_State (Root.Element.To_Dependency.Value) .Solving (Root.Element); begin Visit (Root_State); end; end if; end Traverse; end Alire.Solutions; alire-1.2.1/src/alire/alire-solutions.ads000066400000000000000000000426741430264165500203370ustar00rootroot00000000000000with Alire.Conditional; with Alire.Containers; with Alire.Dependencies.Containers; with Alire.Dependencies.States.Maps; with Alire.Interfaces; with Alire.Optional; with Alire.Properties; with Alire.Releases.Containers; limited with Alire.Roots; with Alire.TOML_Adapters; limited with Alire.Solutions.Diffs; with Semantic_Versioning; with TOML; package Alire.Solutions is subtype Dependency_Map is Dependencies.Containers.Map; subtype Dependency_State is Dependencies.States.State; subtype Name_Set is Containers.Crate_Name_Sets.Set; subtype Release_Map is Releases.Containers.Release_Map; subtype State_Map is Dependencies.States.Maps.Map; package States renames Dependencies.States; -- Note in the following enum type that the only complete solutions are -- Releases and Empty. This enum is mostly useful to classify solutions in -- order of "goodness". type Compositions is (Empty, -- Trivial empty solution when no dependencies are needed Releases, -- Proper (regular or detected) releases with a concrete version and -- deployer, and linked directories. These solutions should build -- properly (if the linked dependencies are correct). Mixed, -- Releases + at least one undetected hint (i.e., build success is not -- guaranteed). Hints, -- Only undetected hints, no proper releases at all Partial, -- There's at least one missing dependency, in the sense of not being -- even an undetected hint. This means some unindexed crate is required, -- or a version that does not exist, or a combination of dependencies -- results in impossible (empty version intersection) version -- requirements. Unsolved -- Solving hasn't even been attempted (e.g., when retrieving with -- --only), so the solution has no dependencies but is still invalid. ); type Solution is new Interfaces.Tomifiable with private; -- A solution stores all dependencies required by some root crate. More -- precisely, it stores the regular releases that fulfill some dependency -- and the particular standing of a dependency (solved, hinted, missing...) -- A solved dependency will be accompanied by the particular release that -- fulfills it. ------------------ -- Construction -- ------------------ function Empty_Invalid_Solution return Solution; -- An unsolved empty solution. This is the only way to obtain an unsolved -- solution. Any solution that has dependencies or is modified in any way -- is considered to having been attempted to be solved. function Empty_Valid_Solution return Solution; function Depending_On (This : Solution; Dep : Dependencies.Dependency) return Solution; -- Add or merge a dependency without changing its state. For a new -- dependency, it will be marked as Pending and with Unknown transitivity. function Hinting (This : Solution; Dep : Dependencies.Dependency) return Solution; -- Add/merge dependency as hinted in solution function Including (This : Solution; Release : Alire.Releases.Release; Env : Properties.Vector; For_Dependency : Optional.Crate_Name := Optional.Crate_Names.Empty; Add_Dependency : Boolean := False; Shared : Boolean := False) return Solution with Pre => Add_Dependency xor (For_Dependency.Has_Element and then This.All_Dependencies.Contains (For_Dependency.Value)); -- Add a release to the solution, marking its dependency as solved. Takes -- care of adding forbidden dependencies and ensuring the Release does -- not conflict with the current solution (the Solver must check this, -- so Program_Error otherwise). Since from the release we can't know -- the actual complete dependency the release is fulfilling, by default -- we don't create its dependency (it must exist previously). Only in -- particular cases where we want to add a dependency matching the -- release Add_Dependency should be true. function Resetting (This : Solution; Crate : Crate_Name) return Solution; -- Equivalent to .Missing (Crate).User_Unpinning (Crate). That is, remove -- any fulfillment and any pinning. function Linking (This : Solution; Crate : Crate_Name; Link : Dependencies.States.Softlink) return Solution with Pre => This.Depends_On (Crate); -- Fulfill a dependency with a link pin function Missing (This : Solution; Dep : Dependencies.Dependency) return Solution; -- Add/merge dependency as missing in solution function Missing (This : Solution; Crate : Crate_Name) return Solution; -- Fulfill an existing dependency as missing, or do nothing otherwise function Pinning (This : Solution; Crate : Crate_Name; Version : Semantic_Versioning.Version) return Solution; -- Return a copy of the solution with the given crate pinned to a version. -- If the crate was not in the original solution it will be added. function Setting (This : Solution; Crate : Crate_Name; Transitivity : States.Transitivities) return Solution; -- Change transitivity function Unlinking (This : Solution; Crate : Crate_Name) return Solution; -- Unpin a crate. If the crate was not linked or not in the solution -- nothing will be done. If it was, it is now missing. function Unpinning (This : Solution; Crate : Crate_Name) return Solution; -- Unpin a crate. If the crate was not pinned or not in the solution -- nothing will be done. function User_Unpinning (This : Solution; Crate : Crate_Name) return Solution; -- Remove either a pin or a link for a crate; e.g. same as calling -- Unpinning and Unlinking in succession. Nothing will be done if -- crate wasn't in the solution. function Unsolving (This : Solution; Crate : Crate_Name) return Solution; -- Remove links, pins, releases... and mark the crate as missing. If not in -- the solution, nothing will be done. function With_Pins (This, Src : Solution) return Solution; -- Copy pins from Src to This and return it ---------------- -- Attributes -- ---------------- function Changes (Former, Latter : Solution) return Diffs.Diff; function Composition (This : Solution) return Compositions; function Contains_Release (This : Solution; Crate : Crate_Name) return Boolean; -- Say if Crate is among the solved releases for this solution. It will -- return False if the solution does not even depend on Crate. function Crates (This : Solution) return Name_Set; -- Dependency name closure, independent of the status in the solution, as -- found by the solver starting from the direct dependencies. function All_Dependencies (This : Solution) return State_Map; -- Get all states in the solution to e.g. iterate over function Dependencies_That (This : Solution; Check : not null access function (Dep : Dependency_State) return Boolean) return Dependency_Map; -- Retrieve all states that pass a boolean check function Dependency (This : Solution; Crate : Crate_Name) return Dependencies.Dependency with Pre => This.Depends_On (Crate); -- Return the specific dependency versions as currently stored function Dependency (This : Solution; Dependent : Crate_Name; Dependee : Crate_Name) return Dependencies.Dependency with Pre => (This.State (Dependent).Has_Release and then This.Depends_On (Dependee)) or else raise Program_Error with "invalid dependency request"; -- The solver groups dependencies on a same crate by several dependents. -- This function allows identifying the concrete dependency that a solved -- release introduced in the solution. function Depends_On (This : Solution; Name : Crate_Name) return Boolean; -- Says if the solution depends on the crate in some way. Will also -- consider Provides of releases in the solution. function Depends_On (This : Solution; Release : Alire.Releases.Release) return Boolean; -- Likewise, but take also into account the Release.Provides function Depends_On_Specific_GNAT (This : Solution) return Boolean; -- Say if the solution contains a release which is a gnat_something function Forbidden (This : Solution; Env : Properties.Vector) return Dependency_Map; -- Returns all forbidden dependencies by releases in solution function Forbids (This : Solution; Release : Alire.Releases.Release; Env : Properties.Vector) return Boolean; -- Check whether the solution forbids a release function Provides (This : Solution; Release : Alire.Releases.Release) return Boolean; -- Check whether the solution already contains or provides a release -- equivalent to Release. function Dependencies_Providing (This : Solution; Crate : Crate_Name) return State_Map; -- Return the dependency containing the release that provides Crate (may be -- empty). function Releases_Providing (This : Solution; Crate : Crate_Name) return Alire.Releases.Containers.Release_Set; function Releases_Providing (This : Solution; Release : Alire.Releases.Release) return Alire.Releases.Containers.Release_Set; -- Return releases already in the solution that are equivalent to Release -- (may be empty). function Hints (This : Solution) return Dependency_Map; -- Return undetected externals in the solution function Is_Attempted (This : Solution) return Boolean with Post => Is_Attempted'Result = (This.Composition /= Unsolved); -- Say if a real attempt at solving has been done function Is_Better (This, Than : Solution) return Boolean; -- Relative ordering to prioritize found solutions. We prefer decreasing -- order of Composition (avoid undetected externals/missing dependencies). function Is_Complete (This : Solution) return Boolean; -- A solution is complete when it fulfills all dependencies via regular -- releases, detected externals, or linked directories. function Links (This : Solution) return Dependency_Map; -- Return crates that are solved with a softlink function Link_Pins (This : Solution) return Conditional.Dependencies; -- Return dependencies of linked crates in the solution function Misses (This : Solution) return Dependency_Map; -- Return crates for which there is neither hint nor proper versions function Pins (This : Solution) return Conditional.Dependencies; -- Return all version-pinned dependencies as a dependency tree containing -- exact versions. NOTE that the original dependency is thus lost in this -- info. function Pins (This : Solution) return Dependency_Map; -- return all version-pinned dependencies as plain dependencies for a exact -- version. NOTE that the original dependency is thus lost. function User_Pins (This : Solution) return Conditional.Dependencies; -- Return all version- or link-pinned dependencies; equivalent to Pins and -- Links. NOTE that the original dependency is lost for the case of version -- pins, as only the pinned version is returned. function Releases (This : Solution) return Release_Map; -- Returns the proper releases in the solution (regular and detected -- externals). This also includes releases found at a linked folder. function Required (This : Solution) return State_Map renames All_Dependencies; -- Returns all dependencies required to fulfill this solution, -- independently of their solving state. function State (This : Solution; Crate : Crate_Name) return Dependency_State with Pre => This.Depends_On (Crate), Post => State'Result.Crate = Crate or else (State'Result.Has_Release and then State'Result.Release.Provides (Crate)); -- Returns the solving state of a dependency in the solution function State (This : Solution; Release : Alire.Releases.Release) return Dependency_State with Pre => This.Depends_On (Release); -- Returns the state of the dependency this release might fulfill, relying -- only on the release name or its provides names. -------------- -- Mutation -- -------------- procedure Set (This : in out Solution; Crate : Crate_Name; Transitivity : States.Transitivities) with Pre => This.Depends_On (Crate); --------- -- I/O -- --------- procedure Print (This : Solution; Root : Alire.Releases.Release; Env : Properties.Vector; Detailed : Boolean; Level : Trace.Levels); -- Prints releases, and direct and transitive dependencies. Root is the -- crate not in solution that introduces the direct dependencies. When -- Detailed, extra information about origins is shown. procedure Print_Graph (This : Solution; Root : Alire.Releases.Release; Env : Properties.Vector); -- Print an ASCII graph of dependencies using libgraph-easy-perl, if -- installed, or default to Print_Tree. procedure Print_Hints (This : Solution; Env : Properties.Vector); -- Display hints about any undetected externals in the solutions procedure Print_Pins (This : Solution); -- Dump a table with pins in this solution procedure Print_States (This : Solution; Indent : String := " "; Level : Trace.Levels := Trace.Info); -- List all dependencies in the solution with their current state procedure Print_Tree (This : Solution; Root : Alire.Releases.Release; Prefix : String := ""; Print_Root : Boolean := True); -- Print the solution in tree form. If Print_Root, Root is printed too; -- otherwise the tree is a forest starting at Root direct dependencies. procedure Print_Versions (This : Solution; Root : Roots.Root); -- Print a table with the dependencies in the solutions, showing the wanted -- dependencies, the solved version, and the latest existing version for a -- crate. ----------------- -- Persistence -- ----------------- function From_TOML (From : TOML_Adapters.Key_Queue) return Solution; overriding function To_TOML (This : Solution) return TOML.TOML_Value with Pre => (for all Release of This.Releases => This.State (Release).Is_Linked or else (Release.Dependencies.Is_Unconditional and then Release.Properties.Is_Unconditional)); -- Requires releases not to have dynamic expressions. This is currently -- guaranteed by the states storing static versions of releases. We do not -- store linked releases, so in that case it does not matter. --------------- -- Utilities -- --------------- function Narrow_New_Dependencies (Old_Deps, New_Deps : Conditional.Dependencies; New_Sol : Solution) return Conditional.Dependencies; -- Take new dependencies in a tree, see how they've been solved, and -- replace "any" dependencies with the proper tilde or caret, depending on -- what was found in the solution. E.g., if the user provided lib=*, and it -- is solved as lib=2.0, replace lib=* with lib^2.0 in the result. procedure Traverse (This : Solution; Doing : access procedure (This : Solution; State : Dependency_State); Root : Alire.Releases.Containers.Optional := Alire.Releases.Containers.Optional_Releases.Empty); -- Visit every dependency in the solution, starting at leaves up to -- the optional root release, calling Doing for each one. This allows -- a safe-order traversal of a solution. This procedure is currently -- sequential but it could be parallelized in the future. private type Solution is new Interfaces.Tomifiable with record Dependencies : State_Map; Solved : Boolean := False; -- Has solving been attempted? end record; -- Implementations moved to body due to bug about missing symbols in -- predicates otherwise. end Alire.Solutions; alire-1.2.1/src/alire/alire-solver.adb000066400000000000000000001346141430264165500175650ustar00rootroot00000000000000with Ada.Containers; use Ada.Containers; with Ada.Containers.Indefinite_Ordered_Sets; with Alire.Conditional; with Alire.Containers; with Alire.Dependencies.States; with Alire.Errors; with Alire.Milestones; with Alire.Optional; with Alire.Releases.Containers; with Alire.Shared; with Alire.Root; with Alire.Toolchains; with Alire.Utils.TTY; with CLIC.User_Input; with Stopwatch; package body Alire.Solver is Solution_Found : exception; -- Used to prematurely end search when a complete solution exists Solution_Timeout : exception; -- Used on search timeout; solution might not even exist or be incomplete package Semver renames Semantic_Versioning; use all type Dependencies.States.Fulfillments; use all type Dependencies.States.Transitivities; package Solution_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Element_Type => Solution, "<" => Solutions.Is_Better, "=" => Solutions."="); ----------- -- Image -- ----------- function Image (Options : Query_Options) return String is ("Age order: " & TTY.Emph (Options.Age'Image) & "; Completeness: " & TTY.Emph (Options.Completeness'Image) & "; Externals: " & TTY.Emph (Options.Detecting'Image) & "; Hinting: " & TTY.Emph (Options.Hinting'Image)); ------------ -- Exists -- ------------ function Exists (Name : Alire.Crate_Name; Allowed : Semantic_Versioning.Extended.Version_Set := Semantic_Versioning.Extended.Any) return Boolean is (not Index.Releases_Satisfying (Dependencies.New_Dependency (Name, Allowed), Root.Platform_Properties).Is_Empty); ---------- -- Find -- ---------- function Find (Name : Alire.Crate_Name; Allowed : Semantic_Versioning.Extended.Version_Set := Semantic_Versioning.Extended.Any; Policy : Age_Policies; Origins : Alire.Origins.Kinds_Set := (others => True)) return Release is Candidates : constant Releases.Containers.Release_Set := Index.Releases_Satisfying (Dependencies.New_Dependency (Name, Allowed), Root.Platform_Properties, With_Origin => Origins); begin if not Candidates.Is_Empty then if Policy = Newest then return Candidates.Last_Element; else return Candidates.First_Element; end if; end if; raise Query_Unsuccessful with "Release within requested version not found: " & Dependencies.New_Dependency (Name, Allowed).Image; end Find; ------------------- -- Is_Resolvable -- ------------------- function Is_Resolvable (Deps : Types.Abstract_Dependencies; Props : Properties.Vector; Pins : Solution; Options : Query_Options := Default_Options) return Boolean is (Resolve (Deps, Props, Pins, Options).Is_Complete); ------------- -- Resolve -- ------------- function Resolve (Deps : Alire.Types.Abstract_Dependencies; Props : Properties.Vector; Pins : Solution; Options : Query_Options := Default_Options) return Solution is Progress : Trace.Ongoing := Trace.Activity ("Solving dependencies"); Timer : Stopwatch.Instance; Timeout : Duration := Options.Timeout; use Alire.Conditional.For_Dependencies; Unavailable_Crates : Containers.Crate_Name_Sets.Set; Unavailable_Direct_Deps : AAA.Strings.Sets.Set; -- Some dependencies may be unavailable because the crate does not -- exist, the requested releases do not exist, or the intersection of -- versions is empty. In this case, we can prematurely end the search -- instead of keeping looking for a valid combination, as these -- dependencies will never be satisfied. NOTE that these unavailable -- impossibilities must be top-level DIRECT dependencies (i.e., -- introduced by the user), or otherwise it does make sense to explore -- alternate solutions that may not require the impossible dependencies. Unavailable_All_Deps : AAA.Strings.Sets.Set; -- Still, we can keep track of indirect unsolvable deps to speed-up the -- search by not reattempting branches that contain such a dependency. -- On the solver internal operation: the solver recursively tries all -- possible dependency combinations, in depth-first order. This means -- that, for a given dependency, all satisfying releases are attempted -- in different exploration branches. Once a search branch exhausts -- all dependencies, successfully solved or not, it is added to the -- following global pool of solutions. The search status in each branch -- is stored in a number of trees that are the arguments of the Expand -- internal procedure, and in a Solution that is being incrementally -- built. Solutions : Solution_Sets.Set; -- We store here all solutions found. The solver is currently exhaustive -- in that it will not stop after the first solution, but will keep -- going until all possibilities are exhausted. If, at some point, -- resolution starts to take too much time, it may be useful to be able -- to select the solver behavior (e.g. stop after the first complete -- solution is found). Installed : constant Releases.Containers.Release_Set := Shared.Available; -- Installed releases do not change during resolution, we make a local -- copy here so they are not read repeatedly from disk. Dupes : Natural := 0; -- Some solutions are found twice when some dependencies are subsets of -- other dependencies. -------------------------- -- Ask_User_To_Continue -- -------------------------- procedure Ask_User_To_Continue is use CLIC.User_Input; Answer : Answer_Kind := No; begin Timer.Hold; if Not_Interactive or else not Options.Interactive then Trace.Debug ("Forcing stop of solution search after " & Timer.Image & " seconds"); raise Solution_Timeout; end if; if Solutions.Is_Empty then Put_Warning ("No solution found after " & Stopwatch.Image (Timeout, Decimals => 0) & " seconds."); else if not Solutions.First_Element.Is_Complete then Put_Warning ("Complete solution not found after " & Stopwatch.Image (Timeout, Decimals => 0) & " seconds."); Put_Info ("The best incomplete solution yet is:"); else Put_Warning ("Solution space not fully explored after " & Stopwatch.Image (Timeout, Decimals => 0) & " seconds."); Put_Info ("The best complete solution yet is:"); end if; Trace.Info (""); Solutions.First_Element.Print_States (Level => Trace.Info); Trace.Info (""); end if; if Answer /= Always then Answer := Query (Question => "Do you want to keep solving for a few more seconds?", Valid => (others => True), Default => (if Not_Interactive then No else Yes)); end if; if Answer /= No then Timeout := Timeout + Options.Timeout_More; Timer.Release; else Trace.Debug ("User forced stop of solution search after " & Timer.Image & " seconds"); raise Solution_Timeout; end if; end Ask_User_To_Continue; -------------- -- Complete -- -------------- function Complete return Natural is begin return Count : Natural := 0 do for Sol of Solutions loop if Sol.Is_Complete then Count := Count + 1; end if; end loop; end return; end Complete; ------------- -- Partial -- ------------- function Partial return Natural is (Natural (Solutions.Length) - Complete); ------------ -- Expand -- ------------ procedure Expand (Expanded, -- Nodes already processed Target, -- Next subtree to consider Remaining : Types.Platform_Dependencies; -- Nodes pending to be considered Solution : Alire.Solutions.Solution -- Partial or complete solution that stores releases -- and dependencies processed up to now ) is ------------------ -- Expand_Value -- ------------------ procedure Expand_Value (Dep : Dependencies.Dependency; Allow_Shared : Boolean) is -- Ensure the dependency exists in the solution, so the following -- procedures can safely count on it being there: Solution : constant Alire.Solutions.Solution := Expand.Solution.Depending_On (Dep); -- Note that, since this merge may render the release for the old -- dependency invalid, it should be checked again (which Check -- below does.) -------------------- -- Check_Compiler -- -------------------- function Check_Compiler (R : Release) return Boolean is ------------------- -- Specific_GNAT -- ------------------- -- Examine pending dependencies for a specific GNAT, and if so -- return the one. function Specific_GNAT (Deps : Conditional.Dependencies) return Conditional.Dependencies is begin if Deps.Is_Iterable then for Dep of Deps loop if AAA.Strings.Has_Prefix (Dep.Value.Crate.As_String, "gnat_") -- Ugly hack then return Dep; end if; end loop; end if; return Conditional.No_Dependencies; end Specific_GNAT; Result : Boolean := False; begin -- The following checks are not guaranteed to find the proper -- GNAT to use, as a yet-unknown dependency might add a precise -- GNAT later on. It should however cover the common case -- in which the GNAT dependencies are in the root crate. If -- all else fails, in the end there is a real problem of the -- user having selected an incompatible compiler, so the last -- recourse is for the user to unselect the compiler in this -- configuration local config, for example. if Solution.Depends_On_Specific_GNAT then -- There is already a precise gnat_xxx in the solution, that -- we can reuse. Result := (for some Prev of Solution.Releases_Providing (GNAT_Crate) => Prev.Name = R.Name); Trace.Debug ("SOLVER: gnat PASS " & Result'Image & " for " & R.Milestone.TTY_Image & " due to compiler already in solution: " & Solution.Releases.Elements_Providing (GNAT_Crate).Image_One_Line); return Result; elsif not Specific_GNAT (Remaining).Is_Empty then -- There is an unsolved dependency on a specific gnat, that -- we must honor sooner or later, so no point on trying -- another target. Trace.Debug ("SOLVER: gnat PASS " & Boolean' (Specific_GNAT (Remaining).Value.Crate = R.Name)'Img & " for " & R.Milestone.TTY_Image & " due to compiler already in dependencies: " & Specific_GNAT (Remaining).Value.TTY_Image); return Specific_GNAT (Remaining).Value.Crate = R.Name; elsif Toolchains.Tool_Is_Configured (GNAT_Crate) then -- There is a preferred compiler that we must use, as there -- is no overriding reason not to Trace.Debug ("SOLVER: gnat PASS " & Boolean' (Toolchains .Tool_Dependency (GNAT_Crate).Crate = R.Name)'Img & " for " & R.Milestone.TTY_Image & " due to configured compiler: " & Toolchains.Tool_Dependency (GNAT_Crate).TTY_Image); return Toolchains .Tool_Dependency (GNAT_Crate).Crate = R.Name; elsif Dep.Crate = GNAT_Crate then -- For generic dependencies on gnat, we do not want to use -- a compiler that is not already installed. Trace.Debug ("SOLVER: gnat PASS " & Boolean' (Installed.Contains (R))'Image & " for " & R.Milestone.TTY_Image & " due to installed compiler availability."); return Installed.Contains (R); else Trace.Debug ("SOLVER: gnat compiler " & R.Milestone.TTY_Image & " is valid candidate."); return True; end if; end Check_Compiler; ----------- -- Check -- ----------- procedure Check (R : Release; Is_Shared : Boolean; Is_Reused : Boolean) is use all type Origins.Kinds; begin -- Special compiler checks are hardcoded when the dependency is -- on a generic GNAT. This way we ensure the preferred compiler -- is used, unless we are forced by other dependencies to do -- something else if Dep.Crate = GNAT_Crate and then R.Provides (GNAT_Crate) and then not Check_Compiler (R) then -- Reason already logged by Check_Compiler return; end if; -- If the candidate release is forbidden by a previously -- resolved dependency, the candidate release is -- incompatible and we may stop search along this branch. if Solution.Forbids (R, Props) then Trace.Debug ("SOLVER: discarding tree because of" & " FORBIDDEN release: " & R.Milestone.Image & " forbidden by current solution when tree is " & Tree'(Expanded and Target and Remaining).Image_One_Line); -- After all these checks, the candidate release must belong to -- a crate that is still unfrozen, so it is a valid new crate -- and release to consider. First, check version compliance: elsif not R.Satisfies (Dep) then Trace.Debug ("SOLVER: discarding search branch because " & R.Milestone.Image & " FAILS to fulfill dependency " & Dep.TTY_Image & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); -- Even if the release is OK for the dependency, the -- aggregated dependencies for the crate in the solution -- can be another matter, so we recheck again. elsif not R.Satisfies (Solution.Dependency (Dep.Crate)) then Trace.Debug ("SOLVER: discarding search branch because " & R.Milestone.Image & " FAILS to fulfill dep-in-solution " & Solution.Dependency (Dep.Crate).TTY_Image & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); -- Or it may be that, even being a valid version, it's not for -- this environment. elsif not R.Is_Available (Props) then Trace.Debug ("SOLVER: discarding search branch because " & R.Milestone.Image & " is UNAVAILABLE" & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); -- If we reached here, the release fulfills the dependency, so -- we add it to the solution. It might still be a release that -- fulfilled a previous dependency, so we take care of that -- when adding its dependencies. else declare -- We only need to add dependencies if it is the first -- time we see this release. New_Deps : constant Conditional.Platform_Dependencies := (if Is_Reused then Conditional.No_Dependencies else R.Dependencies (Props)); begin Trace.Debug ("SOLVER: dependency FROZEN: " & R.Milestone.Image & " to satisfy " & Dep.TTY_Image & (if Is_Reused then " with REUSED" else "") & (if Is_Shared then " with INSTALLED" else "") & (if not R.Provides.Is_Empty then " also providing " & R.Provides.Image_One_Line else "") & " adding" & New_Deps.Leaf_Count'Img & " dependencies to tree " & Tree'(Expanded and Target and Remaining and New_Deps).Image_One_Line); Expand (Expanded => Expanded and R.To_Dependency, Target => Remaining, Remaining => New_Deps, Solution => Solution.Including (R, Props, For_Dependency => Optional.Crate_Names.Unit (Dep.Crate), Shared => Is_Shared or else R.Origin.Kind = Binary_Archive)); end; end if; end Check; -------------------- -- Expand_Missing -- -------------------- -- Mark a crate as missing and continue exploring, depending on -- configuration policies, or abandon this search branch. procedure Expand_Missing (Dep : Alire.Dependencies.Dependency) is begin if Options.Completeness > All_Complete or else Unavailable_Crates.Contains (Dep.Crate) or else Unavailable_Direct_Deps.Contains (Dep.Image) then Trace.Debug ("SOLVER: marking MISSING the crate " & Dep.Image & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); Expand (Expanded => Expanded, Target => Remaining, Remaining => Empty, Solution => Solution.Missing (Dep)); else Trace.Debug ("SOLVER: discarding solution MISSING crate " & Dep.Image & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); end if; end Expand_Missing; ------------------ -- Check_Hinted -- ------------------ procedure Check_Hinted is begin if Index.Has_Externals (Dep.Crate) then if Options.Hinting = Hint then Trace.Debug ("SOLVER: dependency HINTED: " & (+Dep.Crate) & " via EXTERNAL to satisfy " & Dep.Image & " without adding dependencies to tree " & Tree'(Expanded and Target and Remaining).Image_One_Line); Expand (Expanded => Expanded, Target => Remaining, Remaining => Empty, Solution => Solution.Hinting (Dep)); else Trace.Debug ("SOLVER: dependency not hinted: " & (+Dep.Crate) & " as HINTING is DISABLED, for dep " & Dep.Image & " having externals, when tree is " & Tree'(Expanded and Target and Remaining).Image_One_Line); end if; else Trace.Debug ("SOLVER: dependency not hinted: " & (+Dep.Crate) & " for dep " & Dep.Image & " LACKING externals, when tree is " & Tree'(Expanded and Target and Remaining).Image_One_Line); end if; end Check_Hinted; ----------------------- -- Check_Version_Pin -- ----------------------- -- Specific checks for a version pin that narrow down the search procedure Check_Version_Pin is Pin_Version : constant Semver.Version := Pins.State (Dep.Crate).Pin_Version; begin -- For a version pin release, we try only a release with the -- exact version of the pin, to speed up the solving. If the -- pin version is incompatible with the dependency, this branch -- cannot succeed though. if Semver.Extended.Is_In (Pin_Version, Dep.Versions) then -- The pin is compatible with the dependency, go ahead for Release of Index.Releases_Satisfying (Dependencies.New_Dependency (Dep.Crate, Pin_Version), Props) loop -- There is a valid crate for this pin and dependency Trace.Debug ("SOLVER short-cutting due to version pin" & " with valid release in index"); Check (Release, Is_Shared => False, Is_Reused => False); end loop; -- There may be no satisfying releases, or even so the -- check may still fail, so we must attempt this one too: Trace.Debug ("SOLVER: marking crate " & Dep.Image & " MISSING in case pinned version " & TTY.Version (Pin_Version.Image) & " is incompatible with other dependencies" & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); Expand_Missing (Dep); else -- The pin contradicts the dependency Trace.Debug ("SOLVER: marking crate " & Dep.Image & " MISSING because version pin " & TTY.Version (Pin_Version.Image) & " cannot satisfy " & Dep.TTY_Image & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); Expand_Missing (Dep); end if; end Check_Version_Pin; Satisfiable : Boolean := False; -- Mark that the dependency is satisfiable. When we refactor the -- solver from recursive to priority queue (I guess we eventually -- will have to), we should do this globally since this is -- information common to all search states. ------------------ -- Check_Shared -- ------------------ procedure Check_Shared is begin -- Solve with all installed dependencies that satisfy it for R of reverse Installed.Satisfying (Dep) loop Satisfiable := True; Check (R, Is_Shared => True, Is_Reused => False); end loop; -- We may want still check without taking into account -- installed releases. if Installed.Satisfying (Dep).Is_Empty or else Options.Completeness >= Some_Incomplete then Expand_Value (Dep => Dep, Allow_Shared => False); end if; end Check_Shared; use type Alire.Dependencies.Dependency; begin if Timer.Elapsed > Timeout then Ask_User_To_Continue; end if; if Pins.Depends_On (Dep.Crate) and then Pins.State (Dep.Crate).Is_Linked then -- The dependency is softlinked in the starting solution, hence -- we need not look further for releases. Trace.Debug ("SOLVER: dependency LINKED to " & Pins.State (Dep.Crate).Link.Path & " when tree is " & Tree'(Expanded and Target and Remaining).Image_One_Line); Expand (Expanded => Expanded and Dep, Target => Remaining and (if Pins.State (Dep.Crate).Has_Release then Pins.State (Dep.Crate) .Release.Dependencies (Props) else Empty), Remaining => Empty, Solution => Solution.Linking (Dep.Crate, Pins.State (Dep.Crate).Link)); return; end if; if not Solution.Dependencies_Providing (Dep.Crate).Is_Empty then -- Cut search once a crate is frozen, by checking the -- compatibility of the already frozen release. This will -- result in the same release being used to satisfy the new -- Dep, if possible, or discarding the search branch early. Trace.Debug ("SOLVER: re-checking EXISTING releases " & Solution.Releases_Providing (Dep.Crate).Image_One_Line & " for DIFFERENT dep " & Dep.TTY_Image); for In_Sol of Solution.Dependencies_Providing (Dep.Crate) loop if In_Sol.Has_Release then Check (In_Sol.Release, Is_Shared => In_Sol.Is_Shared, Is_Reused => True); end if; end loop; return; end if; if Allow_Shared then -- There is a shared release we can use for this dependency; we -- prefer this option first. If more solutions than the first -- complete one are sought, we can still try without the shared -- release. Check_Shared; end if; if Pins.Depends_On (Dep.Crate) and then Pins.State (Dep.Crate).Is_Pinned then -- Specific pin checks that can speed up the search Check_Version_Pin; elsif Index.Exists (Dep.Crate) or else Index.Has_Externals (Dep.Crate) or else not Index.Releases_Satisfying (Dep, Props).Is_Empty -- TODO: Worth caching? then -- Detect externals for this dependency now, so they are -- available as regular releases. Note that if no release -- fulfills the dependency, it will be resolved as a hint -- below. if Options.Detecting = Detect then Timer.Hold; Index.Detect_Externals (Dep.Crate, Props); Timer.Release; end if; -- Check the releases now, from newer to older (unless required -- in reverse). We keep track that none is valid, as this is -- a special case in which we're being asked an impossible -- thing from the start, which we can use to enable a partial -- solution without exploring the whole solution space: if not Unavailable_Direct_Deps.Contains (Dep.Image) and then not Unavailable_All_Deps.Contains (Dep.Image) then -- Don't bother checking what we known to not be available. -- We still want to go through to external hinting. declare Candidates : constant Releases.Containers.Release_Set := Index.Releases_Satisfying (Dep, Props); procedure Consider (R : Release) is begin -- A GNAT release may still satisfy the dependency -- but be not a valid candidate if uninstalled and -- the dependency is on generic GNAT, so explicitly -- consider this case: Satisfiable := Satisfiable or else (R.Satisfies (Dep) and then (Dep.Crate /= GNAT_Crate or else Installed.Contains (R))); Check (R, Is_Shared => False, Is_Reused => False); end Consider; begin Trace.Debug ("SOLVER: considering" & Candidates.Length'Image & " candidates to " & Dep.TTY_Image & ": " & Candidates.Image_One_Line); if Options.Age = Newest then for R of reverse Candidates loop Consider (R); end loop; else for R of Candidates loop Consider (R); end loop; end if; end; end if; -- Beside normal releases, an external may exist for the -- crate, in which case we hint the crate instead of failing -- resolution (if the external failed to find its releases). Check_Hinted; -- If the dependency cannot be satisfied, add it to our damned -- list for speed-up. if not Satisfiable and then not Unavailable_All_Deps.Contains (Dep.Image) then Trace.Debug ("SOLVER: marking as unsatisfiable: " & Dep.TTY_Image); Unavailable_All_Deps.Include (Dep.Image); end if; -- There may be a less bad solution if we leave this crate out. if not Satisfiable or else Options.Completeness = All_Incomplete then Trace.Debug ("SOLVER: marking crate " & Dep.Image & " MISSING with Satisfiable=" & Satisfiable'Image & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); Expand_Missing (Dep); end if; else -- The crate plainly doesn't exist in our loaded catalog, so -- mark it as missing an move on: Trace.Debug ("SOLVER: catalog LACKS the crate " & Dep.Image & " when the search tree was " & Tree'(Expanded and Target and Remaining).Image_One_Line); Expand_Missing (Dep); end if; end Expand_Value; ----------------------- -- Expand_And_Vector -- ----------------------- procedure Expand_And_Vector is begin Expand (Expanded => Expanded, Target => Target.First_Child, Remaining => Target.All_But_First_Children and Remaining, Solution => Solution); end Expand_And_Vector; ---------------------- -- Expand_Or_Vector -- ---------------------- procedure Expand_Or_Vector is begin for I in Target.Iterate loop Expand (Expanded => Expanded, Target => Target (I), Remaining => Remaining, Solution => Solution); end loop; end Expand_Or_Vector; -------------------- -- Store_Finished -- -------------------- procedure Store_Finished (Solution : Alire.Solutions.Solution) is ------------------------------ -- Contains_All_Satisfiable -- ------------------------------ -- A solution may be incomplete but also may be only missing -- impossible dependencies. In that case we can finish already, as -- if the solution were complete. Otherwise, an e.g. missing crate -- may force exploring all the combos of the rest of crates just -- because it doesn't exist. function Contains_All_Satisfiable return Boolean is begin for Crate of Solution.Crates loop if Solution.State (Crate).Fulfilment in Missed | Hinted -- So the dependency is not solved, but why? and then not Unavailable_Crates.Contains (Crate) -- Because it does not exist at all, so "complete" and then not Unavailable_Direct_Deps.Contains (Solution.Dependency (Crate).Image) -- Because no release fulfills it, so "complete" then return False; end if; end loop; return True; end Contains_All_Satisfiable; Pre_Length : constant Count_Type := Solutions.Length; use AAA.Strings; begin Trace.Debug ("SOLVER: tree FULLY expanded as: " & Expanded.Image_One_Line & " complete: " & Solution.Is_Complete'Img & "; composition: " & Solution.Composition'Img); Solutions.Include (Solution); if Pre_Length = Solutions.Length then Dupes := Dupes + 1; end if; Progress.Step ("Solving dependencies... " & Trim (Complete'Img) & "/" & Trim (Partial'Img) & "/" & Trim (Dupes'Image) & " (complete/partial/dupes)"); if Options.Completeness = First_Complete and then Contains_All_Satisfiable then raise Solution_Found; -- break recursive search end if; end Store_Finished; begin Trace.Debug ("SOLVER: EXPAND"); Trace.Debug ("Frozen: " & Expanded.Image_One_Line); Trace.Debug ("Target: " & Target.Image_One_Line); Trace.Debug ("Remain: " & Remaining.Image_One_Line); if Target.Is_Empty then -- This is a completed search branch, be the solution complete or -- not. if Remaining.Is_Empty then Store_Finished (Solution); return; else -- Take the remaining tree and make it the current target for -- solving, since we already exhausted the previous target. Expand (Expanded => Expanded, Target => Remaining, Remaining => Empty, Solution => Solution); return; end if; end if; if Target.Is_Value then -- We are tackling a new dependency that may have been seen -- previously. For that reason we need to: 1) Recheck releases in -- the solution against this new dependency 2) Be sure to consider -- the merged dependencies for this crate when looking for new -- releases. 1) is done inside Expand_Value (the first check) -- 2 is done here: first add/merge new dep, then use it for expand Expand_Value (Solution.Depending_On (Target.Value) -- add or merge dependency .Dependency (Target.Value.Crate), -- and use it in expansion Allow_Shared => Options.Sharing = Allow_Shared); elsif Target.Is_Vector then if Target.Conjunction = Anded then Expand_And_Vector; else Expand_Or_Vector; end if; else raise Program_Error with "Dynamic dependency trees cannot be resolved"; end if; end Expand; -------------------------------------------- -- Detect_Unavailable_Direct_Dependencies -- -------------------------------------------- -- Direct (i.e., top-level) dependencies that are unsolvable do not -- count towards marking a solution as incomplete (i.e., to force -- keeping looking). These can be detected from the start, and -- the solver will not try to find more solutions for one of -- these impossible requests. procedure Detect_Unavailable_Direct_Dependencies (Direct : Conditional.Dependencies) is begin if not Direct.Contains_ORs then for Dep of Direct loop -- Pre-populate external releases if Options.Detecting = Detect then Index.Detect_Externals (Dep.Value.Crate, Props); end if; -- Regular unavailable releases if Index.Releases_Satisfying (Dep.Value, Props).Is_Empty then Unavailable_Direct_Deps.Include (Dep.Value.Image); Trace.Debug ("Direct dependency has no fulfilling releases: " & Utils.TTY.Name (Dep.Value.Image)); end if; end loop; else Trace.Debug ("Alternate dependencies in tree, " & "speed optimizations disabled."); end if; end Detect_Unavailable_Direct_Dependencies; ---------------- -- Trace_Pins -- ---------------- procedure Trace_Pins is begin if (for some State of Pins.All_Dependencies => State.Is_User_Pinned) then Trace.Detail ("User pins to apply:"); for State of Pins.All_Dependencies loop if State.Is_User_Pinned then Trace.Detail (" " & State.TTY_Image); end if; end loop; else Trace.Detail ("No user pins to apply"); end if; end Trace_Pins; Full_Dependencies : constant Conditional.Dependencies := Tree'(Pins.User_Pins and Deps).Evaluate (Props); -- Include pins before other dependencies. This makes their dependency -- show in solutions explicitly. Solution : constant Alire.Solutions.Solution := Alire.Solutions.Empty_Valid_Solution; -- Valid solution in the sense that solving has been attempted begin Trace.Detail ("Solving dependencies with options: " & Image (Options)); Trace.Detail ("Root dependency tree is: " & Full_Dependencies.Image_One_Line); Trace_Pins; -- Warn if we foresee things taking a loong time... if Options.Completeness = All_Incomplete then Trace.Warning ("Exploring all possible solutions to dependencies," & " this may take some time..."); end if; -- Get the trivial case out of the way if Full_Dependencies.Is_Empty then Trace.Debug ("Returning trivial solution for empty dependencies"); return Solution; end if; -- Preprocess direct dependencies to identify any impossible ones. If -- the tree contains alternate dependencies this is not doable. Detect_Unavailable_Direct_Dependencies (Full_Dependencies); -- Otherwise expand the full dependencies begin Expand (Expanded => Empty, Target => Full_Dependencies, Remaining => Empty, Solution => Solution); exception when Solution_Timeout => Trace.Debug ("Solution search ended forcibly before completion"); when Solution_Found => Trace.Debug ("Solution search ended with first complete solution"); end; -- Once Expand returns, the recursive exploration has ended. Depending -- on options, there must exist at least one incomplete solution, or we -- can retry with a larger solution space. if Solutions.Is_Empty then if Options.Completeness < All_Incomplete then Trace.Detail ("No solution found with completeness policy of " & Options.Completeness'Image & "; attempting to find more incomplete solutions..."); -- Reattempt so we can return an incomplete solution return Resolve (Deps => Deps, Props => Props, Pins => Pins, Options => (Query_Options' (Age => Options.Age, Completeness => (case Options.Completeness is when First_Complete | All_Complete => Some_Incomplete, when Some_Incomplete => All_Incomplete, when All_Incomplete => raise Program_Error with "Unreachable code"), Detecting => Options.Detecting, Hinting => Options.Hinting, Sharing => Options.Sharing, Timeout => Options.Timeout, Timeout_More => Options.Timeout_More, Interactive => Options.Interactive))); else raise Query_Unsuccessful with Errors.Set ("Solver failed to find any solution to fulfill dependencies."); end if; else -- Mark direct/indirect dependencies post-hoc declare Best_Solution : Alire.Solutions.Solution := Solutions.First_Element.With_Pins (Pins); begin -- Mark pins as direct dependencies for Dep of Best_Solution.Required loop if Dep.Is_User_Pinned then Best_Solution.Set (Dep.Crate, Direct); end if; end loop; -- Mark direct dependencies for Dep of Conditional.Enumerate (Deps) loop if Best_Solution.Depends_On (Dep.Crate) then Best_Solution.Set (Dep.Crate, Direct); end if; end loop; -- Mark all not direct as indirect for Crate of Best_Solution.Crates loop if not Best_Solution.State (Crate).Is_Direct then Best_Solution.Set (Crate, Indirect); end if; end loop; Trace.Detail ("Dependencies solvable in" & TTY.Emph (Solutions.Length'Img) & " ways" & " (complete:" & TTY.OK (Complete'Img) & "; partial:" & TTY.Warn (Partial'Img) & "; dupes:" & TTY.Bold (Dupes'Img) & ")"); Trace.Detail ("Dependencies solved with" & TTY.Emph (Best_Solution.Releases.Length'Img) & " releases" & (if not Best_Solution.Hints.Is_Empty then " and" & TTY.Warn (Best_Solution.Hints.Length'Img) & " external hints" else "") & (if not Best_Solution.Misses.Is_Empty then " and" & TTY.Error (Best_Solution.Misses.Length'Img) & " missing dependencies" else "") ); return Best_Solution; end; end if; end Resolve; end Alire.Solver; alire-1.2.1/src/alire/alire-solver.ads000066400000000000000000000153101430264165500175750ustar00rootroot00000000000000with Alire.Dependencies; with Alire.Index; with Alire.Origins; with Alire.Properties; with Alire.Solutions; with Alire.Types; with Alire.User_Pins.Maps; with Semantic_Versioning.Extended; package Alire.Solver is -------------- -- Policies -- -------------- type Age_Policies is (Oldest, Newest); -- When looking for releases within a crate, which one to try first. type Completeness_Policies is (First_Complete, -- Stop after finding the first complete solution. No incomplete -- solutions will be attempted. Other complete solutions may exist -- that are globally "newer". All_Complete, -- Only attempt to find complete solutions; the first unsatisfiable -- dependency will result in abandoning that search branch. All -- complete solutions will be found, and the best one according -- to Solutions.Is_Better will be returned. Some_Incomplete, -- Explores a reasonable subset of incomplete solutions: unknown crates, -- crates with no satisfying releases, crates with externals can appear -- as missing in the solution. All_Incomplete -- All crates may appear as missing, even those that have satisfying -- releases. All possible solutions and incomplete subsets are -- eventually explored. ); -- Allow the solver to further explore incomplete solution space. Each -- value takes more time than the precedent one. All_Incomplete can take -- a veeery long time when many crates/releases must be considered. type Detection_Policies is (Detect, Dont_Detect); -- * Detect: externals will be detected and added to the index once needed. -- * Dont_Detect: externals will remain undetected (faster). type Hinting_Policies is (Hint, Fail); -- * Hint: any crate with externals, detected or not, will as last resort -- provide a hint. -- * Fail: fail for any unsatisfiable crate. If Detect, externally detected -- releases will be used normally; otherwise a crate with only externals -- will always cause failure. type Sharing_Policies is (Allow_Shared, Only_Local); -- * Allow_Shared: crates in the shared config can appear in solutions. -- * Only_Local: only crates in the local workspace will be used. subtype Pin_Map is User_Pins.Maps.Map; subtype Release is Types.Release; subtype Solution is Solutions.Solution; -- The dependency solver (Resolve subprogram, below) receives a -- dependency tree and will return the best solution found (exploration -- is exhaustive), according to Solutions.Is_Better ordering. System -- dependencies are resolved in platforms with system packager support. -- Otherwise they're filed as "hints". In this case, a warning will -- be provided for the user with a list of the dependencies that are -- externally required. Note that a solution is always returned, but -- it might not be complete. --------------------- -- Basic queries -- -- Merely check the catalog function Exists (Name : Alire.Crate_Name; Version : Semantic_Versioning.Version) return Boolean renames Alire.Index.Exists; function Find (Name : Alire.Crate_Name; Version : Semantic_Versioning.Version) return Release renames Alire.Index.Find; function Exists (Name : Alire.Crate_Name; Allowed : Semantic_Versioning.Extended.Version_Set := Semantic_Versioning.Extended.Any) return Boolean; -- Say if some release in the index fulfills this dependency function Find (Name : Alire.Crate_Name; Allowed : Semantic_Versioning.Extended.Version_Set := Semantic_Versioning.Extended.Any; Policy : Age_Policies; Origins : Alire.Origins.Kinds_Set := (others => True)) return Release with Pre => Exists (Name, Allowed) or else raise Query_Unsuccessful with "Release within requested versions not found: " & Dependencies.New_Dependency (Name, Allowed).TTY_Image; ----------------------- -- Advanced queries -- -- They may need to travel the full catalog, with multiple individual -- availability checks. type Query_Options is record Age : Age_Policies := Newest; Completeness : Completeness_Policies := First_Complete; Detecting : Detection_Policies := Detect; Hinting : Hinting_Policies := Hint; Sharing : Sharing_Policies := Allow_Shared; Timeout : Duration := 5.0; -- Time until reporting problems finding a complete solution Timeout_More : Duration := 10.0; -- Extra period if the user wants to keep looking Interactive : Boolean := True; -- If not interactive, the first timeout will be applied without asking end record; Default_Options : constant Query_Options := (others => <>); -- A reasonable combo that will return the first complete solution found, -- or otherwise consider a subset of incomplete solutions. Default_Options_Not_Interactive : constant Query_Options := (Interactive => False, others => <>); Exhaustive_Options : constant Query_Options := (Completeness => All_Incomplete, others => <>); -- Explore the full solution space Find_Best_Options : constant Query_Options := (Completeness => All_Complete, others => <>); -- Find all complete solutions and return the "best" one (see -- Solutions.Is_Better). It does not yet make sense to use this setting -- because with the current Is_Better implementation, the first complete -- solution found is the one considered better anyway. function Resolve (Deps : Alire.Types.Abstract_Dependencies; Props : Properties.Vector; Pins : Solution; Options : Query_Options := Default_Options) return Solution; -- Exhaustively look for a solution to the given dependencies, under the -- given platform properties and lookup options. Pins can be supplied to -- override Deps. May raise No_Solution_Error when not using Exhaustive -- options. function Is_Resolvable (Deps : Types.Abstract_Dependencies; Props : Properties.Vector; Pins : Solution; Options : Query_Options := Default_Options) return Boolean; -- Simplified call to Resolve, discarding result end Alire.Solver; alire-1.2.1/src/alire/alire-spawn.adb000066400000000000000000000030531430264165500173730ustar00rootroot00000000000000with Alire_Early_Elaboration; with Alire.OS_Lib.Subprocess; package body Alire.Spawn is ------------- -- Command -- ------------- procedure Command (Cmd : String; Args : AAA.Strings.Vector; Understands_Verbose : Boolean := False) is Unused_Output : AAA.Strings.Vector; begin if Alire_Early_Elaboration.Switch_Q then Unused_Output := Alire.OS_Lib.Subprocess.Checked_Spawn_And_Capture (Cmd, Args, Understands_Verbose, Err_To_Out => True); else Alire.OS_Lib.Subprocess.Checked_Spawn (Cmd, Args, Understands_Verbose); end if; end Command; -------------- -- Gprbuild -- -------------- procedure Gprbuild (Project_File : String; Extra_Args : AAA.Strings.Vector) is use AAA.Strings; begin if Alire.OS_Lib.Subprocess.Locate_In_Path ("gprbuild") = "" then Alire.Raise_Checked_Error ("Cannot locate " & TTY.Emph ("gprbuild") & ", please check that " & "you have a GNAT and GPRbuild installation in your environment."); end if; Command ("gprbuild", Empty_Vector & "-s" & -- Recompile if compiler switches have changed "-j0" & -- Build in parallel "-p" & -- Create missing obj, lib and exec dirs "-P" & Project_File & Extra_Args, Understands_Verbose => True); end Gprbuild; end Alire.Spawn; alire-1.2.1/src/alire/alire-spawn.ads000066400000000000000000000013731430264165500174170ustar00rootroot00000000000000with AAA.Strings; package Alire.Spawn is -- Encapsulates all external spawns -- Any of those may raise Command_Failed or GNAT.OS_Lib exceptions procedure Command (Cmd : String; Args : AAA.Strings.Vector; Understands_Verbose : Boolean := False); -- Adds -v if understands in Debug log level -- Summary is shown after process successful end, if Log_Level = Info procedure Gprbuild (Project_File : String; Extra_Args : AAA.Strings.Vector); -- Launches gprbuild for the building of a crate. -- Extra args can be -Xblah detected from command-line. -- Out-of-tree build takes place in -- $crate / Alire.Paths.Build_Folder ($crate/alire/build). end Alire.Spawn; alire-1.2.1/src/alire/alire-toml_adapters.adb000066400000000000000000000266011430264165500211050ustar00rootroot00000000000000package body Alire.TOML_Adapters is -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Key_Queue) is pragma Unreferenced (This); begin -- Manually close this error scope Errors.Close; end Finalize; ------------ -- Assert -- ------------ procedure Assert (Queue : Key_Queue; Condition : Boolean; Message : String) is begin if not Condition then Queue.Checked_Error (Message); end if; end Assert; ---------------- -- Assert_Key -- ---------------- procedure Assert_Key (Queue : Key_Queue; Key : String; Kind : TOML.Any_Value_Kind) is begin if not Queue.Value.Has (Key) then Queue.Checked_Error ("missing required field: " & Key); elsif Queue.Value.Get (Key).Kind not in Kind then Queue.Checked_Error ("field " & Key & ": expected a " & Kind'Img & " but got a " & Queue.Value.Get (Key).Kind'Img); end if; end Assert_Key; ------------------- -- Checked_Error -- ------------------- procedure Checked_Error (Queue : Key_Queue; Message : String) is pragma Unreferenced (Queue); begin raise Alire.Checked_Error with Errors.Set (Message); end Checked_Error; ----------------------- -- Recoverable_Error -- ----------------------- procedure Recoverable_Error (Queue : Key_Queue; Message : String; Recover : Boolean := Alire.Force) is begin if Recover then Recoverable_Error (Message, Recover); else Queue.Checked_Error (Message); end if; end Recoverable_Error; ----------------- -- Checked_Pop -- ----------------- function Checked_Pop (Queue : Key_Queue; Key : String; Kind : TOML.Any_Value_Kind) return TOML.TOML_Value is begin Queue.Assert_Key (Key, Kind); return Value : TOML.TOML_Value do if not Queue.Pop (Key, Value) then raise Program_Error with ("missing key, but it was just checked?"); end if; end return; end Checked_Pop; ------------------ -- Create_Table -- ------------------ function Create_Table (Key : String; Value : TOML.TOML_Value) return TOML.TOML_Value is begin return Table : constant TOML.TOML_Value := TOML.Create_Table do Table.Set (Key, Value); end return; end Create_Table; ---------- -- From -- ---------- function From (Value : TOML.TOML_Value; Context : String) return Key_Queue is begin return This : constant Key_Queue := (Ada.Finalization.Limited_Controlled with Value => Value) do Errors.Open (Context); end return; end From; ---------- -- From -- ---------- function From (Key : String; Value : TOML.TOML_Value; Context : String) return Key_Queue is (From (Create_Table (Key, Value), Context)); ------------- -- Descend -- ------------- function Descend (Parent : Key_Queue; Value : TOML.TOML_Value; Context : String) return Key_Queue is (From (Value, Context)); ------------------ -- Merge_Tables -- ------------------ function Merge_Tables (L, R : TOML.TOML_Value) return TOML.TOML_Value is use TOML; function Merge_Internal (Key : Unbounded_UTF8_String; L, R : TOML_Value) return TOML_Value is pragma Unreferenced (Key); begin if L.Kind = TOML_Table and then R.Kind = L.Kind then return TOML.Merge (L, R, Merge_Internal'Access); else Raise_Checked_Error ("Ill-shaped TOML information cannot be merged"); end if; end Merge_Internal; begin return TOML.Merge (L, R, Merge_Entries => Merge_Internal'Access); end Merge_Tables; --------- -- Pop -- --------- function Pop (Queue : Key_Queue) return TOML.TOML_Value is Val : TOML.TOML_Value; Key : constant String := Queue.Pop (Val); begin if Key /= "" then return Val; else return TOML.No_TOML_Value; end if; end Pop; --------- -- Pop -- --------- function Pop (Queue : Key_Queue; Value : out TOML.TOML_Value) return String is begin -- Use first of remaining keys for Key of Queue.Value.Keys loop Value := Queue.Value.Get (Key); Queue.Value.Unset (Key); return +Key; end loop; -- If no keys left... return ""; end Pop; --------- -- Pop -- --------- function Pop (Queue : Key_Queue; Key : String; Value : out TOML.TOML_Value) return Boolean is use TOML; begin if Queue.Value /= No_TOML_Value and then Queue.Value.Kind = TOML_Table then Value := Queue.Value.Get_Or_Null (Key); if Value /= No_TOML_Value then Queue.Value.Unset (Key); end if; return Value /= TOML.No_TOML_Value; else return False; end if; end Pop; --------- -- Pop -- --------- function Pop (Queue : Key_Queue; Key : String) return TOML.TOML_Value is Val : TOML.TOML_Value; begin if not Queue.Pop (Key, Val) then Raise_Checked_Error ("Requested key not found: " & Key); end if; return Val; end Pop; -------------- -- Pop_Expr -- -------------- function Pop_Expr (Queue : Key_Queue; Prefix : String; Value : out TOML.TOML_Value) return String is begin Value := TOML.No_TOML_Value; if Queue.Value.Kind /= TOML.TOML_Table then return ""; end if; for Pair of Queue.Value.Iterate_On_Table loop if AAA.Strings.Has_Prefix (+Pair.Key, Prefix) then return Key : constant String := +Pair.Key do Value := Pair.Value; Queue.Value.Unset (Pair.Key); end return; end if; end loop; return ""; end Pop_Expr; ---------------------- -- Pop_Single_Table -- ---------------------- function Pop_Single_Table (Queue : Key_Queue; Value : out TOML.TOML_Value; Kind : TOML.Any_Value_Kind) return String is use TOML; begin if Queue.Value.Kind /= TOML_Table then Queue.Checked_Error ("expected a table but got a " & Queue.Value.Kind'Img); end if; if Queue.Value.Keys'Length /= 1 then Queue.Checked_Error ("expected a single entry in table, but got" & Queue.Value.Keys'Length'Img); end if; Value := Queue.Value.Get (Queue.Value.Keys (1)); if Value.Kind /= Kind then Queue.Checked_Error ("expected a single entry of type " & Kind'Img & ", but got a " & Value.Kind'Img); end if; return Key : constant String := +Queue.Value.Keys (1) do Queue.Value.Unset (Queue.Value.Keys (1)); end return; end Pop_Single_Table; ----------------------- -- Report_Extra_Keys -- ----------------------- function Report_Extra_Keys (Queue : Key_Queue) return Outcome is use UStrings; Message : UString := +"forbidden extra entries: "; Is_First : Boolean := True; Errored : Boolean := False; begin for Key of Queue.Value.Keys loop Errored := True; if Is_First then Is_First := False; else UStrings.Append (Message, ", "); end if; UStrings.Append (Message, Key); end loop; if Errored then if Force then Recoverable_Error (+Message); return Outcome_Success; else return Outcome_Failure (+Message); end if; else return Outcome_Success; end if; end Report_Extra_Keys; ----------------------- -- Report_Extra_Keys -- ----------------------- procedure Report_Extra_Keys (Queue : Key_Queue) is Result : constant Outcome := Queue.Report_Extra_Keys; begin if not Force and then not Result.Success then raise Alire.Checked_Error with Errors.Set (Message (Result)); end if; end Report_Extra_Keys; ----------- -- Print -- ----------- procedure Print (Queue : Key_Queue) is use TOML; function Image (Val : TOML_Value) return String is (case Val.Kind is when TOML_String => Val.As_String, when TOML_Boolean => Val.As_Boolean'Img, when TOML_Integer => Val.As_Integer'Img, when others => raise Unimplemented); procedure Print (Val : TOML_Value; Prefix : String) is begin case Val.Kind is when TOML_Table => Trace.Always (Prefix & "table:"); for Pair of Val.Iterate_On_Table loop if Pair.Value.Kind in Atom_Value_Kind then Trace.Always (Prefix & (+Pair.Key) & " = " & Image (Pair.Value)); else Trace.Always (Prefix & (+Pair.Key) & " = "); Print (Pair.Value, Prefix & " "); end if; end loop; when TOML_Array => Trace.Always (Prefix & "array(1 .." & Val.Length'Img & ") " & (if Val.Length > 0 then " of " & Val.Item (1).Kind'Img else "")); when others => Trace.Always (Prefix & "value: " & Val.Kind'Img); end case; end Print; begin Print (Queue.Value, ""); end Print; --------- -- "+" -- --------- function "+" (Vect : AAA.Strings.Vector) return TOML.TOML_Value is Result : constant TOML.TOML_Value := TOML.Create_Array; begin for Str of Vect loop Result.Append (TOML.Create_String (Str)); end loop; return Result; end "+"; -------------- -- To_Array -- -------------- function To_Array (V : TOML.TOML_Value) return TOML.TOML_Value is use TOML; begin if V.Kind = TOML_Array then return V; else declare Arr : constant TOML_Value := Create_Array; begin Arr.Append (V); return Arr; end; end if; end To_Array; -------------- -- To_Table -- -------------- function To_Table (Key : String; Val : TOML.TOML_Value) return TOML.TOML_Value is use TOML; begin return Table : constant TOML_Value := Create_Table do Table.Set (Key, Val); end return; end To_Table; --------------- -- To_Vector -- --------------- function To_Vector (Val : TOML.TOML_Value) return AAA.Strings.Vector is Result : Vector := Empty_Vector; begin for I in 1 .. Val.Length loop Result.Append (Val.Item (I).As_String); end loop; return Result; end To_Vector; end Alire.TOML_Adapters; alire-1.2.1/src/alire/alire-toml_adapters.ads000066400000000000000000000222101430264165500211160ustar00rootroot00000000000000private with Ada.Finalization; with AAA.Strings; use AAA.Strings; private with Alire.Errors; with TOML; use all type TOML.Any_Value_Kind; package Alire.TOML_Adapters with Preelaborate is function Create_Table (Key : String; Value : TOML.TOML_Value) return TOML.TOML_Value with Pre => (for all Char of Key => Char /= '.'), Post => Create_Table'Result.Kind in TOML.TOML_Table; -- Create a table with a single key and value type Key_Queue is tagged limited private; -- Helper type that simplifies keeping track of processed keys during load. -- Also encapsulates a context that can be used to pinpoint errors better. -- Note: all operations on this type use shallow copies! function From (Key : String; Value : TOML.TOML_Value; Context : String) return Key_Queue; -- Convert a key/value pair into a wrapped table as Key_Queue. function From (Value : TOML.TOML_Value; Context : String) return Key_Queue; -- Create a new queue wrapping a TOML value. function Descend (Parent : Key_Queue; Value : TOML.TOML_Value; Context : String) return Key_Queue; -- Wrap Value as a Key_Queue, using the parent context as context prefix. function Descend (Parent : Key_Queue; Key : String; Value : TOML.TOML_Value; Context : String) return Key_Queue; -- Use Parent for previous context, wrapping a key = value table. function Failure (Queue : Key_Queue; Message : String) return Outcome with Post => not Failure'Result.Success; -- Return a failed Outcome, using the Context & Message as information. procedure Assert (Queue : Key_Queue; Condition : Boolean; Message : String); -- If Condition is False, call Queue.Checked_Error (Message) procedure Checked_Error (Queue : Key_Queue; Message : String) with No_Return; -- Raise a Checked error with Context & ": " & Message, using Alire.Errors. procedure Recoverable_Error (Queue : Key_Queue; Message : String; Recover : Boolean := Alire.Force); -- As Checked_Error, but emit a warning instead when Recover is True function Checked_Pop (Queue : Key_Queue; Key : String; Kind : TOML.Any_Value_Kind) return TOML.TOML_Value; -- Return the requested Key value, checking it matches type Kind. If type -- mismatch or missing key raise a Checked_Error. function Contains (Queue : Key_Queue; Key : String) return Boolean; -- Says if one of the keys in the wrapped table is Key function Pop (Queue : Key_Queue) return TOML.TOML_Value; -- Return a value discarding its key; if no values left No_TOML_Value is -- returned. function Pop (Queue : Key_Queue; Value : out TOML.TOML_Value) return String with Post => Value.Is_Present or else Pop'Result = ""; -- Get a Key/Value pair. The returned string is the key. The pair is -- removed from the queue. An empty string is returned when no more pairs -- are left. function Pop (Queue : Key_Queue; Key : String; Value : out TOML.TOML_Value) return Boolean with Post => Value.Is_Present or else not Pop'Result; -- Remove Key from the given set of keys and set Value to the -- corresponding value in Queue. Return whether Key was present. function Pop (Queue : Key_Queue; Key : String) return TOML.TOML_Value; -- Pop a key, that must exist, without checking its type (see Checked_Pop); function Pop_Expr (Queue : Key_Queue; Prefix : String; Value : out TOML.TOML_Value) return String; -- Return a entry in the underlying table whose key starts with Prefix, -- or No_TOML_Value if not a table or does not contain such a key. The -- intended use is to process keys beginning with "case(" in the table. function Pop_Single_Table (Queue : Key_Queue; Value : out TOML.TOML_Value; Kind : TOML.Any_Value_Kind) return String; -- For constructions like [parent.child.grandchild], where we known that -- only one child can exist. Will raise Checked_Error if any of these -- happens: Queue is not a table; Queue doesn't have exactly one key; Value -- is not of the expected Kind. Returns the single key child. Value is set -- to grandchild. function Unwrap (Queue : Key_Queue) return TOML.TOML_Value; -- Return the internal value as-is (with any already popped keys missing). procedure Assert_Key (Queue : Key_Queue; Key : String; Kind : TOML.Any_Value_Kind); -- Ensures that Key exists with given Kind type, or raises Checked_Error. function Report_Extra_Keys (Queue : Key_Queue) return Outcome; -- If Queue still contains pending keys, consider it's an error, return -- false and fill error with extra keys. Just return Success otherwise. procedure Report_Extra_Keys (Queue : Key_Queue); -- As the previous function, but raise Checked_Error with the same -- information in case of remaining keys. procedure Print (Queue : Key_Queue); -- Debug helper. -- Helpers to create TOML values with ease function "+" (S : String) return TOML.TOML_Value is (TOML.Create_String (S)); function "+" (Vect : AAA.Strings.Vector) return TOML.TOML_Value; function To_Array (V : TOML.TOML_Value) return TOML.TOML_Value with Pre => V.Kind in TOML.Atom_Value_Kind or V.Kind = TOML.TOML_Array, Post => To_Array'Result.Kind = TOML.TOML_Array; -- Take an atom value and return an array of a single element -- If already an array, do nothing function To_Table (Key : String; Val : TOML.TOML_Value) return TOML.TOML_Value with Post => To_Table'Result.Kind = TOML.TOML_Table; -- Create a table with a single key=val entry function Adafy (Key : String) return String; -- Take a toml key and replace every '-' and '.' with a '_'; Use Title_Case -- unless key = "others". function Tomify (Image : String) return String; -- Take some enumeration image and turn it into a TOML-style key, replacing -- every "_" with a "-" and in lower case. function To_Vector (Val : TOML.TOML_Value) return AAA.Strings.Vector with Pre => Val.Kind = TOML.TOML_Array; -- Take a TOML value and turn it into a vector of strings function Merge_Tables (L, R : TOML.TOML_Value) return TOML.TOML_Value with Pre => L.Kind in TOML.TOML_Table and then R.Kind in TOML.TOML_Table, Post => Merge_Tables'Result.Kind in TOML.TOML_Table; generic type Enum is (<>); function Tomify_Enum (E : Enum) return TOML.TOML_Value; -- As the previous function, but taking enumeration values directly. private use type UString; -- Allows comparisons between strings and unbounded type Key_Queue is new Ada.Finalization.Limited_Controlled with record Value : TOML.TOML_Value; end record; overriding procedure Finalize (This : in out Key_Queue); -------------- -- Contains -- -------------- function Contains (Queue : Key_Queue; Key : String) return Boolean is (Queue.Unwrap.Kind in TOML.TOML_Table and then (for some Table_Key of Queue.Unwrap.Keys => Key = Table_Key)); ------------ -- Unwrap -- ------------ function Unwrap (Queue : Key_Queue) return TOML.TOML_Value is (Queue.Value); ------------- -- Descend -- ------------- function Descend (Parent : Key_Queue; Key : String; Value : TOML.TOML_Value; Context : String) return Key_Queue is (From (Key, Value, Context)); ------------- -- Failure -- ------------- function Failure (Queue : Key_Queue; Message : String) return Outcome is (Outcome_Failure (Message)); ----------- -- Adafy -- ----------- function Adafy (Key : String) return String is (if (for some Char of Key => Char = '_') then raise Alire.Checked_Error with Errors.Set ("TOML keys should use hyphens instead of underscores, but found key: " & Key) elsif To_Lower_Case (Key) = "others" then To_Lower_Case (Key) else To_Mixed_Case (Replace (Replace (Key, Match => "-", Subst => "_"), Match => ".", Subst => "_"))); ---------------------- -- Tomify_As_String -- ---------------------- function Tomify (Image : String) return String is (Replace (To_Lower_Case (Image), Match => "_", Subst => "-")); ------------ -- Tomify -- ------------ function Tomify_Enum (E : Enum) return TOML.TOML_Value is (TOML.Create_String (Replace (To_Lower_Case (E'Img), Match => "_", Subst => "-"))); end Alire.TOML_Adapters; alire-1.2.1/src/alire/alire-toml_index.adb000066400000000000000000000470521430264165500204140ustar00rootroot00000000000000with Ada.Directories; with Alire.Config; with Alire.Crates; with Alire.Directories; with Alire.TOML_Adapters; with Alire.Hashes.SHA256_Impl; pragma Unreferenced (Alire.Hashes.SHA256_Impl); with Alire.Hashes.SHA512_Impl; pragma Unreferenced (Alire.Hashes.SHA512_Impl); -- Hash implementation generics are not directly withed anywhere. Since they -- are not Preelaborate, and the index loader is one of the few in Alire also -- not Preelaborate, and retrieving a file will always occur after loading the -- index, this seems a decent place to force inclusion in the build closure. with Alire.Index; with Alire.Manifest; with Alire.Origins.Deployers.Filesystem; with Alire.Origins.Tweaks; with Alire.TOML_Keys; with Alire.TOML_Load; with Alire.VCSs.Git; with Alire.Utils; with Alire.Utils.TTY; with GNATCOLL.VFS; with TOML; use type TOML.Any_Value_Kind, TOML.TOML_Value; package body Alire.TOML_Index is package Dirs renames Ada.Directories; package Semver renames Semantic_Versioning; Strict : Boolean := False; -- Allow or not unknown values in enums. This isn't easily moved to an -- argument given the current design. procedure Set_Error (Result : out Load_Result; Filename, Message : String; Context : String := "") with Post => not Result.Success; -- Set Result to not successful and assign an error message to it procedure Check_Index (Index : Index_On_Disk.Index'Class; Root : Any_Path; Result : out Load_Result) with Pre => Result.Success; -- Check that Catalog_Dir contains a file called "index.toml" and that it -- describes a supported catalog. procedure Load_Manifest (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean); -- Check if entry is a candidate to manifest file, and in that case load -- its contents. May raise Checked_Error. procedure Load_From_Catalog_Internal (File_Name : Absolute_Path; Name : Crate_Name; Version : String; Strict : Boolean); -- Do the actual loading of a file that pass tests based on name/location. -- Name and version have been deduced from the file name and will be used -- for double-checks. Package_File_Suffix : constant String := "toml"; -- Suffix for the name of package description files External_File_Marker : constant String := "external"; -- External definition files, instead of crate-x.x.x.toml, are named -- crate-external.toml. --------------- -- Set_Error -- --------------- procedure Set_Error (Result : out Load_Result; Filename, Message : String; Context : String := "") is Full_Context : constant String := (if Context = "" then Filename else Filename & "(" & Context & ")"); begin Result := (Success => False, Message => Ada.Strings.Unbounded.To_Unbounded_String (Full_Context & ": " & Message)); end Set_Error; ----------------- -- Check_Index -- ----------------- procedure Check_Index (Index : Index_On_Disk.Index'Class; Root : Any_Path; Result : out Load_Result) is Filename : constant String := Dirs.Compose (Root, "index.toml"); Value : TOML.TOML_Value; Key : constant String := "version"; Version : Semantic_Versioning.Version; Suggest_Update : Boolean := False; use type Semantic_Versioning.Version; Warn_Of_Old_Compatible : constant Boolean := Config.DB.Get (Config.Keys.Warning_Old_Index, Config.Defaults.Warning_Old_Index); ---------------------- -- Compare_Branches -- ---------------------- procedure Compare_Branches (Local : String) is Local_Kind : constant String := AAA.Strings.Head (Local, "-"); begin if Local_Kind /= Alire.Index.Branch_Kind and then Warn_Of_Old_Compatible then Put_Warning ("This alr build expects an index branch with prefix '" & TTY.Emph (Alire.Index.Branch_Kind) & "' but your community index branch is '" & TTY.Emph (Local) & "'", Disable_Config => Config.Keys.Warning_Old_Index); Suggest_Update := True; end if; end Compare_Branches; -------------------------------- -- Get_Local_Community_Branch -- -------------------------------- function Get_Local_Community_Branch return String is begin -- This will raise if somehow the index is not in a git repository return VCSs.Git.Handler.Branch (Index.Index_Directory); exception when E : Checked_Error => Log_Exception (E); return "undefined"; end Get_Local_Community_Branch; begin -- Read "index.toml" Value := TOML_Load.Load_File (Filename); -- Ensure metadata structure is as expected if not Value.Has (Key) then Set_Error (Result, Filename, "index metadata missing 'version' key"); elsif Value.Get (Key).Kind /= TOML.TOML_String then Set_Error (Result, Filename, "index version should hold a string, but found a " & Value.Get (Key).Kind'Img); elsif Value.Keys'Length /= 1 then Set_Error (Result, Filename, "index metadata contains unexpected fields, " & "only 'version' is expected"); else Version := Semantic_Versioning.Parse (Value.Get (Key).As_String, Relaxed => False); -- Check for a branch mismatch first if Index.Name = Alire.Index.Community_Name then Compare_Branches (Local => Get_Local_Community_Branch); end if; -- Check that index version is the expected one, or give minimal -- advice if it does not match. if Alire.Index.Valid_Versions.Contains (Version) and then Version /= Alire.Index.Version and then Warn_Of_Old_Compatible then Put_Warning ("Index '" & TTY.Emph (Index.Name) & "' version (" & Version.Image & ") is older than the newest supported by alr (" & Alire.Index.Version.Image & ")", Disable_Config => Config.Keys.Warning_Old_Index); Suggest_Update := True; elsif not Alire.Index.Valid_Versions.Contains (Version) then -- Index is either too old or too new if Alire.Index.Version < Version then Set_Error (Result, Filename, "index version (" & Version.Image & ") is newer than that expected by alr (" & Alire.Index.Version.Image & ")." & " You may have to update alr"); elsif Version < Semver.Parse (Alire.Index.Min_Compatible_Version) then Set_Error (Result, Filename, "index version (" & Version.Image & ") is too old. The minimum compatible version is " & Alire.Index.Min_Compatible_Version & ASCII.LF & (if Index.Name = Alire.Index.Community_Name then " Resetting the community index (" & TTY.Terminal ("alr index --reset--community") & ") may solve the issue. " & ASCII.LF else " Updating your local index might solve the issue " & "(alr index --update-all). " & ASCII.LF & "Otherwise, remove the " & "index with name '" & TTY.Emph (Index.Name) & "' (alr index --del " & Index.Name & ")")); end if; end if; if Suggest_Update and then Warn_Of_Old_Compatible then Put_Info ("If you experience any problems loading this index, " & "you may need to reset the community index with" & " '" & TTY.Terminal ("alr index --reset-community") & "'. " & "Note that this operation will delete any local" & " changes to the community index."); end if; if Alire.Index.Version /= Version then Trace.Debug ("Expected index version: " & Semantic_Versioning.Image (Alire.Index.Version)); Trace.Debug ("But got index version: " & Semantic_Versioning.Image (Version)); end if; end if; exception when Semantic_Versioning.Malformed_Input => Set_Error (Result, Filename, "malformed version string: " & Value.Get (Key).As_String); end Check_Index; ----------------- -- Locate_Root -- ----------------- function Locate_Root (Index : Index_On_Disk.Index'Class; Result : out Load_Result) return Any_Path is Repo_Version_Files : constant AAA.Strings.Vector := Alire.Directories.Find_Files_Under (Folder => Index.Index_Directory, Name => "index.toml", Max_Depth => 1); begin case Natural (Repo_Version_Files.Length) is when 0 => Result := Outcome_Failure ("No index.toml file found in index"); return ""; when 1 => return Root : constant Any_Path := Ada.Directories.Containing_Directory (Repo_Version_Files.First_Element) do Trace.Detail ("Loading index found at " & Root); Result := Outcome_Success; end return; when others => Result := Outcome_Failure ("Several index.toml files found in index"); return ""; end case; end Locate_Root; ---------- -- Load -- ---------- procedure Load (Index : Index_On_Disk.Index'Class; Strict : Boolean; Result : out Load_Result) is Root : constant Any_Path := Locate_Root (Index, Result); -- Locate a dir containing a 'index.toml' metadata file inside the repo. -- This is the directory containing the actual crates. begin if not Result.Success then return; end if; TOML_Index.Strict := Load.Strict; Trace.Detail ("Loading full catalog from " & Root); Check_Index (Index, Root, Result); if not Result.Success then return; end if; -- Go through all directories looking for release manifests begin Alire.Directories.Traverse_Tree (Start => Root, Doing => Load_Manifest'Access, Recurse => True); exception when E : Checked_Error => Result := Outcome_From_Exception (E); end; end Load; ---------- -- Load -- ---------- procedure Load (Index : Index_On_Disk.Index'Class; Crate : Crate_Name; Strict : Boolean) is use Alire.Directories.Operators; Result : Load_Result; Root : constant Any_Path := Locate_Root (Index, Result); -- Locate a dir containing a 'index.toml' metadata file inside the repo. -- This is the directory containing the actual crates. Crate_Root : constant Any_Path := Root / Crate.Index_Prefix; begin Result.Assert; TOML_Index.Strict := Load.Strict; Trace.Debug ("Loading single crate " & Utils.TTY.Name (Crate) & " from " & Root); if GNAT.OS_Lib.Is_Directory (Crate_Root) then Alire.Directories.Traverse_Tree (Start => Crate_Root, Doing => Load_Manifest'Access, Recurse => True); else Trace.Debug ("Requested crate does not exist in index"); end if; end Load; ------------------- -- Load_Manifest -- ------------------- procedure Load_Manifest (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean) is pragma Unreferenced (Stop); use Ada.Directories; use AAA.Strings; begin if Kind (Item) /= Ordinary_File then return; end if; Trace.Debug ("Checking manifest candidate file: " & Full_Name (Item)); -- We expect a /cr/crate_name/crate_name-version.toml structure declare Path : constant Absolute_Path := Full_Name (Item); File : constant Simple_File := Simple_Name (Item); Parent : constant Absolute_Path := Containing_Directory (Path); Shelf : constant Absolute_Path := Containing_Directory (Parent); subtype Shelf_Name is String with Dynamic_Predicate => Shelf_Name'Length = 2 and then (for all Char of Shelf_Name => Char in Crate_Character) and then Shelf_Name (Shelf_Name'First) /= '_'; begin -- Skip the index metadata file if File = "index.toml" then return; end if; -- Basic checks if Extension (File) /= Package_File_Suffix then Raise_Checked_Error ("Unexpected file in index: " & Path); end if; if not Contains (File, "-") then Raise_Checked_Error ("Malformed manifest file name: " & Path); end if; if Simple_Name (Shelf) not in Shelf_Name then Raise_Checked_Error ("Malformed shelf folder name: " & Shelf); end if; declare -- Name/version deducted from file name, to double check FS_Name : constant Crate_Name := +Head (File, '-'); FS_Version : constant String := Tail (Base_Name (File), '-'); begin -- Preliminary checks based on file name if not Has_Prefix (Full => +FS_Name, Prefix => Simple_Name (Shelf)) then Raise_Checked_Error ("Mismatch between manifest and shelf: " & Path); end if; if +FS_Name /= Simple_Name (Parent) then Raise_Checked_Error ("Mismatch between manifest and parent: " & Path); end if; Load_From_Catalog_Internal (File_Name => Path, Name => FS_Name, Version => FS_Version, Strict => Strict); end; end; end Load_Manifest; -------------------------------- -- Load_From_Catalog_Internal -- -------------------------------- procedure Load_From_Catalog_Internal (File_Name : Absolute_Path; Name : Crate_Name; Version : String; Strict : Boolean) is -- We enter the folder of the file so any relative paths within (mostly -- used during tests, but might be valid for private indexes too) are -- properly resolved by the loaders elsewhere. Enter : Directories.Guard (Directories.Enter (Directories.Parent (File_Name))) with Unreferenced; ------------------- -- Error_In_File -- ------------------- function Error_In_File (Name, Error : String) return String is ("Error loading " & Name & ": " & Error); Value : TOML.TOML_Value; begin Trace.Debug ("Loading " & Utils.TTY.Name (Name) & " " & TTY.Version (Version) & " from " & File_Name); -- Load the TOML file Value := TOML_Load.Load_File (File_Name); -- Minimal name/version checks Assert (Value.Kind = TOML.TOML_Table, Error_In_File (File_Name, "Missing top-level table")); Assert (Value.Has (TOML_Keys.Name), Error_In_File (File_Name, "Missing name field")); Assert (Value.Get (TOML_Keys.Name).As_String = +Name, Error_In_File (File_Name, "External/internal name mismatch: " & "External is " & (+Name) & ", internal is " & Value.Get (TOML_Keys.Name).As_String)); if Version = "external" then Assert (not Value.Has (TOML_Keys.Version), Error_In_File (File_Name, "Expected external definitions but found version field")); else Assert (Value.Has (TOML_Keys.Version), Error_In_File (File_Name, "Missing version field")); declare use type Semver.Version; Internal : constant String := Value.Get (TOML_Keys.Version).As_String; begin Assert (Semver.Parse (Version) = Semver.Parse (Internal), Error_In_File (File_Name, "Mismatched versions: file name says " & Version & " but contents say " & Internal)); end; end if; -- Decode as release/externals if Version = External_File_Marker then Index.Add (Crates.From_Externals_Manifest (TOML_Adapters.From (Value, Context => "Loading externals from " & File_Name), Strict)); else Index_Release (File_Name, Releases.From_TOML (TOML_Adapters.From (Value, Context => "Loading release from " & File_Name), Manifest.Index, Strict)); end if; end Load_From_Catalog_Internal; ------------------- -- Index_Release -- ------------------- procedure Index_Release (Path : Relative_Path; Rel : Releases.Release) is use all type Origins.Kinds; use GNATCOLL; use all type VFS.Filesystem_String; Fixed : Releases.Release := Rel; begin -- Adjust and check a valid path for a local origin. -- This is delayed until this moment to keep many other -- packages Preelaborable. declare use type Origins.Origin; Origin : constant Origins.Origin := Origins.Tweaks.Fixed_Origin (Path, Fixed.Origin); begin if Origin.Kind = Filesystem then if not Origins.Deployers.Filesystem.Is_Valid_Local_Crate (VFS.Create (+Origin.Path)) then raise Constraint_Error with -- not an expected error in an index ("Local origin path is not a valid directory: " & Origin.Path); end if; end if; if Origin /= Fixed.Origin then Fixed := Fixed.Replacing (Origin); end if; end; Index.Add (Fixed); end Index_Release; ------------------- -- Manifest_File -- ------------------- function Manifest_File (Crate : Crate_Name; Version : Semantic_Versioning.Version; With_Extension : Boolean := True) return String is ((+Crate) & "-" & Version.Image & (if With_Extension then ".toml" else "")); ------------------- -- Manifest_Path -- ------------------- function Manifest_Path (Crate : Crate_Name) return Portable_Path is Name : constant String := +Crate; begin return Portable_Path ("index/" & Name (Name'First .. Name'First + 1) & "/" & Name); end Manifest_Path; end Alire.TOML_Index; alire-1.2.1/src/alire/alire-toml_index.ads000066400000000000000000000031601430264165500204250ustar00rootroot00000000000000with Alire.Index_On_Disk; with Alire.Releases; with Semantic_Versioning; package Alire.TOML_Index is subtype Load_Result is Outcome; function Manifest_File (Crate : Crate_Name; Version : Semantic_Versioning.Version; With_Extension : Boolean := True) return String; -- Get the proper file name for the manifest of an indexed crate. If not -- With_Extension, omit ".toml". function Manifest_Path (Crate : Crate_Name) return Portable_Path; -- Get the expected location of a crate manifest in an index. The result is -- portable; that is, always uses forward slashes. procedure Load (Index : Index_On_Disk.Index'Class; Strict : Boolean; Result : out Load_Result); -- Load the whole TOML catalog for the given index. If Strict, don't allow -- unknown enum values. procedure Load (Index : Index_On_Disk.Index'Class; Crate : Crate_Name; Strict : Boolean); -- Load just the releases for the given crate. Does not fail if the crate -- does not exist in the index. private procedure Index_Release (Path : Relative_Path; Rel : Releases.Release); -- Add the release to the global catalog. Path is where on disk the Crate -- was loaded from. This is necessary to fix relative paths in local -- origins, which at load time are relative to the manifest location, but -- at runtime the current dir may be any other. May raise Checked_Error if -- a release has an invalid path as origin. end Alire.TOML_Index; alire-1.2.1/src/alire/alire-toml_keys.ads000066400000000000000000000053751430264165500203030ustar00rootroot00000000000000package Alire.TOML_Keys with Preelaborate is -- Constants for TOML keys in the index format Action : constant String := "actions"; Action_Type : constant String := "type"; Action_Command : constant String := "command"; Action_Folder : constant String := "directory"; Author : constant String := "authors"; Auto_GPR_With : constant String := "auto-gpr-with"; Available : constant String := "available"; Build_Profiles : constant String := "build-profiles"; Build_Switches : constant String := "build-switches"; Case_Others : constant String := "..."; Compiler : constant String := "compiler"; Configuration : constant String := "configuration"; Config_Vars : constant String := "configuration.variables"; Config_Values : constant String := "configuration.values"; Depends_On : constant String := "depends-on"; Description : constant String := "description"; Distribution : constant String := "distribution"; Environment : constant String := "environment"; Executable : constant String := "executables"; External : constant String := "external"; External_Kind : constant String := "kind"; Forbidden : constant String := "forbids"; General : constant String := "general"; GPR_Ext : constant String := "gpr-externals"; GPR_Set_Ext : constant String := "gpr-set-externals"; Hint : constant String := "hint"; Host_Arch : constant String := "host-arch"; License : constant String := "licenses"; Long_Descr : constant String := "long-description"; Maintainer : constant String := "maintainers"; Maint_Logins : constant String := "maintainers-logins"; Name : constant String := "name"; Notes : constant String := "notes"; Origin : constant String := "origin"; OS : constant String := "os"; Path : constant String := "path"; Pinned : constant String := "pinned"; Pins : constant String := "pins"; Project_File : constant String := "project-files"; Provides : constant String := "provides"; Tag : constant String := "tags"; Target : constant String := "target"; Toolchain : constant String := "toolchain"; Version : constant String := "version"; Version_Cmd : constant String := "version-command"; Version_Regexp : constant String := "version-regexp"; Website : constant String := "website"; Word_Size : constant String := "word-size"; -- Constants used elsewhere Index_URL : constant String := "url"; Index_Name : constant String := "name"; Index_Priority : constant String := "priority"; end Alire.TOML_Keys; alire-1.2.1/src/alire/alire-toml_load.adb000066400000000000000000000176701430264165500202270ustar00rootroot00000000000000with Alire.Conditional_Trees.TOML_Load; with Alire.Expressions.Enums; with Alire.Errors; with Alire.Platforms; with Alire.Properties.From_TOML; with Alire.TOML_Keys; with TOML.File_IO; package body Alire.TOML_Load is use AAA.Strings; -- Instantiate loaders at library level package Available_Loader is new Conditional.For_Available.TOML_Load; package Dependency_Loader is new Conditional.For_Dependencies.TOML_Load; -- Register predefined environment variables so they're recognized on load package Distro_Expressions is new Expressions.Enums (Key => TOML_Keys.Distribution, Ada_Enum => Platforms.Distributions) with Unreferenced; package OS_Expressions is new Expressions.Enums (Key => TOML_Keys.OS, Name => "OS", Ada_Enum => Platforms.Operating_Systems) with Unreferenced; package Toolchain_Expressions is new Expressions.Enums (Key => TOML_Keys.Toolchain, Ada_Enum => Platforms.Toolchains) with Unreferenced; package Word_Size_Expressions is new Expressions.Enums (Key => TOML_Keys.Word_Size, Ada_Enum => Platforms.Word_Sizes) with Unreferenced; package Host_Arch_Expressions is new Expressions.Enums (Key => TOML_Keys.Host_Arch, Ada_Enum => Platforms.Architectures) with Unreferenced; -- The following are entries in the manifest that are not loaded as -- properties, but stored separately as complex types. type Tables is (Available, Dependencies, Forbids, Provides, Origin); Allowed_Tables : constant array (Crates.Sections, Tables) of Boolean := (Crates.Index_Release => (others => True), Crates.Local_Release => (Origin => False, others => True), Crates.External_Shared_Section => (others => False), Crates.External_Private_Section => (Available => True, others => False)); ------------------ -- Format_Error -- ------------------ function Format_Error (File : Any_Path; Result : TOML.Read_Result) return String is ((+Result.Message) & " at " & File & ":" & Trim (Result.Location.Line'Img) & ":" & Trim (Result.Location.Column'Img)); ------------------------ -- Load_Crate_Section -- ------------------------ procedure Load_Crate_Section (Strict : Boolean; Section : Crates.Sections; From : TOML_Adapters.Key_Queue; Props : in out Conditional.Properties; Deps : in out Conditional.Dependencies; Equiv : in out Alire.Provides.Equivalences; Forbids : in out Conditional.Forbidden_Dependencies; Pins : in out User_Pins.Maps.Map; Avail : in out Conditional.Availability) is use TOML; use type Conditional.Dependencies; use type Conditional.Properties; TOML_Avail : TOML.TOML_Value; TOML_Deps : TOML.TOML_Value; TOML_Equiv : TOML.TOML_Value; TOML_Forbids : TOML.TOML_Value; begin -- Check mandatory fields existence for Ada_Key in Properties.From_TOML.Mandatory'Range (2) loop declare TOML_Key : constant String := TOML_Adapters.Tomify (Ada_Key'Img); begin if Properties.From_TOML.Mandatory (Section, Ada_Key) then if not From.Unwrap.Has (TOML_Key) then From.Checked_Error ("mandatory property missing: " & TOML_Key); end if; end if; end; end loop; -- Process Dependencies if Allowed_Tables (Section, Dependencies) then if From.Pop (TOML_Keys.Depends_On, TOML_Deps) then From.Assert (TOML_Deps.Kind = TOML_Array, "dependencies must be specified as array of tables"); for I in 1 .. TOML_Deps.Length loop Deps := Deps and Dependency_Loader.Load (From => From.Descend (Key => TOML_Keys.Depends_On, Value => TOML_Deps.Item (I), Context => "(group" & I'Img & ")"), Loader => Conditional.Deps_From_TOML'Access, Resolve => True, Strict => Strict); end loop; end if; elsif From.Unwrap.Has (TOML_Keys.Depends_On) then From.Checked_Error ("found field not allowed in manifest section: " & TOML_Keys.Depends_On); end if; -- Process Forbids if Allowed_Tables (Section, TOML_Load.Forbids) then if From.Pop (TOML_Keys.Forbidden, TOML_Forbids) then From.Assert (TOML_Forbids.Kind = TOML_Array, "dependencies must be specified as array of tables"); for I in 1 .. TOML_Forbids.Length loop Forbids := Forbids and Dependency_Loader.Load (From => From.Descend (Key => TOML_Keys.Forbidden, Value => TOML_Forbids.Item (I), Context => "(group" & I'Img & ")"), Loader => Conditional.Deps_From_TOML'Access, Resolve => True, Strict => Strict); end loop; end if; elsif From.Unwrap.Has (TOML_Keys.Forbidden) then From.Checked_Error ("found field not allowed in manifest section: " & TOML_Keys.Forbidden); end if; -- Process Provides if Allowed_Tables (Section, Provides) then if From.Pop (TOML_Keys.Provides, TOML_Equiv) then From.Assert (TOML_Equiv.Kind = TOML_Array, "provides must be an array of strings describing milestones"); Equiv := Alire.Provides.From_TOML (From.Descend (TOML_Equiv, TOML_Keys.Provides)); end if; end if; -- Process user pins if From.Contains (TOML_Keys.Pins) then Pins := User_Pins.Maps.From_TOML (From.Descend (From.Checked_Pop (TOML_Keys.Pins, TOML_Array), Context => TOML_Keys.Pins)); end if; -- TODO: Process Forbidden -- Process Available if Allowed_Tables (Section, Available) then if From.Pop (TOML_Keys.Available, TOML_Avail) then Avail.Append (Conditional.Availability' (Available_Loader.Load (From => From.Descend (Key => TOML_Keys.Available, Value => TOML_Avail, Context => TOML_Keys.Available), Loader => Conditional.Available_From_TOML'Access, Resolve => True, Strict => Strict) with null record)); end if; elsif From.Unwrap.Has (TOML_Keys.Available) then From.Checked_Error ("found field not allowed in manifest section: " & TOML_Keys.Available); end if; -- Process remaining keys, which must be properties Props := Props and Properties.From_TOML.Section_Loaders (Section) (From, Strict); end Load_Crate_Section; --------------- -- Load_File -- --------------- function Load_File (File_Name : Any_Path) return TOML.TOML_Value is TOML_Result : constant TOML.Read_Result := TOML.File_IO.Load_File (File_Name); begin if TOML_Result.Success then return TOML_Result.Value; else Raise_Checked_Error (Errors.Wrap ("Invalid TOML contents in file", Format_Error (File_Name, TOML_Result))); end if; end Load_File; end Alire.TOML_Load; alire-1.2.1/src/alire/alire-toml_load.ads000066400000000000000000000022401430264165500202330ustar00rootroot00000000000000with Alire.Conditional; with Alire.Crates; with Alire.Provides; with Alire.TOML_Adapters; with Alire.User_Pins.Maps; with TOML; package Alire.TOML_Load is -- Separate package to avoid a circularity, since this is used by both -- Crates and Releases. function Format_Error (File : Any_Path; Result : TOML.Read_Result) return String with Pre => not Result.Success; function Load_File (File_Name : Any_Path) return TOML.TOML_Value; -- Will raise Checked_Error if file contents aren't valid TOML procedure Load_Crate_Section (Strict : Boolean; Section : Crates.Sections; From : TOML_Adapters.Key_Queue; Props : in out Conditional.Properties; Deps : in out Conditional.Dependencies; Equiv : in out Alire.Provides.Equivalences; Forbids : in out Conditional.Forbidden_Dependencies; Pins : in out User_Pins.Maps.Map; Avail : in out Conditional.Availability); -- Loads parts of a manifest, taking into account if we are loading -- an indexed release, a local release, an external shared section or -- an external private section. end Alire.TOML_Load; alire-1.2.1/src/alire/alire-toolchains-solutions.adb000066400000000000000000000033201430264165500224400ustar00rootroot00000000000000with Alire.Root; with Alire.Shared; package body Alire.Toolchains.Solutions is ------------------- -- Add_Toolchain -- ------------------- function Add_Toolchain (Solution : Alire.Solutions.Solution) return Alire.Solutions.Solution is Result : Alire.Solutions.Solution := Solution; begin -- For every tool in the toolchain that does not appear in the solution, -- we will insert the user-configured tool, if any. for Tool of Toolchains.Tools loop if Solution.Depends_On (Tool) then Trace.Debug ("Toolchain environment: solution already depends on " & Solution.State (Tool).TTY_Image); elsif Toolchains.Tool_Is_Configured (Tool) then Result := Result.Including (Release => Shared.Release (Target => Tool_Milestone (Tool), Detect_Externals => Tool_Is_External (Tool)), Env => Root.Platform_Properties, Add_Dependency => True, Shared => True); else Trace.Debug ("Toolchain environment: tool not in solution nor " & "defined by the user: " & Tool.TTY_Image); end if; end loop; return Result; end Add_Toolchain; --------------------- -- Is_In_Toolchain -- --------------------- function Is_In_Toolchain (Release : Releases.Release) return Boolean is use type Dependencies.Dependency; begin return Tool_Is_Configured (Release.Name) and then Tool_Dependency (Release.Name) = Release.To_Dependency.Value; end Is_In_Toolchain; end Alire.Toolchains.Solutions; alire-1.2.1/src/alire/alire-toolchains-solutions.ads000066400000000000000000000012411430264165500224610ustar00rootroot00000000000000with Alire.Releases; with Alire.Solutions; package Alire.Toolchains.Solutions is -- Needed to break circularity function Add_Toolchain (Solution : Alire.Solutions.Solution) return Alire.Solutions.Solution; -- If no release in the solution is a compiler/builder, add the configured -- ones (if defined) to the solution. This is used just before launching -- the build, so the configured tools are used despite not being in a -- regular solution. function Is_In_Toolchain (Release : Releases.Release) return Boolean; -- Say if this Release is part of the user-configured toolchain end Alire.Toolchains.Solutions; alire-1.2.1/src/alire/alire-toolchains.adb000066400000000000000000000332521430264165500204120ustar00rootroot00000000000000with AAA.Text_IO; with Ada.Containers.Indefinite_Vectors; with Alire.Config.Edit; with Alire.Index; with Alire.Origins; with Alire.Properties; with Alire.Releases.Containers; with Alire.Root; with Alire.Shared; with CLIC.User_Input; with CLIC.Config.Edit; with Semantic_Versioning.Extended; package body Alire.Toolchains is -------------- -- Any_Tool -- -------------- -- crate=* dependency builder function Any_Tool (Crate : Crate_Name) return Dependencies.Dependency is (Dependencies.New_Dependency (Crate, Semantic_Versioning.Extended.Any)); --------------- -- Assistant -- --------------- procedure Assistant (Level : Config.Level; Allow_Incompatible : Boolean := False) is package Release_Vectors is new Ada.Containers.Indefinite_Vectors (Positive, Releases.Release, Releases."="); type Selections is record Choices : AAA.Strings.Vector; Targets : Release_Vectors.Vector; -- These two variables are in sync; so the picked choice says the -- release to use at the same position in the respective vector. end record; Selected : Releases.Containers.Release_Set; -- We store here all selected releases, so they are deployed in batch -- after all the user interactions. use all type Origins.Kinds; Origin_Frozen : Boolean := False; Chosen_Origin : Origins.Kinds; -- GNAT and gprbuild should go in tandem; either from system packages, -- from some external user-provided location, or from indexed releases. -- Otherwise they don't see each other. When the user picks the first -- tool with a certain origin, only matching origins are allowed for -- the remaining tool. None : constant String := "None"; --------------------- -- Is_Valid_Choice -- --------------------- function Is_Valid_Choice (R : Releases.Release) return Boolean is (Allow_Incompatible or else not Origin_Frozen or else Chosen_Origin = R.Origin.Kind); -------------------------- -- Fill_Version_Choices -- -------------------------- function Fill_Version_Choices (Crate : Crate_Name) return Selections is Result : Selections; ---------------- -- Add_Choice -- ---------------- procedure Add_Choice (Text : String; Release : Alire.Releases.Release; Prepend : Boolean := False) is begin if Prepend then Result.Choices.Prepend (Text); Result.Targets.Prepend (Release); else Result.Choices.Append (Text); Result.Targets.Append (Release); end if; end Add_Choice; Env : constant Properties.Vector := Root.Platform_Properties; begin Index.Detect_Externals (Crate, Root.Platform_Properties); -- Always offer to configure nothing Result.Choices.Append (None); Result.Targets.Append (Releases.New_Empty_Release (Crate)); -- Just a placeholder that won't be used anywhere, but keeps boot -- collections in sync. -- Identify possible externals first (but after the newest Alire one) for Release of reverse Index.Releases_Satisfying (Any_Tool (Crate), Env) loop if Release.Origin.Kind in System | External and then Is_Valid_Choice (Release) then Add_Choice (Release.Milestone.TTY_Image & TTY.Dim (" [" & Release.Notes & "]"), Release); end if; end loop; -- Regular choices go afterwards, except for the most current one -- which goes before anything else. Add_Binary_Versions : declare First : Boolean := True; begin for Release of reverse Releases.Containers.From_Set -- This sorts by version (Index.Releases_Satisfying (Any_Tool (Crate), Env)) loop if Release.Origin.Is_Regular and then Is_Valid_Choice (Release) then -- We want the newest native compiler packaged by Alire to -- be the default. Sorting of the GNAT crate in Releases -- already guarantees that the last compiler in the -- collection will be a native one (if there is one). if First and then Release.Name.As_String = "gnat_native" then First := False; Add_Choice (Release.Milestone.TTY_Image, Release, Prepend => True); else Add_Choice (Release.Milestone.TTY_Image, Release); end if; end if; end loop; end Add_Binary_Versions; -- If it turns out that the first choice is None, this means that -- the user has selected a external/system toolchain, and no native -- options are offered. In this case, we move None to the second -- position. if Result.Choices.First_Element = None and then Natural (Result.Choices.Length) > 1 then Result.Choices.Delete_First; Result.Targets.Delete_First; Result.Choices.Insert (Before => 2, New_Item => None, Count => 1); Result.Targets.Insert (Before => 2, New_Item => Releases.New_Empty_Release (Crate), Count => 1); end if; return Result; end Fill_Version_Choices; ------------- -- Install -- ------------- procedure Install (Release : Releases.Release) is begin -- If the selected tool is one of our regular indexed ones, install -- the tool. Also, store the version in our configuration for future -- reference. On the contrary, if the selection is from system -- packages or the environment, we need not to install anything. -- (We are not offering system packages, as only one gnat can -- be installed e.g. in Debian, and changing it would affect the -- whole system. We only offer external compilers detected in the -- environment.) -- Deploy as a shared install unless external if Release.Origin.Is_Regular then Shared.Share (Release); else Trace.Debug ("The user selected a external version as default for " & Release.Milestone.TTY_Image); end if; -- Store tool milestone after successful deployment Set_As_Default (Release, Level); end Install; ------------------ -- Pick_Up_Tool -- ------------------ procedure Pick_Up_Tool (Crate : Crate_Name; Selection : Selections) is Choice : constant Positive := CLIC.User_Input.Query_Multi (Question => "Please select the " & Crate.TTY_Image & " version for use with this configuration", Choices => Selection.Choices); begin if Selection.Choices (Choice) = None then Put_Info ("Selected to rely on a user-provided binary."); -- Clean up stored version Unconfigure (Crate, Level); else Put_Info ("Selected tool version " & TTY.Bold (Selection.Targets (Choice).Milestone.TTY_Image)); -- Store for later installation declare Selected_Release : constant Releases.Release := Selection.Targets (Choice); begin Selected.Insert (Selected_Release); -- And verify we are not mixing external/indexed tools if not Origin_Frozen then Origin_Frozen := True; Chosen_Origin := Selected_Release.Origin.Kind; elsif Chosen_Origin /= Selected_Release.Origin.Kind then raise Program_Error with "Mixed selection should not be offered"; end if; end; end if; end Pick_Up_Tool; ------------ -- Set_Up -- ------------ procedure Set_Up (Crate : Crate_Name) is begin Trace.Info (""); if Tool_Is_Configured (Crate) then Put_Info ("Currently configured: " & Tool_Dependency (Crate).TTY_Image); else Put_Info (Crate.TTY_Image & " is currently not configured. (" & Utils.TTY.Alr & " will use the version found in the environment.)"); end if; Trace.Info (""); -- Find the newest regular release in our index: if not Index.Releases_Satisfying (Any_Tool (Crate), Root.Platform_Properties).Is_Empty then Pick_Up_Tool (Crate, Fill_Version_Choices (Crate)); else Put_Warning ("No indexed versions in the catalog for crate " & Crate.TTY_Image); end if; end Set_Up; begin AAA.Text_IO.Put_Paragraphs (AAA.Strings.Empty_Vector .Append ("Welcome to the toolchain selection assistant") .Append ("") .Append ("In this assistant you can set up the default toolchain to be " & "used with any crate that does not specify its own top-level " & "dependency on a version of " & Utils.TTY.Name ("gnat") & " or " & Utils.TTY.Name ("gprbuild.")) .Append ("") .Append ("If you choose " & TTY.Italic ("""None""") & ", Alire will use " & "whatever version is found in the environment.") ); if Allow_Incompatible then Put_Warning ("Selection of incompatible tools is " & TTY.Emph ("enabled"), Trace.Warning); end if; for Tool of Tools loop if not Allow_Incompatible and then Tool /= Tools.First_Element and then not Selected.Is_Empty then Trace.Info (""); Put_Info ("Choices for the following tool are narrowed down to " & "releases compatible with just selected " & Selected.First_Element.Milestone.TTY_Image); Trace.Detail ("Origin allowed for compatible tools is currently: " & Chosen_Origin'Image); end if; Set_Up (Tool); end loop; -- The user has already chosen, so disable the assistant Set_Automatic_Assistant (False, Level); -- Finally deploy selections for Release of Selected loop Install (Release); end loop; end Assistant; -------------------- -- Set_As_Default -- -------------------- procedure Set_As_Default (Release : Releases.Release; Level : Config.Level) is begin Alire.Config.Edit.Set (Level, Key => Tool_Key (Release.Name), Value => Release.Milestone.Image); Alire.Config.Edit.Set (Level, Key => Tool_Key (Release.Name, For_Is_External), Value => Boolean'(not Release.Origin.Is_Regular)'Image); end Set_As_Default; ----------------------------- -- Set_Automatic_Assistant -- ----------------------------- procedure Set_Automatic_Assistant (Enabled : Boolean; Level : Config.Level) is begin Config.Edit.Set (Level, Config.Keys.Toolchain_Assistant, (if Enabled then "true" else "false")); end Set_Automatic_Assistant; ------------------------ -- Tool_Is_Configured -- ------------------------ function Tool_Is_Configured (Crate : Crate_Name) return Boolean is (Config.DB.Defined (Tool_Key (Crate))); --------------------- -- Tool_Dependency -- --------------------- function Tool_Dependency (Crate : Crate_Name) return Dependencies.Dependency is (Dependencies.New_Dependency (Tool_Milestone (Crate))); ------------------ -- Tool_Release -- ------------------ function Tool_Release (Crate : Crate_Name) return Releases.Release is begin if not Tool_Is_Configured (Crate) then Raise_Checked_Error ("Requested tool is not configured: " & Utils.TTY.Name (Crate)); else return Shared.Release (Tool_Milestone (Crate)); end if; exception when E : Constraint_Error => Log_Exception (E); Raise_Checked_Error ("Requested tool configured but not installed: " & Utils.TTY.Name (Crate)); end Tool_Release; ----------------- -- Unconfigure -- ----------------- procedure Unconfigure (Crate : Crate_Name; Level : Config.Level; Fail_If_Unset : Boolean := True) is begin if CLIC.Config.Defined (Config.DB, Tool_Key (Crate)) and then not CLIC.Config.Edit.Unset (Config.Edit.Filepath (Level), Tool_Key (Crate)) then declare Msg : constant String := "Cannot unset config key " & Tool_Key (Crate) & " at config level " & Level'Image; begin if Fail_If_Unset then Raise_Checked_Error (Msg); else Trace.Debug (Msg); end if; end; end if; end Unconfigure; end Alire.Toolchains; alire-1.2.1/src/alire/alire-toolchains.ads000066400000000000000000000132741430264165500204350ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Sets; with AAA.Strings; with Alire.Config; with Alire.Dependencies; with Alire.Milestones; with Alire.Releases; with Alire.Utils; with Alire.Utils.TTY; with CLIC.Config; package Alire.Toolchains is package Name_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Crate_Name); Tools : constant Name_Sets.Set := Name_Sets.Empty_Set .Union (Name_Sets.To_Set (GNAT_Crate)) .Union (Name_Sets.To_Set (GPRbuild_Crate)); -- All crates that are part of the provided binary toolchain function Any_Tool (Crate : Crate_Name) return Dependencies.Dependency; -- Returns a dependency on crate* procedure Assistant (Level : Config.Level; Allow_Incompatible : Boolean := False); -- Runs the interactive assistant to select the default toolchain. By -- default, the native Alire-provided compiler for Current_OS is proposed. -- This information may apply config-wide or workspace-wide. Installation -- goes, in any case, to the config cache location. -- The following functions will transform any `gnat_XXX` dependency on -- plain `gnat`. This way we need to to litter the callers with similar -- transformations, as we always want whatever gnat_XXX is used for "gnat". procedure Set_Automatic_Assistant (Enabled : Boolean; Level : Config.Level); -- Enable/Disable the automatic assistant on next run function Assistant_Enabled return Boolean; procedure Set_As_Default (Release : Releases.Release; Level : Config.Level); -- Mark the given release as the default to be used. Does not check that it -- be already installed. function Tool_Is_Configured (Crate : Crate_Name) return Boolean; -- Say if a tool is actually configured by the user function Tool_Dependency (Crate : Crate_Name) return Dependencies.Dependency with Pre => Tool_Is_Configured (Crate); -- Return the configured compiler as an exact compiler=version dependency type Info_Kinds is (For_Use, For_Is_External); function Tool_Key (Crate : Crate_Name; Kind : Info_Kinds := For_Use) return CLIC.Config.Config_Key; -- Return the config key corresponding to a tool, for which milestone is in -- use or whether it is external. function Tool_Is_External (Crate : Crate_Name) return Boolean; -- Use the stored config to check if the tool is external without having to -- detect it. Defaults to True if unset or tool is not configured. function Tool_Milestone (Crate : Crate_Name) return Milestones.Milestone; function Tool_Release (Crate : Crate_Name) return Releases.Release; -- Will raise Checked_Error for unconfigured, or configured but without the -- release being deployed (e.g. the user messed with files and deleted it -- manually). procedure Unconfigure (Crate : Crate_Name; Level : Config.Level; Fail_If_Unset : Boolean := True); -- Set the crate as not configured. If not set and Fail_If_Unset, raise Description : constant AAA.Strings.Vector := AAA.Strings.Empty_Vector .Append ("Alire indexes binary releases of GNAT and gprbuild. The " & "compilers are indexed with their target name, e.g., " & Utils.TTY.Name ("gnat_native") & " or " & Utils.TTY.Name ("gnat_riscv_elf") & ". ") .Append ("") .Append ("Use " & TTY.Terminal ("alr toolchain --help") & " to obtain " & "information about toolchain management. Alire can be " & "configured to rely on a toolchain installed by the user in " & "the environment, or to use one of the indexed toolchains " & "whenever possible.") .Append ("") .Append ("Some crates may override the default toolchain by specifying " & "dependencies on particular compiler crates, for example to " & "use a cross-compiler. In this situation, a compiler already " & "available (selected as default or already installed) will " & "take precedence over a compiler available in the catalog. ") .Append ("") .Append ("See also " & TTY.URL ("https://alire.ada.dev/docs/#toolchains") & " for " & "additional details about compiler dependencies and toolchain " & "interactions."); private ----------------------- -- Assistant_Enabled -- ----------------------- function Assistant_Enabled return Boolean is (Config.DB.Get (Config.Keys.Toolchain_Assistant, Default => True)); -------------- -- Tool_Key -- -------------- -- Construct the "toolchain.use.crate" keys function Tool_Key (Crate : Crate_Name; Kind : Info_Kinds := For_Use) return CLIC.Config.Config_Key is (if AAA.Strings.Has_Prefix (Crate.As_String, "gnat_") then Tool_Key (GNAT_Crate, Kind) else CLIC.Config.Config_Key ((case Kind is when For_Use => Config.Keys.Toolchain_Use, when For_Is_External => Config.Keys.Toolchain_External) & "." & Crate.As_String)); ---------------------- -- Tool_Is_External -- ---------------------- function Tool_Is_External (Crate : Crate_Name) return Boolean is (Boolean'Value (Config.DB.Get (Tool_Key (Crate, For_Is_External), Default => "True"))); -------------------- -- Tool_Milestone -- -------------------- -- Return the milestone stored by the user for this tool function Tool_Milestone (Crate : Crate_Name) return Milestones.Milestone is (Milestones.New_Milestone (Config.DB.Get (Tool_Key (Crate), ""))); end Alire.Toolchains; alire-1.2.1/src/alire/alire-types.ads000066400000000000000000000021541430264165500174310ustar00rootroot00000000000000with Alire.Conditional; with Alire.Dependencies; -- with Alire.Dependencies.Vectors; with Alire.Releases; with Semantic_Versioning.Extended; package Alire.Types is -- Collection of types for convenient use and documentation subtype Dependency is Dependencies.Dependency; -- A single dependency on a single crate+versions subtype Abstract_Dependencies is Conditional.Dependencies; -- Conditional dependencies as yet unmaterialized for a precise platform subtype Platform_Dependencies is Conditional.Platform_Dependencies; -- A plain tree without conditions (but might have OR nodes) subtype Forbidden_Dependencies is Conditional.Forbidden_Dependencies; -- A plain tree without conditions or alternatives function No_Dependencies return Conditional.Dependencies renames Conditional.For_Dependencies.Empty; function New_Dependency (Name : Crate_Name; Versions : Semantic_Versioning.Extended.Version_Set) return Platform_Dependencies renames Conditional.New_Dependency; subtype Release is Releases.Release; -- A catalogued release end Alire.Types; alire-1.2.1/src/alire/alire-uri.adb000066400000000000000000000026611430264165500170460ustar00rootroot00000000000000package body Alire.URI is ----------------------------------- -- Authority_Without_Credentials -- ----------------------------------- function Authority_Without_Credentials (This : URL) return String is Auth : constant String := Authority (This); begin if (for some Char of Auth => Char = '@') then return AAA.Strings.Tail (Auth, '@'); else return Auth; end if; end Authority_Without_Credentials; ------------ -- Scheme -- ------------ function Scheme (This : URL) return Schemes is Img : constant String := L (U.Scheme (This)); begin return (if Img = "" then None elsif Img = "external" then External elsif Img = "file" then File elsif AAA.Strings.Has_Prefix (Img, "git+") then Git elsif AAA.Strings.Has_Prefix (Img, "git@") then Pure_Git elsif AAA.Strings.Has_Prefix (Img, "hg+") then Hg elsif AAA.Strings.Has_Prefix (Img, "svn+") then SVN elsif Img = "http" then HTTP elsif Img = "https" then HTTP elsif Img = "system" then System elsif Img'Length = 1 and then Img (Img'First) in 'a' .. 'z' then None -- A Windows drive letter, so a path without scheme else Unknown); end Scheme; end Alire.URI; alire-1.2.1/src/alire/alire-uri.ads000066400000000000000000000101521430264165500170610ustar00rootroot00000000000000with AAA.Strings; with Alire.Errors; private with URI; package Alire.URI with Preelaborate is -- Helpers to process URLs provided by the user. Note: there's already an -- Alire.URL type which is simply a String renaming without any additional -- constraints. -- See https://tools.ietf.org/html/rfc3986 for full details. -- -- http://user:pass@www.here.com:80/dir1/dir2/xyz.html?p=8&x=doh#anchor -- | | | | | | | -- protocol host port path file parameters fragment -- -- foo://example.com:8042/over/there?name=ferret#nose -- \_/ \______________/\_________/ \_________/ \__/ -- | | | | | -- scheme authority path query fragment -- | _____________________|__ -- / \ / \ -- urn:example:animal:ferret:nose type Schemes is (None, -- For URLs without scheme (to be interpreted as local paths) External, -- external: denotes a crate detected by some external definition File, -- A file: URI Git, -- Anything understood by git, expressed as git+, e.g.: -- git+http[s], git+file Pure_Git, -- An actual git@host:path URI Hg, SVN, -- Same considerations as for Git HTTP, -- Either http or https, since we don't differentiate treatment System, -- system:package is used to denote a native package from the platform Unknown -- Anything else ); -- Protocols recognized by Alire subtype VCS_Schemes is Schemes range Git .. SVN; subtype File_Schemes is Schemes with Static_Predicate => File_Schemes in None | File; function Scheme (This : URL) return Schemes; -- Extract the Scheme part of a URL function Authority (This : URL) return String; -- The authority includes credentials : user:pass@websi.te function Authority_Without_Credentials (This : URL) return String; -- Only the part after @ in an authority function Local_Path (This : URL) return String with Pre => Scheme (This) in None | File or else raise Checked_Error with Errors.Set ("Given URL does not seem to denote a path: " & This); -- Extract complete path from a URL intended for a local path: According to -- the URIs RFC, we (I) are using improperly the file: scheme. An absolute -- path should be file:/path/to/file, while a relative one should be -- file:rel/ati/ve. By using things like file://../path/to, ".." becomes -- the authority and "/path/to" the absolute path. This function, for use -- with Alire, returns the authority+path as the whole path, so there's no -- possible misinterpretation and any file:[/[/[/]]] combination should be -- properly interpreted. TL;DR: this should work without further concerns. -- -- TODO: fix incorrectly emitted file:// paths in Origins so at least we -- are not generating improper URIs. function Path (This : URL) return String; -- The path as properly defined (without the authority, if any) function Is_HTTP_Or_Git (This : URL) return Boolean is (Scheme (This) in Git | Pure_Git | HTTP or else AAA.Strings.Has_Suffix (This, ".git")); -- Heuristic to detect a possible git remote. Implementation public so -- there is no doubt to what it does. private package U renames Standard.URI; function L (Str : String) return String renames AAA.Strings.To_Lower_Case; --------------- -- Authority -- --------------- function Authority (This : URL) return String is (U.Extract (This, U.Authority)); ---------------- -- Local_Path -- ---------------- function Local_Path (This : URL) return String is (case Scheme (This) is when None => This, when File => U.Permissive_Path (This), when others => raise Program_Error with "not applicable"); ---------- -- Path -- ---------- function Path (This : URL) return String is (U.Extract (This, U.Path)); end Alire.URI; alire-1.2.1/src/alire/alire-user_pins-maps.adb000066400000000000000000000034241430264165500212120ustar00rootroot00000000000000with Ada.Text_IO; package body Alire.User_Pins.Maps is --------------- -- From_TOML -- --------------- function From_TOML (This : TOML_Adapters.Key_Queue) return Map is Result : Map; begin -- Each array entry may contain several pins (just like dependencies). -- We pass those one by one to the pin loader. for I in 1 .. This.Unwrap.Length loop declare Table : constant TOML.TOML_Value := This.Unwrap.Item (I); begin This.Assert (Table.Kind in TOML.TOML_Table, "expected a table with = but got: " & Table.Kind'Image); for Key of Table.Keys loop declare Crate : constant Crate_Name := +(+Key); begin if Result.Contains (Crate) then This.Checked_Error ("pin for crate " & (+Crate) & " is specified more than once"); end if; -- Obtain a single pin Result.Insert (Crate, User_Pins.From_TOML (This.Descend (Value => Table.Get (Key), Context => +Key))); end; end loop; end; end loop; return Result; end From_TOML; ----------- -- Print -- ----------- procedure Print (This : Map; Prefix : String := "") is use Ada.Text_IO; begin for I in This.Iterate loop Put_Line (Prefix & This (I) .To_Manifest_Line (Crate => Pin_Maps.Key (I))); end loop; end Print; end Alire.User_Pins.Maps; alire-1.2.1/src/alire/alire-user_pins-maps.ads000066400000000000000000000011511430264165500212260ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; with Alire.Errors; with TOML; package Alire.User_Pins.Maps is package Pin_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, Pin); type Map is new Pin_Maps.Map with null record; function From_TOML (This : TOML_Adapters.Key_Queue) return Map with Pre => This.Unwrap.Kind in TOML.TOML_Array or else raise Checked_Error with Errors.Set ("array expected but got a " & This.Unwrap.Kind'Image); procedure Print (This : Map; Prefix : String := ""); -- Print to stdout each Pin.To_Manifest_Line end Alire.User_Pins.Maps; alire-1.2.1/src/alire/alire-user_pins.adb000066400000000000000000000430041430264165500202520ustar00rootroot00000000000000with Ada.Directories; with Alire.Directories; with Alire.Origins; with Alire.Roots.Optional; with Alire.Utils.User_Input; with Alire.Utils.TTY; with Alire.VFS; with GNAT.OS_Lib; package body Alire.User_Pins is use type UString; package Keys is Branch : constant String := "branch"; Commit : constant String := "commit"; Internal : constant String := "lockfiled"; Path : constant String := "path"; URL : constant String := "url"; Version : constant String := "version"; end Keys; ----------------- -- New_Version -- ----------------- function New_Version (Version : Semantic_Versioning.Version) return Pin is (Kind => To_Version, Version => Version); -------------- -- New_Path -- -------------- function New_Path (Path : Any_Path) return Pin is (Kind => To_Path, Path => +Path); ---------------- -- New_Remote -- ---------------- function New_Remote (URL : Alire.URL; Commit : String := ""; Branch : String := "") return Pin is (Kind => To_Git, URL => +URL, Commit => +Commit, Branch => +Branch, Local_Path => <>); ----------- -- Image -- ----------- function Image (This : Pin; User : Boolean) return String is (case This.Kind is when To_Version => "version=" & TTY.Version (This.Version.Image), when To_Path => "path=" & TTY.URL (if User then VFS.Attempt_Portable (+This.Path) else +This.Path), when To_Git => (if Path (This) /= "" then "path=" & TTY.URL ((if User then VFS.Attempt_Portable (Path (This)) else Path (This))) & "," else "") & ("url=" & This.TTY_URL_With_Reference)); ---------------------- -- To_Manifest_Line -- ---------------------- function To_Manifest_Line (This : Pin; Crate : Crate_Name) return String is (Crate.As_String & " = { " & (case This.Kind is when To_Version => "version='" & This.Version.Image & "'", when To_Path => "path='" & VFS.Attempt_Portable (Path (This)) & "'", when To_Git => "url='" & (+This.URL) & "'" & (if This.Branch /= "" then ", branch='" & (+This.Branch) & "'" elsif This.Commit /= "" then ", commit='" & (+This.Commit) & "'" else "")) & " }"); --------------- -- Is_Broken -- --------------- function Is_Broken (This : Pin) return Boolean is (not Ada.Directories.Exists (Path (This)) or else Ada.Directories.Kind (Path (This)) not in Ada.Directories.Directory); ----------------- -- Deploy_Path -- ----------------- function Deploy_Path (This : Pin; Crate : Crate_Name; Under : Any_Path) return Absolute_Path is use Directories.Operators; begin return Ada.Directories.Full_Name (Under / (Crate.As_String & (if This.Is_Remote and then This.Commit /= "" then "_" & Origins.Short_Commit (+This.Commit) else ""))); end Deploy_Path; ------------ -- Deploy -- ------------ procedure Deploy (This : in out Pin; Crate : Crate_Name; Under : Any_Path; Online : Boolean) is use Ada.Strings.Unbounded; Destination : constant Absolute_Path := This.Deploy_Path (Crate, Under); -------------- -- Checkout -- -------------- procedure Checkout (Branch : String := ""; Commit : String := "") with Pre => not (Branch /= "" and then Commit /= ""); -- Pass only a commit or a branch. If none, default remote head. procedure Checkout (Branch : String := ""; Commit : String := "") is package Adirs renames Ada.Directories; Temp : Directories.Temp_File; begin -- Skip checkout of existing commit if Commit /= "" and then Adirs.Exists (Destination) then Trace.Debug ("Skipping checkout of commit pin at " & Destination); return; end if; -- Check out the branch or commit if not VCSs.Git.Handler.Clone (From => URL (This) & (if Commit /= "" then "#" & Commit else ""), Into => Temp.Filename, Branch => Branch, -- May be empty for default branch Depth => 1).Success then Raise_Checked_Error ("Checkout of repository at " & TTY.URL (URL (This)) & " failed, re-run with -vv -d for details"); end if; -- Successful checkout if not Adirs.Exists (Adirs.Containing_Directory (Destination)) then Adirs.Create_Path (Adirs.Containing_Directory (Destination)); end if; Adirs.Rename (Temp.Filename, Destination); Temp.Keep; end Checkout; ------------ -- Update -- ------------ procedure Update (Branch : String) is begin Trace.Detail ("Checking out pin " & Utils.TTY.Name (Crate) & " at " & TTY.URL (Destination)); -- If the fetch URL has been changed, fall back to checkout if VCSs.Git.Handler.Fetch_URL (Repo => Destination, Public => False) /= This.URL then Put_Info ("Switching pin " & Utils.TTY.Name (Crate) & " to origin at " & TTY.URL (+This.URL)); Directories.Delete_Tree (Destination); Checkout; -- Pending branch tracking implementation return; end if; -- Finally update. In case the branch has just been changed by the -- user in the manifest, the following call will also take care of -- it. if not VCSs.Git.Handler.Update (Destination, Branch).Success then Raise_Checked_Error ("Update of repository at " & TTY.URL (Destination) & " failed, re-run with -vv -d for details"); end if; end Update; begin -- Check when to do nothing if not This.Is_Remote then return; end if; This.Local_Path := +Destination; -- Don't check out an already existing commit pin, or a non-update -- branch pin if Ada.Directories.Exists (Destination) and then not Online and then (This.Commit /= "" -- Static checkout, no need to re-checkout or else This.Branch = "" -- Default branch, same or else VCSs.Git.Handler.Branch (Destination) = This.Branch) -- Branch is explicit and matches the one on disk, same then Trace.Debug ("Skipping deployment of already existing pin at " & TTY.URL (Destination)); return; end if; -- Check out a fixed commit, a branch, or update a branch are the three -- remaining possibilities. if This.Commit /= "" then Checkout (Commit => +This.Commit); elsif Ada.Directories.Exists (Destination) then Update (+This.Branch); -- Branch may still be "" if none given else Checkout (Branch => +This.Branch); -- Branch may still be "" if none given end if; -- At this point, we have the sources at Destination. Last checks ensue. declare Root : constant Roots.Optional.Root := Roots.Optional.Detect_Root (Destination); begin -- Check crate name mismatch if Root.Is_Valid and then Crate /= Root.Value.Release.Name then Raise_Checked_Error ("Requested and retrieved crates do not match: " & Utils.TTY.Name (Crate) & " /= " & Utils.TTY.Name (Root.Value.Release.Name)); end if; -- Warn if raw project if not Root.Is_Valid then Put_Warning ("Pin for " & Utils.TTY.Name (Crate) & " does not contain an Alire " & "manifest. It will be used as a raw GNAT project."); end if; end; end Deploy; ---------------------------- -- TTY_URL_With_Reference -- ---------------------------- function TTY_URL_With_Reference (This : Pin; Detailed : Boolean := False) return String is (TTY.URL (URL (This)) & (if Commit (This).Has_Element then "#" & TTY.Emph (if Detailed then +This.Commit else Origins.Short_Commit (+This.Commit)) elsif Branch (This).Has_Element then "#" & TTY.Emph (+This.Branch) else "")); ---------- -- Path -- ---------- function Path (This : Pin) return Absolute_Path is -- Having this as an expression function causes CE2021 to return a -- corrupted string some times. begin case This.Kind is when To_Path => return +This.Path; when To_Git => if +This.Local_Path /= "" then return +This.Local_Path; else raise Program_Error with "Undeployed pin"; end if; when others => raise Program_Error with "invalid pin kind"; end case; end Path; ------------------- -- Relative_Path -- ------------------- function Relative_Path (This : Pin; Color : Boolean := True) return String is Portable : constant String := VFS.Attempt_Portable (Directories.Find_Relative_Path_To (Path (This))); begin if Color then return TTY.URL (Portable); else return Portable; end if; end Relative_Path; --------------- -- From_TOML -- --------------- function From_TOML (This : TOML_Adapters.Key_Queue) return Pin is ---------------- -- From_Table -- ---------------- function From_Table (This : TOML_Adapters.Key_Queue) return Pin is use TOML; ------------------- -- From_Lockfile -- ------------------- -- Special case loader for pins not described by the user, but stored -- by us in the lockfile. These already have a path for the pin. function From_Lockfile return Pin is begin This.Assert (This.Checked_Pop (Keys.Internal, TOML_Boolean).As_Boolean, "Boolean expected"); if This.Contains (Keys.URL) then -- A complete remote pin return Result : Pin := (Kind => To_Git, others => <>) do Result.URL := +This.Checked_Pop (Keys.URL, TOML_String).As_String; Result.Local_Path := +Utils.User_Input.To_Absolute_From_Portable (This.Checked_Pop (Keys.Path, TOML_String).As_String); if This.Contains (Keys.Commit) then Result.Commit := +This.Checked_Pop (Keys.Commit, TOML_String).As_String; elsif This.Contains (Keys.Branch) then Result.Branch := +This.Checked_Pop (Keys.Branch, TOML_String).As_String; end if; end return; else -- Just a local pin return Result : Pin := (Kind => To_Path, others => <>) do Result.Path := +Utils.User_Input.To_Absolute_From_Portable (This.Checked_Pop (Keys.Path, TOML_String).As_String); end return; end if; end From_Lockfile; ------------------ -- Load_To_Path -- ------------------ function Load_To_Path return Pin is Result : Pin := (Kind => To_Path, Path => <>); User_Path : constant String := This.Checked_Pop (Keys.Path, TOML_String).As_String; begin This.Report_Extra_Keys; -- Check that the path was stored in portable format or as -- absolute path. if not Check_Absolute_Path (User_Path) and then not VFS.Is_Portable (User_Path) then This.Recoverable_Error ("Pin relative paths must use forward slashes " & "to be portable: " & Utils.TTY.URL (User_Path)); end if; -- Make the path absolute if not already, and store it Result.Path := +Utils.User_Input.To_Absolute_From_Portable (User_Path => User_Path, Error_When_Relative_Native => "Pin relative paths must use forward slashes " & " to be portable"); if not GNAT.OS_Lib.Is_Directory (+Result.Path) then This.Recoverable_Error ("Pin path is not a valid directory: " & (+Result.Path)); end if; return Result; end Load_To_Path; ----------------- -- Load_Remote -- ----------------- function Load_Remote return Pin is Result : Pin := (Kind => To_Git, URL => +This.Checked_Pop (Keys.URL, TOML_String).As_String, Branch => <>, Commit => <>, Local_Path => <>); begin if This.Contains (Keys.Branch) and then This.Contains (Keys.Commit) then This.Checked_Error ("cannot specify both a branch and a commit"); end if; -- TEST: simultaneous branch/commit if This.Contains (Keys.Commit) then Result.Commit := +This.Checked_Pop (Keys.Commit, TOML_String).As_String; This.Assert (+Result.Commit in Origins.Git_Commit, "invalid commit: " & (+Result.Commit)); elsif This.Contains (Keys.Branch) then Result.Branch := +This.Checked_Pop (Keys.Branch, TOML_String).As_String; This.Assert (+Result.Branch /= "", "branch cannot be the empty string"); end if; -- TEST: empty branch value This.Report_Extra_Keys; return Result; end Load_Remote; begin if This.Contains (Keys.Internal) then return Result : constant Pin := From_Lockfile do This.Report_Extra_Keys; end return; elsif This.Contains (Keys.Version) then return Pin' (Kind => To_Version, Version => Semantic_Versioning.Parse (This.Checked_Pop (Keys.Version, TOML_String).As_String)); elsif This.Contains (Keys.Path) then return Load_To_Path; elsif This.Contains (Keys.URL) then return Load_Remote; else Trace.Error ("Unexpected key in pin, got:"); This.Print; Raise_Checked_Error ("invalid pin description"); end if; end From_Table; begin case This.Unwrap.Kind is when TOML.TOML_String => return Pin' (Kind => To_Version, Version => Semantic_Versioning.Parse (This.Unwrap.As_String)); when TOML.TOML_Table => return Result : constant Pin := From_Table (This) do This.Report_Extra_Keys; end return; when others => Raise_Checked_Error ("improper format for pin, string or table expected but got a " & This.Unwrap.Kind'Image); end case; exception when E : Semantic_Versioning.Malformed_Input => Log_Exception (E); Raise_Checked_Error ("Malformed semantic version in pin"); end From_TOML; ------------- -- To_TOML -- ------------- function To_TOML (This : Pin) return TOML.TOML_Value is use TOML; Table : constant TOML_Value := Create_Table; begin -- Pins going into the lockfile require all the information; we must -- also notify the loader not to report unexpected keys if This.Is_Remote then Table.Set (Keys.URL, Create_String (URL (This))); if Commit (This).Has_Element then Table.Set (Keys.Commit, Create_String (Commit (This).Element.Ptr.all)); elsif Branch (This).Has_Element then Table.Set (Keys.Branch, Create_String (Branch (This).Element.Ptr.all)); end if; end if; Table.Set (Keys.Path, Create_String (VFS.Attempt_Portable (Path (This)))); Table.Set (Keys.Internal, Create_Boolean (True)); return Table; end To_TOML; end Alire.User_Pins; alire-1.2.1/src/alire/alire-user_pins.ads000066400000000000000000000144161430264165500203000ustar00rootroot00000000000000with Alire.Optional; with Alire.TOML_Adapters; with Alire.VCSs.Git; with Semantic_Versioning; with TOML; package Alire.User_Pins is -- User-facing representation of pins. These are loaded from the manifest. -- Internally, a user pin can be either a pin to a version, or a softlink -- to a folder. Note that, as they cannot exist in the index (we would not -- want an indexed crate to depend on unknown folders/remotes), there is no -- need to generate TOML for them. -- The information provided by the user in the pin is not complete to work -- with. The root must check if a remote pin was already retrieved, and if -- it matches the user description, or else fetch it, when a change in the -- manifest is detected. type Kinds is (To_Git, To_Path, To_Version); subtype Kinds_With_Path is Kinds range To_Git .. To_Path; type Pin (Kind : Kinds) is tagged private; function Image (This : Pin; User : Boolean) return String; -- Returns the internal information as-is or with relative paths, when User function Is_Remote (This : Pin) return Boolean; -- A pin to a remote source such as git, source archives, etc -- Version pins function New_Version (Version : Semantic_Versioning.Version) return Pin with Post => New_Version'Result.Kind = To_Version; function Version (This : Pin) return Semantic_Versioning.Version with Pre => This.Kind = To_Version; -- Local path pins function New_Path (Path : Any_Path) return Pin with Post => New_Path'Result.Kind = To_Path; function Is_Broken (This : Pin) return Boolean with Pre => This.Kind in Kinds_With_Path; function Path (This : Pin) return Absolute_Path with Pre => This.Kind in Kinds_With_Path; -- May raise if a Git pin hasn't been yet deployed (see Deploy proc). Even -- if paths can be given as relative, for our internal processing we can -- simplify things by always relying on absolute paths. function Relative_Path (This : Pin; Color : Boolean := True) return String with Pre => This.Kind in Kinds_With_Path; -- Convenience to show to users. May still return an absolute path for -- paths in another drive on Windows. May include TTY sequences. -- Remote pins function New_Remote (URL : Alire.URL; Commit : String := ""; Branch : String := "") return Pin with Pre => Commit = "" or else VCSs.Git.Is_Valid_Commit (Commit), Post => New_Remote'Result.Kind = To_Git; function URL (This : Pin) return Alire.URL with Pre => This.Is_Remote; function Branch (This : Pin) return Optional.String with Pre => This.Is_Remote; function Commit (This : Pin) return Optional.String with Pre => This.Is_Remote; function TTY_URL_With_Reference (This : Pin; Detailed : Boolean := False) return String with Pre => This.Is_Remote; -- returns https://blah[#commit|#branch], when existing function Deploy_Path (This : Pin; Crate : Crate_Name; Under : Any_Path) return Absolute_Path with Pre => This.Kind in Kinds_With_Path; -- Says where this pin would be deployed, without doing nothing else. Under -- is the umbrella folder for all pins of a root. procedure Deploy (This : in out Pin; Crate : Crate_Name; Under : Any_Path; Online : Boolean) with Pre => This.Kind in Kinds_With_Path, Post => Path (This) /= ""; -- Will fetch a remote pin and fill its local path; it is a no-op -- otherwise. Under is the umbrella folder for all pins, not the final pin -- destination. If Online, branch pins will be checked for updates. Any pin -- sources not at their expected final path (computed in here depending on -- the pin kind) will be checked out anyway. -- Pin loading from manifest function From_TOML (This : TOML_Adapters.Key_Queue) return Pin; -- Expects the rhs of a crate = entry. The rhs is always a table. -- Must be called with PWD being the same as of the manifest that is being -- loaded, so relative pins are correct. -- The TOML representation of a pin is similar to a dependency, but instead -- of a version set, we get either a precise version, or an url + commit: -- [[pins]] -- foo = "3.4" -- OR: -- foo = { version = "5.6" } -- foo = { path = "/path/to/folder" } -- bar = { url = "git+https://blah", [commit = "deadbeef"] } function To_TOML (This : Pin) return TOML.TOML_Value with Pre => This.Kind in Kinds_With_Path; -- Used by the lockfile function To_Manifest_Line (This : Pin; Crate : Crate_Name) return String; -- Returns the single line that describes this pin in a manifest private type Pin (Kind : Kinds) is tagged record case Kind is when To_Git => URL : UString; Branch : UString; -- Optional Commit : UString; -- Optional Local_Path : Unbounded_Absolute_Path; -- Empty until the pin is locally deployed when To_Path => Path : Unbounded_Absolute_Path; when To_Version => Version : Semantic_Versioning.Version; end case; end record; ------------ -- Branch -- ------------ function Branch (This : Pin) return Optional.String is (if +This.Branch = "" then Optional.Strings.Empty else Optional.Strings.Unit (+This.Branch)); ------------ -- Commit -- ------------ function Commit (This : Pin) return Optional.String is (if +This.Commit = "" then Optional.Strings.Empty else Optional.Strings.Unit (+This.Commit)); --------------- -- Is_Remote -- --------------- function Is_Remote (This : Pin) return Boolean is (This.Kind in To_Git); --------- -- URL -- --------- function URL (This : Pin) return Alire.URL is (+This.URL); ------------- -- Version -- ------------- function Version (This : Pin) return Semantic_Versioning.Version is (This.Version); end Alire.User_Pins; alire-1.2.1/src/alire/alire-utils-gnat_switches.ads000066400000000000000000000034511430264165500222660ustar00rootroot00000000000000with AAA.Strings; with Alire.Utils.Switches; use Alire.Utils.Switches; package Alire.Utils.GNAT_Switches with Preelaborate is pragma Style_Checks ("M120"); GNAT_Optimize_Performance : constant Switch := "-O3"; GNAT_Optimize_Debug : constant Switch := "-Og"; GNAT_Optimize_Size : constant Switch := "-Os"; GNAT_Enable_Inlining : constant Switch := "-gnatn"; GNAT_Asserts_And_Contracts : constant Switch := "-gnata"; GNAT_Debug_Info : constant Switch := "-g"; GNAT_Suppress_Runtime_Check : constant Switch := "-gnatp"; GNAT_Enable_Overflow_Check : constant Switch := "-gnato"; GNAT_Disable_Warn_No_Exception_Propagation : constant Switch := "-gnatw.X"; GNAT_Dont_Quit : constant Switch := "-gnatQ"; GNAT_All_Warnings : constant Switch := "-gnatwa"; GNAT_All_Validity_Checks : constant Switch := "-gnatVa"; GNAT_Warnings_As_Errors : constant Switch := "-gnatwe"; GNAT_Function_Sections : constant Switch := "-ffunction-sections"; GNAT_Data_Sections : constant Switch := "-fdata-sections"; GNAT_Ada83 : constant Switch := "-gnat83"; GNAT_Ada95 : constant Switch := "-gnat95"; GNAT_Ada05 : constant Switch := "-gnat05"; GNAT_Ada12 : constant Switch := "-gnat12"; GNAT_Ada2022 : constant Switch := "-gnat2022"; GNAT_Ada_Extensions : constant Switch := "-gnatX"; end Alire.Utils.GNAT_Switches; alire-1.2.1/src/alire/alire-utils-switches-knowledge.adb000066400000000000000000000073271430264165500232170ustar00rootroot00000000000000with Alire.Utils.GNAT_Switches; use Alire.Utils.GNAT_Switches; package body Alire.Utils.Switches.Knowledge is Builtin_Done : Boolean := False; -------------- -- Get_Info -- -------------- function Get_Info (Sw : Switch) return String is begin if DB.Contains (Sw) then return DB.Element (Sw); else return ""; end if; end Get_Info; -------------- -- Register -- -------------- procedure Register (Sw : Switch; Info : String) is begin DB.Insert (Sw, Info); end Register; -------------- -- Populate -- -------------- procedure Populate is begin if Builtin_Done then return; else Builtin_Done := True; end if; -- Register GNAT switches in the Switches knowledge database pragma Style_Checks ("M200"); Register (GNAT_Optimize_Performance, "Optimize for performance"); Register (GNAT_Optimize_Debug, "Optimize for debug"); Register (GNAT_Optimize_Size, "Optimize for code size"); Register (GNAT_Enable_Inlining, "Enable inlining"); Register (GNAT_Asserts_And_Contracts, "Enable assertions and contracts"); Register (GNAT_Debug_Info, "Generate debug info"); Register (GNAT_Suppress_Runtime_Check, "Suppress run-time checks"); Register (GNAT_Enable_Overflow_Check, "Enable numeric overflow checking"); Register (GNAT_Disable_Warn_No_Exception_Propagation, "Disable warnings for No_Exception_Propagation"); Register (GNAT_Dont_Quit, "Don't quit. Generate ALI and tree files even if illegalities"); Register (GNAT_All_Warnings, "Enable all warnings"); Register (GNAT_All_Validity_Checks, "All validity checks"); Register (GNAT_Warnings_As_Errors, "Warnings as errors"); Register (GNAT_Function_Sections, "Separate ELF section for each function"); Register (GNAT_Data_Sections, "Separate ELF section for each variable"); Register (GNAT_Ada83, "Ada 83 Compatibility Mode"); Register (GNAT_Ada95, "Ada 95 Mode"); Register (GNAT_Ada05, "Ada 2005 Mode"); Register (GNAT_Ada12, "Ada 2012 Mode"); Register (GNAT_Ada2022, "Ada 2022 Mode"); Register (GNAT_Ada_Extensions, "Enable GNAT Extensions"); Register ("-gnaty3", "Specify indentation level of 3"); Register ("-gnatya", "Check attribute casing"); Register ("-gnatyA", "Use of array index numbers in array attributes"); Register ("-gnatyB", "Check Boolean operators"); Register ("-gnatyb", "Blanks not allowed at statement end"); Register ("-gnatyc", "Check comments"); Register ("-gnaty-d", "Disable check no DOS line terminators present"); Register ("-gnatyD", "Check declared identifiers in mixed case"); Register ("-gnatye", "Check end/exit labels"); Register ("-gnatyf", "No form feeds or vertical tabs"); Register ("-gnatyh", "No horizontal tabs"); Register ("-gnatyi", "Check if-then layout"); Register ("-gnatyI", "check mode IN keywords"); Register ("-gnatyk", "Check keyword casing"); Register ("-gnatyl", "Check layout"); Register ("-gnatym", "Check maximum line length"); Register ("-gnatyn", "Check casing of entities in Standard"); Register ("-gnatyO", "Check that overriding subprograms are explicitly marked as such"); Register ("-gnatyp", "Check pragma casing"); Register ("-gnatyr", "Check identifier references casing"); Register ("-gnatyS", "Check no statements after THEN/ELSE"); Register ("-gnatyt", "Check token spacing"); Register ("-gnatyu", "Check unnecessary blank lines"); Register ("-gnatyx", "Check extra parentheses"); end Populate; end Alire.Utils.Switches.Knowledge; alire-1.2.1/src/alire/alire-utils-switches-knowledge.ads000066400000000000000000000010301430264165500232210ustar00rootroot00000000000000private with Ada.Containers.Indefinite_Ordered_Maps; package Alire.Utils.Switches.Knowledge is function Get_Info (Sw : Switch) return String; procedure Register (Sw : Switch; Info : String); procedure Populate; -- Populate the switches knowledge database with built-in switches private package Switch_Info_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Key_Type => Switch, Element_Type => String); DB : Switch_Info_Maps.Map; end Alire.Utils.Switches.Knowledge; alire-1.2.1/src/alire/alire-utils-switches.adb000066400000000000000000000153351430264165500212400ustar00rootroot00000000000000with Ada.Strings.Unbounded; with Alire.Utils.GNAT_Switches; use Alire.Utils.GNAT_Switches; package body Alire.Utils.Switches is ------------ -- Append -- ------------ function Append (L : Switch_List; S : Switch) return Switch_List is begin return R : Switch_List := L do R.Append (S); end return; end Append; ------------ -- Append -- ------------ function Append (L : Switch_List; S : not null Switch_Access) return Switch_List is begin return L.Append (S.all); end Append; ------------ -- Append -- ------------ function Append (A, B : Switch_List) return Switch_List is begin return R : Switch_List := A.Copy do for Elt of B loop R.Append (Elt); end loop; end return; end Append; ------------- -- Flatten -- ------------- function Flatten (L : Switch_List; Separator : String := " ") return String is use Ada.Strings.Unbounded; First : Boolean := True; Result : Unbounded_String; begin for Elt of L loop if First then Append (Result, Elt); First := False; else Append (Result, Separator & Elt); end if; end loop; return To_String (Result); end Flatten; -------------- -- Get_List -- -------------- function Get_List (S : Optimization_Switches) return Switch_List is (case S.Kind is when Performance => Empty_List .Append (GNAT_Optimize_Performance) .Append (GNAT_Enable_Inlining) .Append (GNAT_Function_Sections) .Append (GNAT_Data_Sections), when Size => Empty_List .Append (GNAT_Optimize_Size) .Append (GNAT_Enable_Inlining) .Append (GNAT_Function_Sections) .Append (GNAT_Data_Sections), when Debug => Empty_List .Append (GNAT_Optimize_Debug) .Append (GNAT_Function_Sections) .Append (GNAT_Data_Sections), when Custom => S.List); -------------- -- Get_List -- -------------- function Get_List (S : Debug_Info_Switches) return Switch_List is (case S.Kind is when No => Empty_List, when Yes => Empty_List.Append (GNAT_Debug_Info), when Custom => S.List); -------------- -- Get_List -- -------------- function Get_List (S : Contracts_Switches) return Switch_List is (case S.Kind is when No => Empty_List, when Yes => Empty_List.Append (GNAT_Asserts_And_Contracts), when Custom => S.List); -------------- -- Get_List -- -------------- function Get_List (S : Runtime_Checks_Switches) return Switch_List is (case S.Kind is when None => Empty_List.Append (GNAT_Suppress_Runtime_Check), when Default => Empty_List, when Overflow => Empty_List .Append (GNAT_Suppress_Runtime_Check) .Append (GNAT_Enable_Overflow_Check), when Everything => Empty_List.Append (GNAT_Enable_Overflow_Check), when Custom => S.List); -------------- -- Get_List -- -------------- function Get_List (S : Compile_Checks_Switches) return Switch_List is (case S.Kind is when None => Empty_List, when Warnings => Empty_List .Append (GNAT_All_Warnings) .Append (GNAT_Disable_Warn_No_Exception_Propagation) .Append (GNAT_All_Validity_Checks), when Errors => Empty_List .Append (GNAT_All_Warnings) .Append (GNAT_Disable_Warn_No_Exception_Propagation) .Append (GNAT_All_Validity_Checks) .Append (GNAT_Warnings_As_Errors), when Custom => S.List); -------------- -- Get_List -- -------------- function Get_List (S : Style_Checks_Switches) return Switch_List is (case S.Kind is when No => Empty_List, when Yes => Empty_List .Append ("-gnaty3") .Append ("-gnatya") .Append ("-gnatyA") .Append ("-gnatyB") .Append ("-gnatyb") .Append ("-gnatyc") .Append ("-gnaty-d") -- -gnatyD is not available in GNAT 9 -- .Append ("-gnatyD") .Append ("-gnatye") .Append ("-gnatyf") .Append ("-gnatyh") .Append ("-gnatyi") .Append ("-gnatyI") .Append ("-gnatyk") .Append ("-gnatyl") .Append ("-gnatym") .Append ("-gnatyn") .Append ("-gnatyO") .Append ("-gnatyp") .Append ("-gnatyr") .Append ("-gnatyS") .Append ("-gnatyt") .Append ("-gnatyu") .Append ("-gnatyx"), when Custom => S.List); -------------- -- Get_List -- -------------- function Get_List (S : Ada_Version_Switches) return Switch_List is (case S.Kind is when Compiler_Default => Empty_List, when Ada83 => Empty_List.Append (GNAT_Ada83), when Ada95 => Empty_List.Append (GNAT_Ada95), when Ada05 => Empty_List.Append (GNAT_Ada05), when Ada12 => Empty_List.Append (GNAT_Ada12), when Ada2022 => Empty_List.Append (GNAT_Ada2022), when GNAT_Extensions => Empty_List.Append (GNAT_Ada_Extensions), when Custom => S.List); -------------- -- Get_List -- -------------- function Get_List (C : Switches_Configuration) return Switch_List is begin return Empty_List .Append (Get_List (C.Optimization)) .Append (Get_List (C.Debug_Info)) .Append (Get_List (C.Runtime_Checks)) .Append (Get_List (C.Compile_Checks)) .Append (Get_List (C.Contracts)) .Append (Get_List (C.Style_Checks)) .Append (Get_List (C.Ada_Version)); end Get_List; end Alire.Utils.Switches; alire-1.2.1/src/alire/alire-utils-switches.ads000066400000000000000000000125551430264165500212620ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; package Alire.Utils.Switches with Preelaborate is subtype Switch is String; type Switch_Access is access all Switch; package Switch_Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Switch); type Switch_List is new Switch_Lists.List with null record; Empty_List : constant Switch_List; function Append (L : Switch_List; S : Switch) return Switch_List; function Append (L : Switch_List; S : not null Switch_Access) return Switch_List; function Flatten (L : Switch_List; Separator : String := " ") return String; type Profile_Kind is (Release, Validation, Development); type Switches_Categories is (Optimization, Debug_Info, Contracts, Compile_Checks, Runtime_Checks, Style_Checks, Ada_Version); type Optimization_Kind is (Performance, Size, Debug, Custom); type Debug_Info_Kind is (No, Yes, Custom); type Runtime_Checks_Kind is (None, Default, Overflow, Everything, Custom); type Compile_Checks_Kind is (None, Warnings, Errors, Custom); type Contracts_Kind is (No, Yes, Custom); type Style_Checks_Kind is (No, Yes, Custom); type Ada_Version_Kind is (Compiler_Default, -- This value means that no switch will be added -- and it's up to the compiler to decide which -- Ada version will be used. Ada83, Ada95, Ada05, Ada12, Ada2022, GNAT_Extensions, Custom); type Optimization_Switches (Kind : Optimization_Kind := Performance) is record case Kind is when Custom => List : Switch_List; when others => null; end case; end record; type Debug_Info_Switches (Kind : Debug_Info_Kind := No) is record case Kind is when Custom => List : Switch_List; when others => null; end case; end record; type Runtime_Checks_Switches (Kind : Runtime_Checks_Kind := None) is record case Kind is when Custom => List : Switch_List; when others => null; end case; end record; type Compile_Checks_Switches (Kind : Compile_Checks_Kind := None) is record case Kind is when Custom => List : Switch_List; when others => null; end case; end record; type Contracts_Switches (Kind : Contracts_Kind := No) is record case Kind is when Custom => List : Switch_List; when others => null; end case; end record; type Style_Checks_Switches (Kind : Style_Checks_Kind := No) is record case Kind is when Custom => List : Switch_List; when others => null; end case; end record; type Ada_Version_Switches (Kind : Ada_Version_Kind := Compiler_Default) is record case Kind is when Custom => List : Switch_List; when others => null; end case; end record; function Get_List (S : Optimization_Switches) return Switch_List; function Get_List (S : Debug_Info_Switches) return Switch_List; function Get_List (S : Runtime_Checks_Switches) return Switch_List; function Get_List (S : Compile_Checks_Switches) return Switch_List; function Get_List (S : Contracts_Switches) return Switch_List; function Get_List (S : Style_Checks_Switches) return Switch_List; function Get_List (S : Ada_Version_Switches) return Switch_List; type Switches_Configuration is record Optimization : Optimization_Switches; Debug_Info : Debug_Info_Switches; Runtime_Checks : Runtime_Checks_Switches; Compile_Checks : Compile_Checks_Switches; Contracts : Contracts_Switches; Style_Checks : Style_Checks_Switches; Ada_Version : Ada_Version_Switches; end record; function Get_List (C : Switches_Configuration) return Switch_List; Default_Release_Switches : constant Switches_Configuration := (Optimization => (Kind => Performance), Debug_Info => (Kind => No), Runtime_Checks => (Kind => Default), Compile_Checks => (Kind => None), Contracts => (Kind => No), Style_Checks => (Kind => No), Ada_Version => (Kind => Compiler_Default)); Default_Validation_Switches : constant Switches_Configuration := (Optimization => (Kind => Performance), Debug_Info => (Kind => Yes), Runtime_Checks => (Kind => Everything), Compile_Checks => (Kind => Errors), Contracts => (Kind => Yes), Style_Checks => (Kind => Yes), Ada_Version => (Kind => Compiler_Default)); Default_Development_Switches : constant Switches_Configuration := (Optimization => (Kind => Debug), Debug_Info => (Kind => Yes), Runtime_Checks => (Kind => Default), Compile_Checks => (Kind => Warnings), Contracts => (Kind => No), Style_Checks => (Kind => Yes), Ada_Version => (Kind => Compiler_Default)); private Empty_List : constant Switch_List := (Switch_Lists.Empty_List with null record); end Alire.Utils.Switches; alire-1.2.1/src/alire/alire-utils-tables.adb000066400000000000000000000014331430264165500206530ustar00rootroot00000000000000package body Alire.Utils.Tables is ------------ -- Header -- ------------ procedure Header (T : in out Table; Cell : String) is begin T.Append (TTY.Emph (AAA.Strings.To_Upper_Case (Cell))); end Header; ----------- -- Print -- ----------- procedure Print (T : Table; Level : Trace.Levels := Info; Separator : String := " "; Align : AAA.Table_IO.Alignments := (1 .. 0 => <>)) is procedure Print (Line : String) is begin Trace.Log (Line, Level); end Print; begin T.Print (Separator => Separator, Align => Align, Put_Line => Print'Access); end Print; end Alire.Utils.Tables; alire-1.2.1/src/alire/alire-utils-tables.ads000066400000000000000000000010061430264165500206700ustar00rootroot00000000000000with AAA.Table_IO; package Alire.Utils.Tables with Preelaborate is type Table is new AAA.Table_IO.Table with null record; procedure Header (T : in out Table; Cell : String); procedure Print (T : Table; Level : Trace.Levels := Info; Separator : String := " "; Align : AAA.Table_IO.Alignments := (1 .. 0 => <>)); -- Hook so tables use the default output facilities of Alire end Alire.Utils.Tables; alire-1.2.1/src/alire/alire-utils-text_files.adb000066400000000000000000000046131430264165500215520ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; with AAA.Strings; use AAA.Strings; with Alire.Directories; package body Alire.Utils.Text_Files is ------------------ -- Append_Lines -- ------------------ procedure Append_Lines (File : Any_Path; Lines : AAA.Strings.Vector; Backup : Boolean := True; Backup_Dir : Any_Path := "") is F : Text_Files.File := Load (File, Backup, Backup_Dir); begin F.Lines.Append (Lines); end Append_Lines; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out File) is File : File_Type; begin if This.Lines = This.Orig then Trace.Debug ("No changes to save in " & This.Name); return; end if; declare Replacer : Directories.Replacer := Directories.New_Replacement (This.Name, This.Backup, This.Backup_Dir); begin Open (File, Out_File, Replacer.Editable_Name); for Line of This.Lines loop Put_Line (File, Line); end loop; Close (File); Replacer.Replace; end; end Finalize; ----------- -- Lines -- ----------- function Lines (This : aliased in out File) return access AAA.Strings.Vector is (This.Lines'Access); ---------- -- Load -- ---------- function Load (From : Any_Path; Backup : Boolean := True; Backup_Dir : Any_Path := "") return File is F : File_Type; begin return This : File := (Ada.Finalization.Limited_Controlled with Length => From'Length, Backup_Len => Backup_Dir'Length, Name => From, Backup => Backup, Backup_Dir => Backup_Dir, Lines => <>, Orig => <>) do Open (F, In_File, From); while not End_Of_File (F) loop This.Orig.Append (Get_Line (F)); end loop; Close (F); This.Lines := This.Orig; end return; end Load; end Alire.Utils.Text_Files; alire-1.2.1/src/alire/alire-utils-text_files.ads000066400000000000000000000030051430264165500215650ustar00rootroot00000000000000with AAA.Strings; package Alire.Utils.Text_Files is -- A convenience type to hold a complete text file in memory as a vector of -- lines. On destruction, changes to the contents are written back to disk. -- A backup ".prev" file is also created by default. type File (<>) is tagged limited private; function Load (From : Any_Path; Backup : Boolean := True; Backup_Dir : Any_Path := "") return File; -- Load a text file into memory. If Backup, when saving takes place the -- original is renamed to ".prev". Backup_Dir optionally designates where -- the backup file will be moved. function Lines (This : aliased in out File) return access AAA.Strings.Vector; procedure Append_Lines (File : Any_Path; Lines : AAA.Strings.Vector; Backup : Boolean := True; Backup_Dir : Any_Path := ""); -- Add the given lines to the end of the file private type File (Length, Backup_Len : Natural) is new Ada.Finalization.Limited_Controlled with record Name : Any_Path (1 .. Length); Lines : aliased AAA.Strings.Vector; -- The final contents Orig : AAA.Strings.Vector; -- The original contents Backup : Boolean := True; Backup_Dir : Any_Path (1 .. Backup_Len); end record; overriding procedure Finalize (This : in out File); end Alire.Utils.Text_Files; alire-1.2.1/src/alire/alire-utils-tools.adb000066400000000000000000000115461430264165500205470ustar00rootroot00000000000000with Alire.OS_Lib.Subprocess; use Alire.OS_Lib.Subprocess; with Alire.OS_Lib; with Alire.Platforms.Current; with Alire.Origins.Deployers.System; with CLIC.User_Input; package body Alire.Utils.Tools is Already_Detected : array (Tool_Kind) of Boolean := (others => False); function Exec_For_Tool (Tool : Tool_Kind) return String; --------------- -- Available -- --------------- function Available (Tool : Tool_Kind) return Boolean is begin if Already_Detected (Tool) then return True; end if; if Locate_In_Path (Exec_For_Tool (Tool)) /= "" then -- The tool is available Already_Detected (Tool) := True; end if; return Already_Detected (Tool); end Available; ------------------- -- Exec_For_Tool -- ------------------- function Exec_For_Tool (Tool : Tool_Kind) return String is (case Tool is when Easy_Graph => "graph-easy", when Git => "git", when Tar => "tar", when Unzip => "unzip", when Curl => "curl", when Mercurial => "hg", when Subversion => "svn"); ----------------------------- -- System_Package_For_Tool -- ----------------------------- function System_Package_For_Tool (Tool : Tool_Kind) return String is use Alire.Platforms; use Alire.Platforms.Current; begin case Distribution is when Distro_Unknown => -- Cannot have package for an unknown distribution return ""; when Msys2 | Debian | Ubuntu | Arch | Centos | Fedora | Rhel => return (case Tool is when Easy_Graph => (if Distribution = Centos or else Distribution = Fedora or else Distribution = Rhel then "perl-Graph-Easy" elsif Distribution /= Msys2 and Distribution /= Arch then "libgraph-easy-perl" else ""), when Git | Tar | Unzip | Curl => Exec_For_Tool (Tool), when Mercurial => "mercurial", when Subversion => "subversion"); end case; end System_Package_For_Tool; -------------------------- -- Install_From_Distrib -- -------------------------- procedure Install_From_Distrib (Tool : Tool_Kind; Fail : Boolean) is use CLIC.User_Input; Pck : constant String := System_Package_For_Tool (Tool); begin if Pck /= "" then if Query ("Do you want Alire to install the required tool?", Valid => (Yes | No => True, others => False), Default => Yes) = Yes then declare use Alire.Origins.Deployers.System; Dep : Deployer'Class := Platform_Deployer (Pck); Result : Alire.Outcome; begin -- We already asked for permission, so disable the user query -- of the deployer. Dep.Dont_Ask_Permission; Result := Dep.Deploy (Folder => "unused"); Alire.Assert (Result); -- Check if installation worked if Locate_In_Path (Exec_For_Tool (Tool)) /= "" then -- Good to go return; else -- Error when installation failed Trace.Error ("Cannot proceed."); Trace.Error ("Tool still not available after installation..."); end if; end; else -- Error when user rejected installation if Fail then Trace.Error ("Cannot proceed."); Trace.Error ("Please install the tool and retry."); else Trace.Info ("Tool not installed."); return; end if; end if; else -- Error when Alire doesn't know how to install (unknown distro or -- tool not available in distro). if Fail then Trace.Error ("Cannot proceed."); Trace.Error ("Alire is not able to install required tool: '" & Tool'Img & "'"); Trace.Error ("Please install the tool and retry."); else Trace.Warning ("Alire is not able to install tool: '" & Tool'Img & "'"); return; end if; end if; OS_Lib.Bailout (1); end Install_From_Distrib; ---------------- -- Check_Tool -- ---------------- procedure Check_Tool (Tool : Tool_Kind; Fail : Boolean := True) is begin if Available (Tool) then return; end if; Trace.Info ("Cannot find required tool: " & Tool'Img); Install_From_Distrib (Tool, Fail); end Check_Tool; end Alire.Utils.Tools; alire-1.2.1/src/alire/alire-utils-tools.ads000066400000000000000000000010201430264165500205520ustar00rootroot00000000000000package Alire.Utils.Tools is type Tool_Kind is (Easy_Graph, Git, Tar, Unzip, Curl, Mercurial, Subversion); function Available (Tool : Tool_Kind) return Boolean; -- Say if tool is already available (attempts detection for the tool, but -- does not install it if missing). procedure Check_Tool (Tool : Tool_Kind; Fail : Boolean := True); -- Check if a required executable tool is available in PATH. -- If not, try to install it. If unable and Fail, abort, otherwise return end Alire.Utils.Tools; alire-1.2.1/src/alire/alire-utils-tty.ads000066400000000000000000000012771430264165500202500ustar00rootroot00000000000000with ANSI; with CLIC.TTY; package Alire.Utils.TTY with Preelaborate is function Alr return String is (CLIC.TTY.Terminal ("alr")); function Name (Crate : Crate_Name) return String is (CLIC.TTY.Bold (+Crate)); function Name (Crate : String) return String is (CLIC.TTY.Bold (Crate)); function Description (Text : String) return String is (CLIC.TTY.Format (Text, Fore => ANSI.Light_Cyan)); function Version (Text : String) return String is (CLIC.TTY.Format (Text, Fore => ANSI.Magenta, Style => ANSI.Bright)); function URL (Text : String) return String renames Version; end Alire.Utils.TTY; alire-1.2.1/src/alire/alire-utils-user_input-query_config.adb000066400000000000000000000043631430264165500242730ustar00rootroot00000000000000with Alire.Config.Edit; with CLIC.User_Input; use CLIC.User_Input; package body Alire.Utils.User_Input.Query_Config is ---------------------------- -- Config_Or_Query_String -- ---------------------------- function Config_Or_Query_String (Config_Key : String; Question : String; Default : String; Validation : String_Validation_Access) return String is use Alire.Config; begin if Config.DB.Defined (Config_Key) then return Config.DB.Get (Config_Key, Default); else declare Result : constant String := Query_String (Question, Default, Validation); begin if Result /= Default then Alire.Config.Edit.Set_Globally (Config_Key, Result); end if; return Result; end; end if; end Config_Or_Query_String; --------------- -- User_Name -- --------------- function User_Name return String is (Config_Or_Query_String (Config_Key => "user.name", Question => "Please enter your full name:", Default => "Your Name", Validation => null)); ----------------------- -- User_GitHub_Login -- ----------------------- function User_GitHub_Login return String is (Config_Or_Query_String (Config_Key => "user.github_login", Question => "Please enter your GitHub login:", Default => "github-username", Validation => Is_Valid_GitHub_Username'Access)); ----------------- -- Check_Email -- ----------------- function Check_Email (Str : String) return Boolean is (Could_Be_An_Email (Str, With_Name => False)); ---------------- -- User_Email -- ---------------- function User_Email return String is (Config_Or_Query_String (Config_Key => "user.email", Question => "Please enter your email address:", Default => "example@example.com", Validation => Check_Email'Access)); end Alire.Utils.User_Input.Query_Config; alire-1.2.1/src/alire/alire-utils-user_input-query_config.ads000066400000000000000000000021601430264165500243050ustar00rootroot00000000000000with CLIC.User_Input; package Alire.Utils.User_Input.Query_Config is use type CLIC.User_Input.String_Validation_Access; function Config_Or_Query_String (Config_Key : String; Question : String; Default : String; Validation : CLIC.User_Input.String_Validation_Access) return String with Pre => Validation = null or else Validation (Default); -- Same as Query_String but first looks for a configuration value before -- querying the user. If the answer is different from Default, it is saved -- in the global configuration. --------------------- -- Query or config -- --------------------- -- The following function will get their value from: -- - The config if defined -- - The user if in interactive mode -- - A default value otherwise function User_Name return String; function User_GitHub_Login return String with Post => (Is_Valid_GitHub_Username (User_GitHub_Login'Result)); function User_Email return String with Post => Could_Be_An_Email (User_Email'Result, With_Name => False); end Alire.Utils.User_Input.Query_Config; alire-1.2.1/src/alire/alire-utils-user_input.adb000066400000000000000000000053771430264165500216110ustar00rootroot00000000000000with Ada.Directories; with GNAT.OS_Lib; with Alire.VFS; with CLIC.User_Input; use CLIC.User_Input; package body Alire.Utils.User_Input is ----------------- -- Approve_Dir -- ----------------- function Approve_Dir (Dir : Any_Path; Force : Boolean := Alire.Force) return Boolean is begin if not GNAT.OS_Lib.Is_Directory (Dir) then return Query (Question => TTY.Error (if TTY.Color_Enabled then "âš " else "!") & " Given path does not exist: " & TTY.URL (Dir) & ASCII.LF & "Do you want to continue anyway?", Valid => (Yes | No => True, others => False), Default => (if Force then Yes else No)) = Yes; end if; return True; end Approve_Dir; ------------------------------ -- Confirm_Solution_Changes -- ------------------------------ function Confirm_Solution_Changes (Changes : Alire.Solutions.Diffs.Diff; Changed_Only : Boolean := not Alire.Detailed; Level : Alire.Trace.Levels := Info) return Boolean is package UI renames CLIC.User_Input; begin Trace.Log ("", Level); if Changes.Contains_Changes then Trace.Log ("Changes to dependency solution:", Level); Changes.Print (Changed_Only => Changed_Only); Trace.Log ("", Level); return UI.Query (Question => "Do you want to proceed?", Valid => (Yes | No => True, others => False), Default => (if Changes.Latter_Is_Complete or else Alire.Force then Yes else No)) = Yes; else Trace.Log ("There are no changes between the former and new solution.", Level); return True; end if; end Confirm_Solution_Changes; ------------------------------- -- To_Absolute_From_Portable -- ------------------------------- function To_Absolute_From_Portable (User_Path : String; Error_When_Relative_Native : String := "relative paths must use forward slashes to be portable") return Absolute_Path is begin if not Check_Absolute_Path (User_Path) and then not VFS.Is_Portable (User_Path) then Recoverable_Error (Error_When_Relative_Native & ": " & TTY.URL (User_Path)); end if; -- Make the path absolute if not already, and store it return Ada.Directories.Full_Name (if VFS.Is_Portable (User_Path) then VFS.To_Native (Portable_Path (User_Path)) else User_Path); end To_Absolute_From_Portable; end Alire.Utils.User_Input; alire-1.2.1/src/alire/alire-utils-user_input.ads000066400000000000000000000030231430264165500216140ustar00rootroot00000000000000with Alire.Solutions.Diffs; package Alire.Utils.User_Input is function Confirm_Solution_Changes (Changes : Solutions.Diffs.Diff; Changed_Only : Boolean := not Alire.Detailed; Level : Alire.Trace.Levels := Info) return Boolean; -- Present a summary of changes and ask the user for confirmation. Returns -- True when the user answers positively. Defaults to Yes when the new -- solution is complete, or when Alire.Force. function Approve_Dir (Dir : Any_Path; Force : Boolean := Alire.Force) return Boolean; -- Some commands receive a path from the user (e.g., pinning). If such path -- does not exist, we allow to continue only after user confirmation (or -- forcing). Returns whether to proceed. ---------------- -- VALIDATION -- ---------------- function To_Absolute_From_Portable (User_Path : String; Error_When_Relative_Native : String := "relative paths must use forward slashes to be portable") return Absolute_Path; -- Paths given by the user in the manifest have to be vetted for -- portability. If they are absolute there is nothing to do; but if they -- are relative they may be native or portable. Here we check if a relative -- path is portable (which is desirable so a manifest/lockfile can work -- across OSes) and, for internal processing, we convert it in any case -- to a native absolute path. end Alire.Utils.User_Input; alire-1.2.1/src/alire/alire-utils-yaml.adb000066400000000000000000000051001430264165500203360ustar00rootroot00000000000000package body Alire.Utils.YAML is ------------- -- To_YAML -- ------------- function To_YAML (V : Vector) return String is use all type Vectors.Index_Type; function Image (V : Vector; Pos : Vectors.Index_Type) return String is (T'Class (V.Element (Pos)).To_YAML & (if Pos = V.Last_Index then "" else "," & ASCII.LF & Image (V, Pos + 1))); begin if V.Is_Empty then return "[]"; else return "[" & Image (V, V.First_Index) & "]"; end if; end To_YAML; -------------------- -- YAML_Stringify -- -------------------- function YAML_Stringify (Input : String) return String is -- Inspired by AdaYaml, (c) 2017 Felix Krause Result : String (1 .. Input'Length * 4 + 2); -- Worst case is all input characters are escaped to hexadecimal, e.g. -- \xff. We also add leading and trailing double quotes. Last : Positive := Result'First; -- Index of the last character of result string ------------ -- Escape -- ------------ procedure Escape (C : Character) is begin Last := Last + 2; Result (Last - 1) := '\'; Result (Last) := C; end Escape; ------------------- -- Escape_To_Hex -- ------------------- procedure Escape_To_Hex (C : Character) is function To_Hex (X : Natural) return Character is (case X is when 0 .. 9 => Character'Val (Character'Pos ('0') + X), when 10 .. 15 => Character'Val (Character'Pos ('a') + X - 10), when others => 'x') with Pre => X <= 15; begin Escape ('x'); Last := Last + 2; Result (Last - 1) := To_Hex (Character'Pos (C) / 16); Result (Last) := To_Hex (Character'Pos (C) mod 16); end Escape_To_Hex; begin Result (Last) := '"'; for C of Input loop case C is when ASCII.LF => Escape ('l'); when ASCII.CR => Escape ('c'); when '"' | '\' => Escape (C); when ASCII.HT => Escape ('t'); when ASCII.NUL .. ASCII.BS | ASCII.VT .. ASCII.FF | ASCII.SO .. ASCII.US => Escape_To_Hex (C); when others => Last := Last + 1; Result (Last) := C; end case; end loop; Last := Last + 1; Result (Last) := '"'; return Result (Result'First .. Last); end YAML_Stringify; end Alire.Utils.YAML; alire-1.2.1/src/alire/alire-utils-yaml.ads000066400000000000000000000012441430264165500203640ustar00rootroot00000000000000with Alire.Interfaces; package Alire.Utils.YAML with Preelaborate is -- Needs to be split from Utils to avoid a dependency circularity. generic type T (<>) is new Alire.Interfaces.Yamlable with private; with package Vectors is new Ada.Containers.Indefinite_Vectors (Index_Type => <>, Element_Type => T); type Vector is new Vectors.Vector with private; function To_YAML (V : Vector) return String; -- Turn a vector of Yamlable into a YAML array function YAML_Stringify (Input : String) return String; -- Turn String data into YAML string, including enclosing double-quotes and -- escape characters. end Alire.Utils.YAML; alire-1.2.1/src/alire/alire-utils.adb000066400000000000000000000167571430264165500174220ustar00rootroot00000000000000with Ada.Command_Line; with AAA.Strings; use AAA.Strings; with Ada.Strings.Maps; with GNAT.OS_Lib; with GNAT.Regpat; package body Alire.Utils is --------------------------- -- Command_Line_Contains -- --------------------------- function Command_Line_Contains (Prefix : String) return Boolean is begin for I in 1 .. Ada.Command_Line.Argument_Count loop if Has_Prefix (Ada.Command_Line.Argument (I), Prefix) then return True; end if; end loop; return False; end Command_Line_Contains; ------------- -- Convert -- ------------- function Convert (V : Vector) return Other_Vector is OV : Other_Vector := Initial_Other_Vector; begin for E of V loop Append (OV, To_New_Value (E)); end loop; return OV; end Convert; ----------------------- -- Could_Be_An_Email -- ----------------------- type Matcher_Access is access GNAT.Regpat.Pattern_Matcher; Email_Matcher : Matcher_Access; -- Holds the email pattern matcher, compiled on first use. Email_With_Name_Matcher : Matcher_Access; -- Likewise, with a name and email enclosed in '<...>'. function Could_Be_An_Email (Str : String; With_Name : Boolean) return Boolean is Pat_Printable : constant String := "[!-~]"; -- Anything printable (ASCII 32-126). Pat_Printable_But_Dot : constant String := "[!--/-~]"; -- Anything printable but a dot Pat_User : constant String := Pat_Printable_But_Dot & Pat_Printable & "*"; -- Part before '@', anything printable goes except starting with '.' -- (ending is valid). Pat_Subdomain : constant String := "([[:alnum:]]([[:alnum:]]|-){0,61}[[:alnum:]])"; -- Subdomain parts; alphanumeric plus dash sequences, not -- starting/ending with a dash. Length in 2..63 (RFC 1035). Pat_Domain : constant String := Pat_Subdomain & "(\." & Pat_Subdomain & "){1,85}"; -- A domain is at least two subdomains separated by dots. A domain can -- be at worst 255 chars in length, but subs are already 2 + dot. Pat_Email : constant String := Pat_User & "@" & Pat_Domain; -- user@do.ma.in Pat_Only_Email : constant String := "^" & Pat_Email & "$"; -- An email without anything before or after. Pat_Named_Email : constant String := "^[^<]+ <" & Pat_Email & ">$"; -- A name plus a <...> quoted email. Pat_With_Or_Without_Name : constant String := "(" & Pat_Only_Email & ")|(" & Pat_Named_Email & ")"; -- Accept either of the two. use GNAT.Regpat; begin -- Initialize matchers on first call: if Email_Matcher = null then Trace.Debug ("Compiling email pattern...: " & Pat_Only_Email); Email_Matcher := new Pattern_Matcher'(Compile (Pat_Only_Email)); Trace.Debug ("Compiling named email pattern...: " & Pat_Named_Email); Email_With_Name_Matcher := new Pattern_Matcher'(Compile (Pat_With_Or_Without_Name)); end if; -- Do the matching: return Match (Self => (if With_Name then Email_With_Name_Matcher.all else Email_Matcher.all), Data => Str); end Could_Be_An_Email; ---------------- -- Count_True -- ---------------- function Count_True (Booleans : Boolean_Array) return Natural is begin return Set : Natural := 0 do for Bool of Booleans loop if Bool then Set := Set + 1; end if; end loop; end return; end Count_True; ----------------- -- First_Match -- ----------------- function First_Match (Regex : String; Text : String) return String is ----------------------- -- Count_Parentheses -- ----------------------- function Count_Parentheses return Positive is Count : Natural := 0; begin for Char of Regex loop if Char = '(' then Count := Count + 1; end if; end loop; return Count; end Count_Parentheses; use GNAT.Regpat; Matches : Match_Array (1 .. Count_Parentheses); -- This is a safe estimation, as some '(' may not be part of a capture begin Match (Regex, Text, Matches); for I in Matches'Range loop if Matches (I) /= No_Match then return Text (Matches (I).First .. Matches (I).Last); end if; end loop; return ""; end First_Match; ------------------------------- -- Is_Valid_Full_Person_Name -- ------------------------------- function Is_Valid_Full_Person_Name (Name : String) return Boolean is (for all C of Name => C not in Character'Val (0) .. Character'Val (31) | '\'); ------------------------------ -- Is_Valid_GitHub_Username -- ------------------------------ function Is_Valid_GitHub_Username (User : String) return Boolean is ((for all C of User => C in '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' | '-') and then User'Length in 1 .. 39 and then User (User'First) /= '-' and then User (User'Last) /= '-' and then not AAA.Strings.Contains (User, "--")); ------------------ -- Is_Valid_Tag -- ------------------ function Is_Valid_Tag (Tag : String) return Boolean is ((for all C of Tag => C in '0' .. '9' | 'a' .. 'z' | '-') and then Tag (Tag'First) /= '-' and then Tag (Tag'Last) /= '-' and then not AAA.Strings.Contains (Tag, "--")); -------------------- -- Image_One_Line -- -------------------- function Image_One_Line (V : Vector) return String is use all type Vectors.Index_Type; function Image (V : Vector; Pos : Vectors.Index_Type) return String is (Image (V.Element (Pos)) & (if Pos = V.Last_Index then "" else Separator & Image (V, Pos + 1))); begin if V.Is_Empty then return When_Empty; else return Image (V, V.First_Index); end if; end Image_One_Line; --------------- -- To_Native -- --------------- function To_Native (Path : Any_Path) return String is Dir_Seps : constant Ada.Strings.Maps.Character_Set := Ada.Strings.Maps.To_Set ("/\"); use Ada.Strings.Maps; begin return Native : String := Path do for I in Native'Range loop if Is_In (Path (I), Dir_Seps) then Native (I) := GNAT.OS_Lib.Directory_Separator; end if; end loop; end return; end To_Native; ------------------------- -- Image_Keys_One_Line -- ------------------------- function Image_Keys_One_Line (M : Maps.Map) return String is begin if M.Is_Empty then return When_Empty; else declare use Ada.Strings.Unbounded; US : Unbounded_String; First : Boolean := True; begin for C in M.Iterate loop if First then Append (US, Maps.Key (C)); First := False; else Append (US, Separator & Maps.Key (C)); end if; end loop; return To_String (US); end; end if; end Image_Keys_One_Line; end Alire.Utils; alire-1.2.1/src/alire/alire-utils.ads000066400000000000000000000100201430264165500174140ustar00rootroot00000000000000with Ada.Containers; with Ada.Containers.Indefinite_Vectors; with Ada.Containers.Indefinite_Ordered_Maps; with Ada.Finalization; package Alire.Utils with Preelaborate is subtype Hexadecimal_Character is Character with Static_Predicate => Hexadecimal_Character in '0' .. '9' | 'a' .. 'f'; function Command_Line_Contains (Prefix : String) return Boolean; -- Say if any of the command-line arguments begins with Prefix. This is -- needed for string arguments, that even when not supplied are initialized -- to an empty string by GNAT.Command_Line. Thus, it is impossible to -- distinguish by the switch value alone if the switch has been given -- without an optional argument, or not given at all. function Could_Be_An_Email (Str : String; With_Name : Boolean) return Boolean; -- Minimally check that a string could be an email. Since well-formed -- emails can be perfectly fake, we don't make this exceptionally -- foolproof. Complete regexps for email-compliant addresses are not -- trivial (see RFC 5322). We settle for the following: "a@b.c", -- where a can be anything printable but whitespace. b, c, can be -- alphanumeric and hyphens, not starting/ending with the latter -- (https://en.wikipedia.org/wiki/Domain_name). Additionally, if With_Name, -- the email can be enclosed in "<...>", with anything before it a -- plaintext name. type Boolean_Array is array (Positive range <>) of Boolean; function Count_True (Booleans : Boolean_Array) return Natural; function Is_Valid_Full_Person_Name (Name : String) return Boolean; -- Validate that a name does not contain control/escape characters function Is_Valid_GitHub_Username (User : String) return Boolean; -- Check username is valid according to -- https://github.com/shinnn/github-username-regex function Is_Valid_Tag (Tag : String) return Boolean; function Quote (S : String) return String; function To_Native (Path : Any_Path) return String; generic with package Vectors is new Ada.Containers.Indefinite_Vectors (<>); type Vector is new Vectors.Vector with private; with function Image (Item : Vectors.Element_Type) return String is <>; Separator : String := " "; When_Empty : String := "(empty)"; function Image_One_Line (V : Vector) return String; -- Flatten vector into string representation generic with package Vectors is new Ada.Containers.Indefinite_Vectors (<>); type Vector is new Vectors.Vector with private; type Other_Vector is new Ada.Finalization.Controlled with private; type Other_Vector_Value is private; Initial_Other_Vector : Other_Vector; with function To_New_Value (Item : Vectors.Element_Type) return Other_Vector_Value is <>; with procedure Append (Vec : in out Other_Vector; Val : Other_Vector_Value); function Convert (V : Vector) return Other_Vector; -- Convert between two vector types generic with package Maps is new Ada.Containers.Indefinite_Ordered_Maps (Key_Type => String, Element_Type => <>, "<" => <>, "=" => <>); Separator : String := " "; When_Empty : String := "(empty)"; function Image_Keys_One_Line (M : Maps.Map) return String; -- Flatten String keys of Indefinite_Ordered_Maps into string -- representation. function First_Match (Regex : String; Text : String) return String with Pre => (for some Char of Regex => Char = '('); -- Wrapper on GNAT.Regpat. It returns the first match found, which is not -- necessarily the first parenthesized expression. E.g., in a pattern like: -- (abc)|(efg), it will return the "efg" match, even if to GNAT.Regpat that -- is the second matching expression. In case of no match, it will return -- an empty string. At least one capture must be attempted in the Regex. private function Quote (S : String) return String is ("""" & S & """"); end Alire.Utils; alire-1.2.1/src/alire/alire-vcss-git.adb000066400000000000000000000451301430264165500200040ustar00rootroot00000000000000with Ada.Directories; with Alire.Directories; with Alire.OS_Lib.Subprocess; with Alire.Errors; with Alire.Utils.Tools; with Alire.VFS; with GNAT.Source_Info; package body Alire.VCSs.Git is ------------- -- Run_Git -- ------------- procedure Run_Git (Arguments : AAA.Strings.Vector) is begin -- Make sure git is installed Utils.Tools.Check_Tool (Utils.Tools.Git); OS_Lib.Subprocess.Checked_Spawn ("git", Arguments); end Run_Git; ------------------------- -- Run_Git_And_Capture -- ------------------------- function Run_Git_And_Capture (Arguments : AAA.Strings.Vector) return AAA.Strings.Vector is begin -- Make sure git is installed Utils.Tools.Check_Tool (Utils.Tools.Git); return OS_Lib.Subprocess.Checked_Spawn_And_Capture ("git", Arguments, Err_To_Out => True); end Run_Git_And_Capture; ----------------------------------- -- Unchecked_Run_Git_And_Capture -- ----------------------------------- procedure Unchecked_Run_Git_And_Capture (Arguments : AAA.Strings.Vector; Output : out AAA.Strings.Vector; Code : out Integer) is begin -- Make sure git is installed Utils.Tools.Check_Tool (Utils.Tools.Git); Code := OS_Lib.Subprocess.Unchecked_Spawn_And_Capture (Command => "git", Arguments => Arguments, Output => Output, Err_To_Out => True); end Unchecked_Run_Git_And_Capture; ------------ -- Branch -- ------------ function Branch (This : VCS; Path : Directory_Path) return String is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Path)) with Unreferenced; Output : constant AAA.Strings.Vector := Run_Git_And_Capture (Empty_Vector & "branch"); begin for Line of Output loop if Line'Length > 0 and then Line (Line'First) = '*' then return Tail (Line, ' '); end if; end loop; Raise_Checked_Error ("Unexpected output from 'git branch: " & Output.Flatten ("\n ")); end Branch; ----------- -- Clone -- ----------- overriding function Clone (This : VCS; From : URL; Into : Directory_Path) return Outcome is (This.Clone (From, Into, Branch => "")); ----------- -- Clone -- ----------- not overriding function Clone (This : VCS; From : URL; Into : Directory_Path; Branch : String; Depth : Natural := 0) return Outcome is pragma Unreferenced (This); Extra : constant Vector := (if Log_Level < Trace.Info or else not CLIC.TTY.Is_TTY then Empty_Vector & "-q" else Empty_Vector); Depth_Opts : constant Vector := (if Depth /= 0 and then Commit (From) = "" then Empty_Vector & "--depth" & Trim (Depth'Image) & "--no-single-branch" -- but all tips else Empty_Vector); Branch_Opts : constant Vector := (if Branch /= "" then Empty_Vector & "--branch" & Branch else Empty_Vector); begin Trace.Detail ("Checking out [git]: " & From); Run_Git (Empty_Vector & "clone" & "--recursive" & Extra & Branch_Opts & Depth_Opts & Repo (From) & Into); if Commit (From) /= "" then declare Guard : Directories.Guard (Directories.Enter (Into)) with Unreferenced; begin -- Checkout a specific commit. -- "-q" needed to avoid the "detached HEAD" warning from git Run_Git (Empty_Vector & "checkout" & "-q" & Commit (From)); -- Update the submodules, if any Run_Git (Empty_Vector & "submodule" & "update" & "--init" & "--recursive" & Extra); end; end if; return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Clone; --------------------- -- Revision_Commit -- --------------------- function Revision_Commit (This : VCS; Repo : Directory_Path; Rev : String) return String is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Repo)) with Unreferenced; begin declare Output : constant AAA.Strings.Vector := Run_Git_And_Capture (Empty_Vector & "log" & Rev & "-n1" & "--oneline" & "--no-abbrev-commit"); begin -- Check expected output if Output.Length in 1 then return Head (Output.First_Element, ' '); else return ""; end if; end; exception when others => -- git exits with code 128 for a non-existing Rev return ""; end Revision_Commit; --------------- -- Fetch_URL -- --------------- function Fetch_URL (This : VCS; Repo : Directory_Path; Origin : String := "origin"; Public : Boolean := True) return URL is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Repo)) with Unreferenced; Output : constant AAA.Strings.Vector := Run_Git_And_Capture (Empty_Vector & "config" & "--list"); begin for Line of Output loop if Has_Prefix (Line, "remote." & Origin & ".url") then declare URL : constant Alire.URL := Tail (Line, '='); begin if Public then return Transform_To_Public (URL); else return URL; end if; end; end if; end loop; return ""; end Fetch_URL; ----------------- -- Is_Detached -- ----------------- function Is_Detached (This : VCS; Path : Directory_Path) return Boolean is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Path)) with Unreferenced; Output : constant AAA.Strings.Vector := Run_Git_And_Capture (Empty_Vector & "status"); begin -- When a repo is in detached head state (e.g. after checking out a -- commit instead of a branch), 'git status' will have as the first line -- "HEAD detached at ". Other changes come next. return not Output.Is_Empty and then Contains (Output.First_Element, "HEAD detached"); end Is_Detached; ------------------- -- Is_Repository -- ------------------- function Is_Repository (This : VCS; Path : Directory_Path) return Boolean is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Path)) with Unreferenced; Unused : AAA.Strings.Vector; begin return OS_Lib.Subprocess.Unchecked_Spawn_And_Capture (Command => "git", Arguments => Empty_Vector & "status", Output => Unused, Err_To_Out => True) = 0; end Is_Repository; ------------ -- Remote -- ------------ function Remote (This : VCS; Path : Directory_Path; Checked : Boolean := True) return String is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Path)) with Unreferenced; Output : constant AAA.Strings.Vector := Run_Git_And_Capture (Empty_Vector & "remote"); begin if Output.Is_Empty then if Checked then Raise_Checked_Error ("No remote is configured"); else return ""; end if; else return Output.First_Element; end if; end Remote; ------------------- -- Remote_Commit -- ------------------- not overriding function Remote_Commit (This : VCS; From : URL; Ref : String := "HEAD") return String is Output : constant AAA.Strings.Vector := Run_Git_And_Capture (Empty_Vector & "ls-remote" & From); begin -- Sample output from git (space is tab): -- 95818710c1a2bea0cbfa617a67972fe984761227 HEAD -- b0825ac9373ed587394cf5e7ecf51fd7caf9290a refs/heads/feat/cache -- 95818710c1a2bea0cbfa617a67972fe984761227 refs/heads/master -- a917c31c47a8bd0155c402f692b63bd77e53bae7 refs/pull/1/head -- 22cb794ed99dfe6cbb0541af558ada1d2ed8fdbe refs/tags/v0.1 -- ae6fdd0711bb3ca2c1e2d1d18caf7a1b82a11f0a refs/tags/v0.1^{} -- 7376b76f23ab4421fbec31eb616d767edbec7343 refs/tags/v0.2 -- Prepare Ref to make it less ambiguous if Ref = "HEAD" or else Ref = "" then return This.Remote_Commit (From, ASCII.HT & "HEAD"); elsif Ref (Ref'First) not in '/' | ASCII.HT then return This.Remote_Commit (From, '/' & Ref); end if; -- Once here is reached, the Ref is ready for comparison declare Not_Found : constant String (Git_Commit'Range) := (others => 'x'); Result : String := Not_Found; begin for Line of Output loop if Has_Suffix (Line, Ref) then if Result = Not_Found then Result := Head (Line, ASCII.HT); else Raise_Checked_Error ("Reference is ambiguous: " & TTY.Emph (Ref)); end if; end if; end loop; if Result = Not_Found then return ""; else return Git_Commit (Result); -- Contents check end if; end; end Remote_Commit; ------------ -- Status -- ------------ function Status (This : VCS; Repo : Directory_Path) return States is Guard : Directories.Guard (Directories.Enter (Repo)) with Unreferenced; -- Out_1 should be portable. Out_2 is used as last resort; I believe -- git is not localized so it should always work but since it relies on -- human output it might break at any time I guess. Worst case, we would -- report an 'Ahead' as 'Dirty'. Out_1 : constant AAA.Strings.Vector := Run_Git_And_Capture (Empty_Vector & "status" & "--porcelain"); Untracked_File : Natural := 0; Tracked_File : Natural := 0; begin for Line of Out_1 loop if Contains (Line, "GNAT-TEMP-") then -- Turns out the temporary file we use to capture the output of -- "git status" makes git to return a dirty tree. We filter these -- out then. null; elsif Has_Prefix (Line, "??") then Untracked_File := Untracked_File + 1; else Tracked_File := Tracked_File + 1; end if; end loop; if Tracked_File /= 0 then -- There are added/modified tracked files return Dirty; else -- Retrieve revisions from remote branch tip up to our local HEAD. If -- not empty, we are locally ahead. declare Remote : constant String := This.Remote (Repo, Checked => False); begin if Remote = "" then return No_Remote; elsif Run_Git_And_Capture (Empty_Vector & "rev-list" & String'(Remote & "/" & This.Branch (Repo) & "..HEAD")).Is_Empty then return Clean; else -- At least one local commit not pushed to the remote return Ahead; end if; end; end if; end Status; ------------------------- -- Transform_To_Public -- ------------------------- function Transform_To_Public (Remote : String) return URL is Domain : constant String := Head (Tail (Remote, '@'), ':'); begin if Has_Prefix (Remote, "git@") and then Known_Transformable_Hosts.Contains (Domain) then return Public : constant URL := "https://" & Domain & "/" & Tail (Remote, ':') & (if Has_Suffix (Remote, ".git") then "" else ".git") do Trace.Warning ("Private git " & TTY.URL (Remote) & " transformed to public " & TTY.URL (Public)); end return; else return Remote; end if; end Transform_To_Public; ------------ -- Update -- ------------ overriding function Update (This : VCS; Repo : Directory_Path) return Outcome is (This.Update (Repo, Branch => "")); ------------ -- Update -- ------------ function Update (This : VCS; Repo : Directory_Path; Branch : String) return Outcome is Guard : Directories.Guard (Directories.Enter (Repo)) with Unreferenced; Extra : constant Vector := (if Log_Level < Trace.Info then Empty_Vector & "-q" else Empty_Vector); begin -- Switch branch if changed if Branch /= "" and then This.Branch (Repo) /= Branch then Trace.Detail ("Detected branch change needed in git update at " & TTY.URL (Repo) & "; switching from " & TTY.Emph (This.Branch (Repo)) & " to " & TTY.Emph (Branch)); Run_Git (Empty_Vector & "fetch"); -- In case there are new remote branches Run_Git (Empty_Vector & "checkout" & String'(This.Remote (Repo) & "/" & Branch) & "-B" & Branch & Extra & "--recurse-submodules"); -- Force overwrite any previous local same branch. Since we just -- fetched, the checkout should be up to date and there's no need -- to additionally pull. else Run_Git (Empty_Vector & "pull" & Extra & "--recurse-submodules"); -- Plain pull end if; return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Update; -------------- -- Worktree -- -------------- function Worktree (This : VCS; Repo : Directory_Path) return Worktree_Data is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Repo)) with Unreferenced; Output : AAA.Strings.Vector; Code : Integer; -------------------- -- Worktree_Error -- -------------------- function Worktree_Error (Output : AAA.Strings.Vector; Error : String) return String is (Error & " in `git worktree list`: " & Output.Flatten ("\n")); begin Code := OS_Lib.Subprocess.Unchecked_Spawn_And_Capture (Command => "git", Arguments => Empty_Vector & "worktree" & "list" & "--porcelain", Output => Output, Err_To_Out => True); return Data : Worktree_Data do if Code /= 0 then Trace.Debug ("git worktree list failed with code: " & Trim (Code'Image)); return; end if; Assert (Natural (Output.Length) >= 3, Worktree_Error (Output, "Unexpected output length (lines)")); Assert (Head (Output (1), ' ') = "worktree", Worktree_Error (Output, "Unexpected 1st line")); Assert (Head (Output (2), ' ') = "HEAD", Worktree_Error (Output, "Unexpected 2nd line")); Assert (Head (Output (3), ' ') = "branch", Worktree_Error (Output, "Unexpected 3rd line")); -- Git on windows returns an absolute but forward-slashed path. -- Depending on if it is a Windows git or a msys2 git it will [not] -- have also a drive letter. So we convert this path to a native one, -- as promised by the type in use. Data.Worktree := +VFS.To_Native (Portable_Path (Tail (Output (1), ' '))); Data.Head := Tail (Output (2), ' '); Data.Branch := +Tail (Output (3), ' '); end return; end Worktree; ----------------- -- Head_Commit -- ----------------- function Head_Commit (This : VCS; Repo : Directory_Path) return String is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Repo)) with Unreferenced; Output : constant AAA.Strings.Vector := Run_Git_And_Capture (Empty_Vector & "log" & "-n1" & "--oneline" & "--no-abbrev-commit"); begin return Head (Output.First_Element, ' '); end Head_Commit; ------------------------------ -- Get_Rel_Path_Inside_Repo -- ------------------------------ function Get_Rel_Path_Inside_Repo (This : VCS; Dir : Directory_Path) return Relative_Path is pragma Unreferenced (This); use Ada.Directories; use Alire.Directories.Operators; Guard : Directories.Guard (Directories.Enter (Full_Name (Dir))) with Unreferenced; begin return "." / Run_Git_And_Capture (Empty_Vector & "rev-parse" & "--show-prefix").First_Element; end Get_Rel_Path_Inside_Repo; ---------- -- Root -- ---------- function Root (This : VCS) return Optional.Absolute_Path is pragma Unreferenced (This); Code : Integer; Output : AAA.Strings.Vector; begin Unchecked_Run_Git_And_Capture (Empty_Vector & "rev-parse" & "--show-toplevel", Output, Code); if Code /= 0 then Trace.Debug ("git rev-parse returned code: " & Code'Image & " at " & GNAT.Source_Info.Source_Location); return Optional.Absolute_Paths.Empty; else return Optional.Absolute_Paths.Unit (Output.First_Element); end if; end Root; end Alire.VCSs.Git; alire-1.2.1/src/alire/alire-vcss-git.ads000066400000000000000000000134661430264165500200340ustar00rootroot00000000000000with AAA.Strings; with Alire.Optional; with Alire.Utils; package Alire.VCSs.Git is Known_Transformable_Hosts : constant AAA.Strings.Vector; -- Known hosts that honor the git@ --> https:// transformation subtype Git_Commit is String (1 .. 40) with Dynamic_Predicate => (for all Char of Git_Commit => Char in Utils.Hexadecimal_Character); function Is_Valid_Commit (S : String) return Boolean is (S'Length = Git_Commit'Length and then (for all Char of S => Char in Utils.Hexadecimal_Character)); No_Commit : constant Git_Commit := (others => '0'); -- This is actually returned by e.g. `git worktree`, even if it could be a -- real commit. I guess the chances are deemed too low. type VCS (<>) is new VCSs.VCS with private; function Handler return VCS; not overriding function Branch (This : VCS; Path : Directory_Path) return String; -- Returns the branch name of the repo checked out at Path. overriding function Clone (This : VCS; From : URL; Into : Directory_Path) return Outcome; not overriding function Clone (This : VCS; From : URL; Into : Directory_Path; Branch : String; Depth : Natural := 0) return Outcome; -- Specify a branch to check out after cloning. Branch may be "" for the -- default remote branch. For any Depth /= 0, apply --depth . A -- commit may be specified as From#Commit_Id not overriding function Remote_Commit (This : VCS; From : URL; Ref : String := "HEAD") return String; -- Returns the commit matching Ref by ls-remote. If none, returns "". If -- several match, Checked_Error. not overriding function Revision_Commit (This : VCS; Repo : Directory_Path; Rev : String) return String; -- Returns the commit for a revision, if the repository and revision -- (commit, tag, branch...) exist. Should be a no-op for a commit. not overriding function Is_Detached (This : VCS; Path : Directory_Path) return Boolean; -- Says if the repo checked out at Path is in a detached HEAD state. not overriding function Is_Repository (This : VCS; Path : Directory_Path) return Boolean; -- Check if a repo exists at Path not overriding function Remote (This : VCS; Path : Directory_Path; Checked : Boolean := True) return String; -- Retrieve current remote name (usually "origin"). If checked, raise -- Checked_Error when no remote configured. Otherwise, return ""; overriding function Update (This : VCS; Repo : Directory_Path) return Outcome; not overriding function Update (This : VCS; Repo : Directory_Path; Branch : String) return Outcome; -- Update and track Branch, if given. type States is (Dirty, -- Uncommitted local changes No_Remote, -- Clean, no remote configured Clean, -- Clean, up to date with remote Ahead); -- Clean, ahead of remote (needs pull) -- States we are interested in for publishing not overriding function Status (This : VCS; Repo : Directory_Path) return States; not overriding function Fetch_URL (This : VCS; Repo : Directory_Path; Origin : String := "origin"; Public : Boolean := True) return URL; -- Retrieve the "fetch" url of the given origin, or "" if no repo, no -- origin, or any other unforeseen circumstance. If Public, a git@github -- private URL is transformed into its equivalent https:// public URL. not overriding function Head_Commit (This : VCS; Repo : Directory_Path) return String; -- Obtain the currently checked out Rev in the repository not overriding function Get_Rel_Path_Inside_Repo (This : VCS; Dir : Directory_Path) return Relative_Path; -- Return the relative path from the VCSs root to Dir. Will raise if Dir is -- not a real dir or not actually inside a git repo. This is a wrapper on -- git rev-parse --show-prefix function Root (This : VCS) return Optional.Absolute_Path; -- Return the repo absolute root path, if in a repo; otherwise Empty. This -- is a wrapper on git rev-parse --show-toplevel function Transform_To_Public (Remote : String) return URL; -- For a Known_Transformable_Host, return the https:// equivalent of a -- git@... address. Otherwise return Remote unmodified. type Worktree_Data is record Worktree : Unbounded_Absolute_Path := +""; -- When not a git repo Head : Git_Commit := No_Commit; -- When not on a commit Branch : UString := +"detached"; -- When on detached head end record; function Worktree (This : VCS; Repo : Directory_Path) return Worktree_Data; -- Retrieve bundled info on a working repo; wraps `git worktree` private type VCS is new VCSs.VCS with null record; function Handler return VCS is (null record); use AAA.Strings; Known_Transformable_Hosts : constant AAA.Strings.Vector := Empty_Vector & "github.com" & "gitlab.com"; end Alire.VCSs.Git; alire-1.2.1/src/alire/alire-vcss-hg.adb000066400000000000000000000040371430264165500176200ustar00rootroot00000000000000with AAA.Strings; use AAA.Strings; with Alire.Directories; with Alire.OS_Lib.Subprocess; with Alire.Utils; use Alire.Utils; with Alire.OS_Lib; with Alire.Errors; with Alire.Utils.Tools; package body Alire.VCSs.Hg is ----------- -- Clone -- ----------- overriding function Clone (This : VCS; From : URL; Into : Directory_Path) return Outcome is pragma Unreferenced (This); Extra : constant Vector := Empty_Vector & (if Log_Level < Trace.Info then "-q" else "-v"); Commit_Arg : constant Vector := (if Commit (From) /= "" then Empty_Vector & "-u" & Commit (From) else Empty_Vector); begin -- Make sure hg is installed Utils.Tools.Check_Tool (Utils.Tools.Mercurial); Trace.Detail ("Checking out [hg]: " & From); OS_Lib.Subprocess.Checked_Spawn ("hg", Empty_Vector & "clone" & "-y" & Commit_Arg & Extra & Repo (From) & Into); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Clone; ------------ -- Update -- ------------ overriding function Update (This : VCS; Repo : Directory_Path) return Outcome is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Repo)) with Unreferenced; Extra : constant Vector := Empty_Vector & (if Log_Level < Trace.Info then "-q" else "-v"); begin -- Make sure hg is installed Utils.Tools.Check_Tool (Utils.Tools.Mercurial); OS_Lib.Subprocess.Checked_Spawn ("hg", Empty_Vector & "pull" & "-u" & Extra); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Update; end Alire.VCSs.Hg; alire-1.2.1/src/alire/alire-vcss-hg.ads000066400000000000000000000010531430264165500176340ustar00rootroot00000000000000package Alire.VCSs.Hg is subtype Hg_Commit is String (1 .. 40); type VCS (<>) is new VCSs.VCS with private; function Handler return VCS; overriding function Clone (This : VCS; From : URL; Into : Directory_Path) return Outcome; overriding function Update (This : VCS; Repo : Directory_Path) return Outcome; private type VCS is new VCSs.VCS with null record; function Handler return VCS is (null record); end Alire.VCSs.Hg; alire-1.2.1/src/alire/alire-vcss-svn.adb000066400000000000000000000036211430264165500200260ustar00rootroot00000000000000with AAA.Strings; use AAA.Strings; with Alire.Directories; with Alire.OS_Lib.Subprocess; with Alire.Errors; with Alire.Utils.Tools; package body Alire.VCSs.SVN is ----------- -- Clone -- ----------- overriding function Clone (This : VCS; From : URL; Into : Directory_Path) return Outcome is pragma Unreferenced (This); Extra : constant Vector := (if Log_Level < Trace.Info then Empty_Vector & "-q" else Empty_Vector); Commit_Arg : constant Vector := (if Commit (From) /= "" then Empty_Vector & String'("-r" & Commit (From)) else Empty_Vector); begin Trace.Detail ("Checking out [svn]: " & From); -- Make sure svn is installed Utils.Tools.Check_Tool (Utils.Tools.Subversion); OS_Lib.Subprocess.Checked_Spawn ("svn", Empty_Vector & "checkout" & Extra & Repo (From) & Commit_Arg & Into); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Clone; ------------ -- Update -- ------------ overriding function Update (This : VCS; Repo : Directory_Path) return Outcome is pragma Unreferenced (This); Guard : Directories.Guard (Directories.Enter (Repo)) with Unreferenced; Extra : constant Vector := (if Log_Level < Trace.Info then Empty_Vector & "-q" else Empty_Vector); begin -- Make sure svn is installed Utils.Tools.Check_Tool (Utils.Tools.Subversion); OS_Lib.Subprocess.Checked_Spawn ("svn", Empty_Vector & "update" & Extra); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Update; end Alire.VCSs.SVN; alire-1.2.1/src/alire/alire-vcss-svn.ads000066400000000000000000000010021430264165500200360ustar00rootroot00000000000000package Alire.VCSs.SVN is type VCS (<>) is new VCSs.VCS with private; function Handler return VCS; overriding function Clone (This : VCS; From : URL; Into : Directory_Path) return Outcome; overriding function Update (This : VCS; Repo : Directory_Path) return Outcome; private type VCS is new VCSs.VCS with null record; function Handler return VCS is (null record); end Alire.VCSs.SVN; alire-1.2.1/src/alire/alire-vcss.adb000066400000000000000000000024361430264165500172250ustar00rootroot00000000000000with Alire.VCSs.Git; package body Alire.VCSs is use AAA.Strings; ----------- -- Clone -- ----------- function Clone (From : URL; Into : Directory_Path) return Outcome is begin case Kind (From) is when VCS_Git => return Git.Handler.Clone (Repo_And_Commit (From), Into); when VCS_Unknown => return Outcome_Failure ("Unknown VCS requested: " & From); end case; end Clone; ------------ -- Commit -- ------------ function Commit (Origin : URL) return String is (if Contains (Origin, "#") then Tail (Origin, '#') else ""); ---------- -- Kind -- ---------- function Kind (Origin : URL) return Kinds is (if Has_Prefix (Origin, "git+") then VCS_Git else VCS_Unknown); ---------- -- Repo -- ---------- function Repo (Origin : URL) return String is (Head (Repo_And_Commit (Origin), '#')); --------------------- -- Repo_And_Commit -- --------------------- function Repo_And_Commit (Origin : URL) return String is (if Contains (Origin, "+http") then Tail (Origin, '+') elsif Has_Prefix (Origin, "file://") then Origin (Origin'First + 7 .. Origin'Last) else Origin); end Alire.VCSs; alire-1.2.1/src/alire/alire-vcss.ads000066400000000000000000000023451430264165500172450ustar00rootroot00000000000000package Alire.VCSs is type VCS is interface; type Kinds is (VCS_Git, VCS_Unknown); subtype Known_Kinds is Kinds range Kinds'First .. Kinds'Pred (VCS_Unknown); -- URL format: -- vcs+http[s]://path/to/repo[#commit] function Clone (This : VCS; From : URL; Into : Directory_Path) return Outcome is abstract; function Update (This : VCS; Repo : Directory_Path) return Outcome is abstract; ----------------------- -- General utilities -- ----------------------- function Kind (Origin : URL) return Kinds; function Repo (Origin : URL) return String; -- Without kind and commit function Repo_And_Commit (Origin : URL) return String; -- Without Kind and with optional Commit (separated by #) function Commit (Origin : URL) return String; -- Empty string if no commit part (separated by #) ------------------------ -- Classwide versions -- ------------------------ -- Those redispatch to the appropriate descendant function Clone (From : URL; Into : Directory_Path) return Outcome with Pre => Kind (From) in Known_Kinds; end Alire.VCSs; alire-1.2.1/src/alire/alire-version.ads000066400000000000000000000017701430264165500177550ustar00rootroot00000000000000package Alire.Version with Preelaborate is -- Remember to update Alire.Index branch if needed too Current : constant String := "1.2.1"; -- 1.2.1: build switches fix and other minor assorted fixes -- 1.2.0: rpm speed-up, silence propagation warning, early switch parse -- 1.2.0-rc1: release candidate for 1.2 -- 1.1.2: latest msys2 and ensure it's fully updated -- 1.1.1: fixes in #862 #866 #875 #876 -- 1.1.0: toolchain compatibility checks -- 1.1.0-rc3: toolchain with multiple switches, minor fixes -- 1.1.0-rc2: toolchain non-interactive, lockfile under alire -- 1.1.0-rc1: crate config, toolchains, manifest pins -- 1.1.0-dev: begin post-1.0 changes -- 1.0.0: no changes since rc3 -- 1.0.0-rc3: added help colors PR -- 1.0.0-rc2: move community index to stable-1.0 branch -- 1.0.0-rc1: release candidate for 1.0 -- 0.8.1-dev: update to devel-0.5 index branch -- 0.8.0-dev: post-0.7-beta changes end Alire.Version; alire-1.2.1/src/alire/alire-vfs.adb000066400000000000000000000050071430264165500170420ustar00rootroot00000000000000with Ada.Directories; package body Alire.VFS is ---------------------- -- Attempt_Portable -- ---------------------- function Attempt_Portable (Path : Any_Path; From : Any_Path := Directories.Current) return String is Relative : constant Any_Path := Directories.Find_Relative_Path (Parent => From, Child => Path); begin if Check_Absolute_Path (Relative) then return Path; else return String (To_Portable (Relative)); end if; end Attempt_Portable; -------------- -- Read_Dir -- -------------- function Read_Dir (Dir : Virtual_File; Filter : Read_Dir_Filter := All_Files; Special : Boolean := True) return Virtual_File_Vector is Files : GNATCOLL.VFS.File_Array_Access := Dir.Read_Dir (GNATCOLL.VFS.Read_Dir_Filter (Filter)); begin return Contents : Virtual_File_Vector do Contents.Reserve_Capacity (Files'Length); for File of Files.all loop if Special or else (File.Base_Name /= "." and then File.Base_Name /= "..") then Contents.Append (File); end if; end loop; GNATCOLL.VFS.Unchecked_Free (Files); end return; end Read_Dir; ----------------- -- Simple_Name -- ----------------- function Simple_Name (File : Virtual_File) return Filesystem_String is (if File.Is_Directory then File.Base_Dir_Name else File.Base_Name); ----------------- -- Is_Same_Dir -- ----------------- function Is_Same_Dir (P1, P2 : Any_Path) return Boolean is use GNAT.OS_Lib; begin if not Is_Directory (P1) or else not Is_Directory (P2) then return False; end if; -- Attempt a lest costly check first declare use Ada.Directories; begin if Full_Name (P1) = Full_Name (P2) then return True; end if; end; -- To be absolutely sure, touch a temp file in one of the dirs and -- verify whether it exist in the other. declare Tmp : constant Directories.Temp_File := Directories.In_Dir (P1); use Directories.Operators; begin Directories.Touch (Tmp.Filename); return Is_Regular_File (P2 / Ada.Directories.Simple_Name (Tmp.Filename)); end; end Is_Same_Dir; end Alire.VFS; alire-1.2.1/src/alire/alire-vfs.ads000066400000000000000000000076421430264165500170720ustar00rootroot00000000000000with Ada.Containers.Vectors; with Alire.Directories; private with GNATCOLL.OS.Constants; with GNATCOLL.VFS; with AAA.Strings; use AAA.Strings; package Alire.VFS is -- Portable paths are relative and use forward slashes. Absolute paths -- cannot be portable. function Is_Portable (Path : Any_Path) return Boolean; -- Say if the path may be safely cast to a portable path function Attempt_Portable (Path : Any_Path; From : Any_Path := Directories.Current) return String; -- If Path seen from From is relative, convert to portable, else return -- as-is function To_Portable (Path : Relative_Path) return Portable_Path; function To_Native (Path : Portable_Path) return Relative_Path; -- Wrapper types on top of GNATCOLL.VFS that hide pointers/deallocations. -- Some types are renamed here to be able to rely on this spec without -- needing to mix both Alire.VFS and GNATCOLL.VFS. function Is_Same_Dir (P1, P2 : Any_Path) return Boolean; -- Check if two paths are to the same dir, even if they're given as -- different equivalent full paths in the filesystem (e.g., Windows -- short and long names). -- Basic types: subtype Filesystem_String is GNATCOLL.VFS.Filesystem_String; use type Filesystem_String; function From_FS (Str : String) return Filesystem_String renames GNATCOLL.VFS."+"; -- GNATCOLL deliberately makes names that come from disk a new type. If -- Ada.Directories had done the same our life would be easier; as things -- stand, mixing both requires explicitly converting string types. "+" -- seems to defeat the purpose of having a separate type though. subtype Virtual_File is GNATCOLL.VFS.Virtual_File; function New_Virtual_File (Path : Filesystem_String) return Virtual_File is (GNATCOLL.VFS.Create (Path)); -- A virtual file is the portable wrapper over file/dir names, that may -- then exists or not on disk. -- Name retrieval function Simple_Name (File : Virtual_File) return Filesystem_String with Post => (if File.Is_Directory then Simple_Name'Result = File.Base_Dir_Name else Simple_Name'Result = File.Base_Name); -- Returns the last base name in a full path, independently of whether it -- is a file or a folder. There is nothing equivalent in GNATCOLL since for -- a dir, Base_Name will return "". This mimics Ada.Directories.Simple_Name -- Dir enumeration package Virtual_File_Vectors is new Ada.Containers.Vectors (Positive, GNATCOLL.VFS.Virtual_File, GNATCOLL.VFS."="); subtype Virtual_File_Vector is Virtual_File_Vectors.Vector; type Read_Dir_Filter is new GNATCOLL.VFS.Read_Dir_Filter; function Read_Dir (Dir : Virtual_File; Filter : Read_Dir_Filter := All_Files; Special : Boolean := True) return Virtual_File_Vector; -- As GNATCOLL's one, plus if not Special, omit "." and "..". private use all type GNATCOLL.OS.OS_Type; ----------------- -- Is_Portable -- ----------------- function Is_Portable (Path : Any_Path) return Boolean is ((for all Char of Path => Char /= '\') and then not Check_Absolute_Path (Path)); ----------------- -- To_Portable -- ----------------- function To_Portable (Path : Relative_Path) return Portable_Path is (case GNATCOLL.OS.Constants.OS is when MacOS | Unix => Portable_Path (Path), when Windows => Portable_Path (Replace (Path, "\", "/"))); --------------- -- To_Native -- --------------- function To_Native (Path : Portable_Path) return Relative_Path is (case GNATCOLL.OS.Constants.OS is when MacOS | Unix => Relative_Path (Path), when Windows => Relative_Path (Replace (String (Path), "/", "\"))); end Alire.VFS; alire-1.2.1/src/alire/alire-warnings.adb000066400000000000000000000013551430264165500200760ustar00rootroot00000000000000package body Alire.Warnings is Already_Emitted : AAA.Strings.Set; --------------- -- Warn_Once -- --------------- procedure Warn_Once (Text : String; Id : Warning_Id := ""; Level : Trace.Levels := Trace.Warning) is begin if Id = "" then Warn_Once (Text, Warning_Id (Text), Level); elsif not Already_Emitted.Contains (String (Id)) then Already_Emitted.Include (String (Id)); Trace.Log (Text, Level); end if; end Warn_Once; -------------------- -- Already_Warned -- -------------------- function Already_Warned (Id : Warning_Id) return Boolean is (Already_Emitted.Contains (String (Id))); end Alire.Warnings; alire-1.2.1/src/alire/alire-warnings.ads000066400000000000000000000013721430264165500201160ustar00rootroot00000000000000package Alire.Warnings with Preelaborate is -- TODO: thread-unsafe type Warning_Id is new String; procedure Warn_Once (Text : String; Id : Warning_Id := ""; Level : Trace.Levels := Trace.Warning); -- Emit a warning just once. If it has been already seen, do not warn -- again. ID is used to determine if a warning has already been emitted -- or, when not given, the actual warning text serves as the ID. function Already_Warned (Id : Warning_Id) return Boolean; -- Says if a warning has been already emitted in the current run ------------------ -- Defined Ids -- ------------------ Caret_Or_Tilde : constant Warning_Id := "caret or tilde"; end Alire.Warnings; alire-1.2.1/src/alire/alire.adb000066400000000000000000000164501430264165500162520ustar00rootroot00000000000000with AAA.Debug; with Alire.Errors; with Alire.Warnings; with Alire.Utils.TTY; with GNAT.IO; package body Alire is --------- -- "=" -- --------- overriding function "=" (L, R : Crate_Name) return Boolean is (AAA.Strings.To_Lower_Case (+L) = AAA.Strings.To_Lower_Case (+R)); --------- -- "<" -- --------- function "<" (L, R : Crate_Name) return Boolean is (AAA.Strings.To_Lower_Case (+L) < AAA.Strings.To_Lower_Case (+R)); ------------------------- -- Absolute_Path_Image -- ------------------------- function Absolute_Path_Image (Path : Alire.Absolute_Path) return String is (String (Path)); ------------------------- -- Check_Absolute_Path -- ------------------------- function Check_Absolute_Path (Path : Any_Path) return Boolean is separate; ------------- -- Err_Log -- ------------- -- Write given string to Standard_Error procedure Err_Log (S : String) is use GNAT.IO; begin Put_Line (Standard_Error, "stderr: " & S); end Err_Log; ------------------- -- Log_Exception -- ------------------- procedure Log_Exception (E : Ada.Exceptions.Exception_Occurrence; Level : Simple_Logging.Levels := Debug) is use Ada.Exceptions; Full_Msg : constant String := Errors.Get (E, Clear => False); -- Avoid consuming the message for good. begin Log ("---8<--- Exception dump begin ---8<---", Level); Log (Exception_Name (E), Level); Log (Full_Msg, Level); Log (Exception_Information (E), Level); Log ("--->8--- Exception dump end ----->8---", Level); if Log_Debug then Err_Log (Exception_Name (E)); Err_Log (Full_Msg); Err_Log (Exception_Information (E)); end if; end Log_Exception; ----------------- -- Put_Failure -- ----------------- procedure Put_Failure (Text : String; Level : Trace.Levels := Info) is begin Trace.Log (TTY.Text_With_Fallback (TTY.Error ("✗ "), "ERROR: ") & Text, Level); end Put_Failure; -------------- -- Put_Info -- -------------- procedure Put_Info (Text : String; Level : Trace.Levels := Info) is begin Trace.Log (TTY.Info (Text), Level); end Put_Info; ----------------- -- Put_Success -- ----------------- procedure Put_Success (Text : String; Level : Trace.Levels := Info) is begin Trace.Log (TTY.Success (Text), Level); end Put_Success; ----------------- -- Put_Warning -- ----------------- procedure Put_Warning (Text : String; Level : Trace.Levels := Info; Disable_Config : String := "") is begin Trace.Log (TTY.Text_With_Fallback (TTY.Warn ("âš  "), "warning: ") & Text, Level); if Disable_Config /= "" then Trace.Log (TTY.Text_With_Fallback (TTY.Warn ("âš  "), "warning: ") & "You can disable this warning with configuration key '" & TTY.Emph (Disable_Config) & "'", Level); end if; end Put_Warning; ------------ -- Assert -- ------------ procedure Assert (Result : Outcome'Class) is begin if not Result.Success then raise Checked_Error with Errors.Set (+Result.Message); end if; end Assert; ------------ -- Assert -- ------------ procedure Assert (Condition : Boolean; Or_Else : String) is begin if not Condition then Raise_Checked_Error (Msg => Or_Else); end if; end Assert; ------------------- -- Error_In_Name -- ------------------- function Error_In_Name (S : String) return String is Err : UString; use type UString; begin if S'Length < Min_Name_Length then Err := +"Identifier too short."; elsif S'Length > Max_Name_Length then Err := +"Identifier too long."; elsif S (S'First) = '_' then Err := +"Identifiers must not begin with an underscore."; elsif (for some C of S => C not in Crate_Character) then Err := +"Identifiers must be lowercase ASCII alphanumerical."; end if; if +Err /= "" then Err := Err & " You can see the complete identifier naming rules" & " with 'alr help identifiers'"; end if; return +Err; end Error_In_Name; ------------------- -- Is_Valid_Name -- ------------------- function Is_Valid_Name (S : String) return Boolean is (Error_In_Name (S) = ""); --------------- -- TTY_Image -- --------------- function TTY_Image (This : Crate_Name) return String is (Utils.TTY.Name (This)); --------------------- -- Outcome_Failure -- --------------------- function Outcome_Failure (Message : String; Report : Boolean := True) return Outcome is Stack : constant String := AAA.Debug.Stack_Trace; begin if Report then if Log_Debug then Err_Log ("Generating Outcome_Failure with message: " & Errors.Stack (Message)); Err_Log ("Generating Outcome_Failure with call stack:"); Err_Log (Stack); end if; Trace.Debug ("Generating Outcome_Failure with message: " & Errors.Stack (Message)); Trace.Debug ("Generating Outcome_Failure with call stack:"); Trace.Debug (Stack); end if; return (Success => False, Message => +Errors.Stack (Message)); end Outcome_Failure; ---------------------------- -- Outcome_From_Exception -- ---------------------------- function Outcome_From_Exception (Ex : Ada.Exceptions.Exception_Occurrence; Msg : String := "") return Outcome is Full_Msg : constant String := Errors.Get (Ex); begin Trace.Debug ("Failed Outcome because of exception: "); Trace.Debug (Full_Msg); Trace.Debug (Ada.Exceptions.Exception_Information (Ex)); if Log_Debug then Err_Log ("Failed Outcome because of exception: "); Err_Log (Full_Msg); Err_Log (Ada.Exceptions.Exception_Information (Ex)); end if; if Msg /= "" then return Outcome'(Success => False, Message => +Msg); else return Outcome'(Success => False, Message => +Full_Msg); end if; end Outcome_From_Exception; ------------------------- -- Raise_Checked_Error -- ------------------------- procedure Raise_Checked_Error (Msg : String) is begin if Log_Debug then Err_Log (Msg); end if; raise Checked_Error with Errors.Set (Msg); end Raise_Checked_Error; ----------------------- -- Recoverable_Error -- ----------------------- procedure Recoverable_Error (Msg : String; Recover : Boolean := Force) is Info : constant String := " (This error can be overridden with " & TTY.Terminal ("--force") & ".)"; begin if Msg'Length > 0 and then Msg (Msg'Last) /= '.' then Recoverable_Error (Msg & ".", Recover); return; end if; if Recover then Warnings.Warn_Once (Msg); else Raise_Checked_Error (Msg & Info); end if; end Recoverable_Error; end Alire; alire-1.2.1/src/alire/alire.ads000066400000000000000000000301661430264165500162730ustar00rootroot00000000000000with Ada.Exceptions; with Ada.Strings.Unbounded; pragma Warnings (Off, "no entities of * are referenced"); with AAA.Strings; pragma Unreferenced (AAA.Strings); -- AAA.Strings is used everywhere in Alire, so we make it with-visible for all -- units. pragma Warnings (On, "no entities of * are referenced"); pragma Warnings (Off); with GNAT.OS_Lib; pragma Warnings (On); with Simple_Logging; with CLIC.TTY; package Alire with Preelaborate is Checked_Error : exception; -- A Checked_Error is an explicitly diagnosed error condition, usually in -- relation with user inputs (e.g., parsing of TOML files or other inputs). -- Used internally in Alire in conjunction with Alire.Errors to use the -- normal exception mechanisms, that produce less boilerplate, while using -- Outcomes for results returned to clients. Query_Unsuccessful : exception; -- Raised by subprograms that return releases/dependencies when not -- found/impossible. Unimplemented : exception; -- Features that are known to be missing and scheduled for near future -- implementation. subtype URL is String; Min_Name_Length : constant := 3; Max_Name_Length : constant := 64; -- Github maximum is 100 and bitbucket 128, cargo is 64 and npm 50... Max_Description_Length : constant := 72; -- Git line recommendation (although it's 50 for subject line) Max_Tag_Length : constant := 15; -- Maximum length of a single element of the tags field -- package BStrings is new Ada.Strings.Bounded.Generic_Bounded_Length -- (Integer'Max (Max_Name_Length, Max_Description_Length)); Extension_Separator : constant Character := '.'; -- Refers to extension releases! Nothing to do with files -- Strings that are used quite generally package UStrings renames Ada.Strings.Unbounded; subtype UString is Ada.Strings.Unbounded.Unbounded_String; function "+" (S : String) return UString renames UStrings.To_Unbounded_String; function "+" (S : UString) return String renames UStrings.To_String; subtype Crate_Character is Character with Static_Predicate => Crate_Character in 'a' .. 'z' | '0' .. '9' | '_' | Extension_Separator; -------------------- -- Crate Naming -- -------------------- function Is_Valid_Name (S : String) return Boolean; function Error_In_Name (S : String) return String; -- Returns the problem with the crate name type Crate_Name (<>) is tagged private; overriding function "=" (L, R : Crate_Name) return Boolean; -- Crate names are case preserving but insensitive when compared. function "<" (L, R : Crate_Name) return Boolean; -- Likewise, we do not want capitalization to influence ordering. function Length (This : Crate_Name) return Positive; function As_String (This : Crate_Name) return String; function TTY_Image (This : Crate_Name) return String; function Index_Prefix (This : Crate_Name) return String with Post => Index_Prefix'Result'Length = 2; -- The two first letters in the crate name subtype Restricted_Name is String with Dynamic_Predicate => Restricted_Name'Length >= Min_Name_Length and then Restricted_Name (Restricted_Name'First) /= '_' and then (for all C of Restricted_Name => C in Crate_Character); -- A type used to limit some things that are given names by the user -- (e.g., remote index names). function "+" (P : Crate_Name) return String; function "+" (P : String) return Crate_Name; function To_Name (S : String) return Crate_Name renames "+"; subtype Description_String is String with Dynamic_Predicate => Description_String'Length <= Max_Description_Length; subtype Folder_String is String with Dynamic_Predicate => Folder_String'Length > 0 and then (for all C of Folder_String => C in 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | Extension_Separator); -- Used for cross-platform folder names subtype Any_Path is String; -- Base type for paths in Alire. These paths are always platform-dependent -- and can be used directly with filesystem functions. type Portable_Path is new String with Dynamic_Predicate => (for all Char of Portable_Path => Char /= '\'); -- A portable path always uses forward slashes. For use in the current -- platform, it should be adapted first. -- To clarify constants/functions declared herein: function Check_Absolute_Path (Path : Any_Path) return Boolean; -- Return True if the string Path represent an absolute path on the -- platform. subtype Directory_Path is Any_Path; subtype File_Path is Any_Path with Dynamic_Predicate => File_Path (File_Path'Last) /= GNAT.OS_Lib.Directory_Separator; subtype Absolute_File is Any_Path with Dynamic_Predicate => Check_Absolute_Path (Absolute_File) and then Absolute_File (Absolute_File'Last) /= GNAT.OS_Lib.Directory_Separator; -- Filenames with full path subtype Absolute_Path is Any_Path with Dynamic_Predicate => Check_Absolute_Path (Absolute_Path); function Absolute_Path_Image (Path : Absolute_Path) return String; -- Needed for later instantiations subtype Unbounded_Absolute_Path is UString with Dynamic_Predicate => +Unbounded_Absolute_Path = "" or else Check_Absolute_Path (+Unbounded_Absolute_Path); subtype Relative_File is Any_Path; -- Filenames with relative paths subtype Relative_Path is Any_Path; -- A relative path subtype Unbounded_Relative_Path is UString with Dynamic_Predicate => +Unbounded_Relative_Path = "" or else not Check_Absolute_Path (+Unbounded_Relative_Path); subtype Simple_File is String with Dynamic_Predicate => (for all C of Simple_File => C /= GNAT.OS_Lib.Directory_Separator); -- Filenames without path ---------------- -- Outcomes -- ---------------- type Outcome is tagged private; -- For operations that may fail as part of normal usage. -- Status -- function Message (Result : Outcome) return String with Pre => not Result.Success; -- Returns some information in case of unsuccessful Outcome function Success (Result : Outcome) return Boolean; -- Constructors -- function Outcome_Failure (Message : String; Report : Boolean := True) return Outcome with Pre => Message'Length > 0, Post => not Outcome_Failure'Result.Success; -- Calling this function generates a debug stack trace log, unless Report -- is set to False. For failures that are part of regular operation, -- this is recommended to avoid "scares" in the debug output. function Outcome_Success return Outcome with Post => Outcome_Success'Result.Success; function Outcome_From_Exception (Ex : Ada.Exceptions.Exception_Occurrence; Msg : String := "") return Outcome with Post => not Outcome_From_Exception'Result.Success; -- Create a failed Outcome when a exception has occurred. -- The exception stack trace will be dumped at debug level. -- If message is empty, message will be Ex exception message. ---------------------- -- Error generation -- ---------------------- Force : aliased Boolean := False; -- When True, recoverable errors are demoted to warnings and we keep going procedure Assert (Result : Outcome'Class); -- Does nothing for successful outcomes. Raises Checked_Error with the -- corresponding message set in Alire.Errors otherwise. procedure Assert (Condition : Boolean; Or_Else : String); -- Calls Raise_Checked_Error (Or_Else) when Condition is false procedure Raise_Checked_Error (Msg : String) with No_Return; -- For errors where we do not return an Outcome_Failure, we log an error -- message (Msg) and raise Checked_Error. There is no limitation on the -- length of Msg. procedure Recoverable_Error (Msg : String; Recover : Boolean := Force); -- When Recover, emit a warning and return normally. When not Recover call -- Raise_Checked_Error instead. --------------- -- LOGGING -- --------------- use all type Simple_Logging.Levels; package Trace renames Simple_Logging; package TTY renames CLIC.TTY; Log_Level : Simple_Logging.Levels renames Simple_Logging.Level; -- This one selects the verbosity level of the logging library. The usage -- of log levels in Alire is as follows. By default, no output is produced -- unless in case of warning or error. The log levels supported are: -- * ERROR: for fatal situations that preclude further operation. -- * Warning: for suspicious situations, but where alr continues normally. -- Hidden with '-q' switch. -- * Info: messages that are shown by default. Output that is the result -- of user requests in normal situations. -- * Detail: not shown by default, enabled with '-v' switch, that -- may be interesting to and intended for regular users. -- * Debug: not shown by default, enabled with '-vv' switch, messages -- intended for developers or curious users, not user friendly. function Detailed return Boolean; -- True when Log_Level is Detail or Debug Log_Debug : aliased Boolean := False; -- This one enables special debug output, irrespectively of the log level. procedure Log_Exception (E : Ada.Exceptions.Exception_Occurrence; Level : Simple_Logging.Levels := Debug); -- Feedback-oriented commands for one-line feedback with symbol prefix: procedure Put_Info (Text : String; Level : Trace.Levels := Info); -- Prepend Text with a blue "🛈", or "Note: " & if no color/tty. procedure Put_Warning (Text : String; Level : Trace.Levels := Info; Disable_Config : String := ""); -- Prepend Text with a yellow "âš ", or "Warning: " if no color/tty. If -- Disable_setting /= "", append a line informing about how to disable -- this warning. procedure Put_Success (Text : String; Level : Trace.Levels := Info); -- Prepend Text with a green check mark, or "Success:" if no color/tty. procedure Put_Failure (Text : String; Level : Trace.Levels := Info); -- Prepend Text with a red "✗", or "Failed:" if no color/tty. Intended as -- the opposite of Put_Success when it makes sense to continue, albeit -- briefly, without emitting a final error with Raise_Checked_Error. --------------- -- Constants -- --------------- GNAT_Crate : constant Crate_Name; GNAT_External_Crate : constant Crate_Name; GPRbuild_Crate : constant Crate_Name; private type Crate_Name (Len : Natural) is tagged record Name : String (1 .. Len); end record; function Length (This : Crate_Name) return Positive is (This.Len); function As_String (This : Crate_Name) return String is (This.Name); function Index_Prefix (This : Crate_Name) return String is (This.Name (This.Name'First .. This.Name'First + 1)); function "+" (P : Crate_Name) return String is (P.Name); function "+" (P : String) return Crate_Name is (if Is_Valid_Name (P) then (P'Length, P) else raise Checked_Error with Error_In_Name (P)); type Outcome is tagged record Success : Boolean := False; Message : Ada.Strings.Unbounded.Unbounded_String := +"Uninitialized Outcome"; end record; -- We cannot simultaneously be tagged and have default constraints; the -- small overhead of always having the Message member is the price to pay. function Message (Result : Outcome) return String is (+Result.Message); function Outcome_Success return Outcome is (Success => True, Message => +""); function Success (Result : Outcome) return Boolean is (Result.Success); function Detailed return Boolean is (Log_Level >= Detail); GNAT_Crate : constant Crate_Name := (Len => 4, Name => "gnat"); GPRbuild_Crate : constant Crate_Name := (Len => 8, Name => "gprbuild"); GNAT_External_Crate : constant Crate_Name := (Len => 13, Name => "gnat_external"); end Alire; alire-1.2.1/src/alire/alire_early_elaboration.adb000066400000000000000000000125041430264165500220210ustar00rootroot00000000000000with Ada.Text_IO; with Alire; with GNAT.Command_Line; with GNAT.OS_Lib; with Interfaces.C_Streams; with Simple_Logging.Filtering; package body Alire_Early_Elaboration is ---------------- -- Add_Scopes -- ---------------- procedure Add_Scopes (Debug_Arg : String) is -- Receives as-is the --debug/-d[ARG] argument. This is a list of -- optionally comma-separated, plus/minus prefixed substrings that will -- be used for filtering against the enclosing entity/source location. -- Example whitelisting argument: +commands,-search -- Example blacklisting argument: -commands,+search -- The first sign puts the filter in (-) blacklist / (+) whitelist mode. -- In whitelist mode, only the given substrings are logged, unless later -- added as exception. E.g., in the "+commands,-search" example, only -- commands traces would be logged (because of whitelist mode), except -- the ones for the search command (because given as an exception). -- In the "-commands,+search" example for blacklist mode, everything but -- command traces would be logged, but search command traces would be -- logged because that's the exception. -- Once scopes are used, we activate logging of enclosing entity and -- location to provide full logging information. begin if not Simple_Logging.Filtering.Add_From_String (Debug_Arg, Say => True) then -- Bypass debug channel, which was not entirely set up. -- Otherwise we get unwanted location/entity info already. Ada.Text_IO.Put_Line ("ERROR: Invalid logging filters."); GNAT.OS_Lib.OS_Exit (1); end if; end Add_Scopes; ---------------------------- -- Early_Switch_Detection -- ---------------------------- procedure Early_Switch_Detection is use GNAT.Command_Line; Subcommand_Seen : Boolean := False; -------------------- -- Check_Switches -- -------------------- procedure Check_Switches is ---------------------- -- Check_Long_Debug -- ---------------------- -- Take care manually of the -debug[ARG] optional ARG, since the -- simple Getopt below doesn't for us: procedure Check_Long_Debug (Switch : String) is Target : constant String := "--debug"; begin if Switch (Switch'First) /= '-' then Subcommand_Seen := True; elsif Switch'Length >= Target'Length and then Switch (Switch'First .. Switch'First + Target'Length - 1) = Target then Switch_D := True; Add_Scopes (Switch (Switch'First + Target'Length .. Switch'Last)); end if; end Check_Long_Debug; begin loop -- We use the simpler Getopt form to avoid built-in help and other -- shenanigans. case Getopt ("* d? --debug? q v c=") is when ASCII.NUL => exit; when '*' => if not Subcommand_Seen then Check_Long_Debug (Full_Switch); end if; when 'd' => if not Subcommand_Seen then Switch_D := True; Add_Scopes (Parameter); end if; when 'q' => if not Subcommand_Seen then Switch_Q := True; end if; when 'v' => if not Subcommand_Seen then if Switch_V and then not Switch_VV then Switch_VV := True; Switch_V := False; elsif not (Switch_V or else Switch_VV) then Switch_V := True; else Alire.Trace.Error ("Only one or two -v allowed"); GNAT.OS_Lib.OS_Exit (1); end if; end if; when others => null; end case; end loop; exception when Exit_From_Command_Line => -- Something unexpected happened but it will be properly dealt -- with later on, in the regular command-line parser. null; end Check_Switches; begin Check_Switches; -- Exclusivity check if (Switch_Q and Switch_V) or (Switch_Q and Switch_VV) then Alire.Trace.Error ("Use only one of -q or -v"); GNAT.OS_Lib.OS_Exit (1); end if; -- Level setting if Switch_VV then Alire.Log_Level := Simple_Logging.Debug; elsif Switch_V then Alire.Log_Level := Simple_Logging.Detail; elsif Switch_Q then Alire.Log_Level := Simple_Logging.Error; end if; -- Debug channel if Switch_D then Alire.Log_Debug := True; end if; end Early_Switch_Detection; ------------------- -- TTY_Detection -- ------------------- procedure TTY_Detection is use Interfaces.C_Streams; begin Simple_Logging.Is_TTY := isatty (fileno (stdout)) /= 0; end TTY_Detection; begin TTY_Detection; Early_Switch_Detection; end Alire_Early_Elaboration; alire-1.2.1/src/alire/alire_early_elaboration.ads000066400000000000000000000015621430264165500220440ustar00rootroot00000000000000with Ada.Calendar; package Alire_Early_Elaboration with Elaborate_Body is -- This body should be elaborated among the first ones. -- For anything requiring early elaboration (e.g. logging setup) -- Not directly a child of Alire to avoid circularity -- Logging in alire works in two separate channels: -- The -q, (none), -v and -vv switches allow to select one of the normal -- verbosity levels: quiet, normal, verbose, detail. -- OTOH, the -d/--debug switch enables logging of all unexpected exceptions -- to stderr independently of the verbosity level. Switch_D : aliased Boolean := False; -- For the debugging channel. Switch_Q, Switch_V, Switch_VV : aliased Boolean := False; -- For the verbosity level. Start : constant Ada.Calendar.Time := Ada.Calendar.Clock; -- Out of curiosity end Alire_Early_Elaboration; alire-1.2.1/src/alire/obsolete/000077500000000000000000000000001430264165500163145ustar00rootroot00000000000000alire-1.2.1/src/alire/obsolete/alire-dependencies-vectors.ads000066400000000000000000000034701430264165500242140ustar00rootroot00000000000000with Ada.Containers.Indefinite_Vectors; with Alire.Utils; package Alire.Dependencies.Vectors with Preelaborate is -- Dependencies are a plain list (vector) of individual dependencies -- There's nothing preventing giving version sets on the same project as distinct dependencies package Dependency_Vectors is new Ada.Containers.Indefinite_Vectors (Positive, Dependency); type Vector is new Dependency_Vectors.Vector with private; function Image_One_Line (V : Vector) return String; function No_Dependencies return Vector; -- Creation of dependency vectors function New_Dependency (Name : Names; Versions : Semantic_Versioning.Version_Set) return Vector; function "and" (Dep1, Dep2 : Vector) return Vector is (Dep1 & Dep2); private type Vector is new Dependency_Vectors.Vector with null record; -- New type so the "and" function is primitive function No_Dependencies return Vector is (Dependency_Vectors.Empty_Vector with null record); -------------------- -- New_Dependency -- -------------------- function New_Dependency (Name : Names; Versions : Semantic_Versioning.Version_Set) return Vector is (To_Vector ((Name'Length, Name, Versions), 1)); -------------------- -- Image_One_Line -- -------------------- package Non_Primitives is function Image_One_Line_Instance is new Utils.Image_One_Line (Dependency_Vectors, Vector, Image, " and ", "(no dependencies"); end Non_Primitives; function Image_One_Line (V : Vector) return String renames Non_Primitives.Image_One_Line_Instance; end Alire.Dependencies.Vectors; alire-1.2.1/src/alire/obsolete/alire-platform.adb000066400000000000000000000014361430264165500217060ustar00rootroot00000000000000with Ada.Containers.Indefinite_Holders; package body Alire.Platform is package Holders is new Ada.Containers.Indefinite_Holders (Supported_Platform'Class); This : Holders.Holder; type Unsupported_Platform is new Supported_Platform with null record; overriding function Package_Version (P : Unsupported_Platform; Origin : Origins.Origin) return String is (""); ------------- -- Current -- ------------- function Current return Supported_Platform'Class is (if This.Is_Empty then Unsupported_Platform'(Supported_Platform with null record) else This.Element); ------------------ -- Set_Platform -- ------------------ procedure Set (P : Supported_Platform'Class) is begin This.Replace_Element (P); end Set; end Alire.Platform; alire-1.2.1/src/alire/obsolete/alire-platform.ads000066400000000000000000000012141430264165500217210ustar00rootroot00000000000000with Alire.Origins; package Alire.Platform with Preelaborate is -- This interface encapsulates what a supported platform must provide for use in Alire, and a way -- to hook it after elaboration type Supported_Platform is interface; function Package_Version (P : Supported_Platform; Origin : Origins.Origin) return String is abstract; procedure Set (P : Supported_Platform'Class); function Current return Supported_Platform'Class with Pre => Platform'Elaborated; -- Always valid, because at worst a dummy do-nothign one is returned end Alire.Platform; alire-1.2.1/src/alire/obsolete/alire-properties-dependencies.ads000066400000000000000000000032741430264165500247250ustar00rootroot00000000000000with Alire.Dependencies.Vectors; with Alire.Properties; package Alire.Properties.Dependencies with Preelaborate is type Availability_Checker is new Property with private; type Checker_Function is access function (Dependencies : Alire.Dependencies.Vectors.Vector) return Boolean; -- The platform-bound function that says if a dependency is available -- Currently, Alr.Query.Is_Resolvable function New_Property (Checker : Checker_Function; Props : Properties.Vector) return Vector; function Checker (This : Availability_Checker) return Checker_Function; function Properties (This : Availability_Checker) return Properties.Vector; -- Contained platform properties private type Availability_Checker is new Property with record Checker : Checker_Function; -- Needed to check resolution Properties : Alire.Properties.Vector; -- Needed to materialize the conditional dependencies end record; overriding function Image (This : Availability_Checker) return String is ("Availability_Resolver"); function New_Property (Checker : Checker_Function; Props : Alire.Properties.Vector) return Vector is (+Availability_Checker'(Checker => Checker, Properties => Props)); function Checker (This : Availability_Checker) return Checker_Function is (This.Checker); function Properties (This : Availability_Checker) return Alire.Properties.Vector is (This.Properties); -- FIXME currently there is no recursivity detection so mutually dependent packages will enter infinite loop end Alire.Properties.Dependencies; alire-1.2.1/src/alire/os_freebsd/000077500000000000000000000000001430264165500166135ustar00rootroot00000000000000alire-1.2.1/src/alire/os_freebsd/alire-check_absolute_path.adb000066400000000000000000000003431430264165500243440ustar00rootroot00000000000000separate (Alire) function Check_Absolute_Path (Path : Any_Path) return Boolean is begin return (Path'Length >= 1 and then Path (Path'First) = GNAT.OS_Lib.Directory_Separator); end Check_Absolute_Path; alire-1.2.1/src/alire/os_freebsd/alire-platforms-current__freebsd.adb000066400000000000000000000014561430264165500257030ustar00rootroot00000000000000 package body Alire.Platforms.Current is -- FreeBSD implementation (very close to Linux) --------------------------- -- Detected_Distribution -- --------------------------- function Detected_Distribution return Platforms.Distributions is (Platforms.Distro_Unknown); ----------------------- -- Distribution_Root -- ----------------------- function Distribution_Root return Absolute_Path is ("/"); ---------------------- -- Load_Environment -- ---------------------- procedure Load_Environment (Ctx : in out Alire.Environment.Context) is null; ---------------------- -- Operating_System -- ---------------------- function Operating_System return Alire.Platforms.Operating_Systems is (Alire.Platforms.FreeBSD); end Alire.Platforms.Current; alire-1.2.1/src/alire/os_freebsd/alire-platforms-folders__freebsd.adb000066400000000000000000000005361430264165500256550ustar00rootroot00000000000000with Alire.Platforms.Common; package body Alire.Platforms.Folders is -- Linux implementation ----------- -- Cache -- ----------- function Cache return String is (Common.XDG_Config_Folder); ----------- -- Config-- ----------- function Config return String is (Common.XDG_Config_Folder); end Alire.Platforms.Folders; alire-1.2.1/src/alire/os_linux/000077500000000000000000000000001430264165500163405ustar00rootroot00000000000000alire-1.2.1/src/alire/os_linux/alire-check_absolute_path.adb000066400000000000000000000003431430264165500240710ustar00rootroot00000000000000separate (Alire) function Check_Absolute_Path (Path : Any_Path) return Boolean is begin return (Path'Length >= 1 and then Path (Path'First) = GNAT.OS_Lib.Directory_Separator); end Check_Absolute_Path; alire-1.2.1/src/alire/os_linux/alire-platforms-current__linux.adb000066400000000000000000000104461430264165500251540ustar00rootroot00000000000000with AAA.Strings; use AAA.Strings; with GNAT.Regpat; package body Alire.Platforms.Current is -- Linux implementation --------------------------- -- Detected_Distribution -- --------------------------- OS_Identity_File : constant String := "/etc/os-release"; Cached_Distro : Alire.Platforms.Distributions; Distro_Cached : Boolean := False; function Detected_Distribution return Platforms.Distributions is use Alire.OS_Lib; begin if Distro_Cached then return Cached_Distro; elsif not GNAT.OS_Lib.Is_Regular_File (OS_Identity_File) then Trace.Debug ("Distribution identity file not found: " & OS_Identity_File); Distro_Cached := True; Cached_Distro := Distro_Unknown; return Cached_Distro; else declare Release : constant AAA.Strings.Vector := Subprocess.Checked_Spawn_And_Capture ("cat", Empty_Vector & OS_Identity_File); function Get_Os_Release_Value_For_Key (Key : String) return Alire.Platforms.Distributions is use GNAT.Regpat; -- Regexp accepting lines not starting with '#' like: -- key=value -- key='value' -- key='value1 value2' -- key="value" -- key="value1 value2" Regexp : constant Pattern_Matcher := Compile ("^" & Key & "=[""']?([^""']+)[""']?"); Matches : Match_Array (1 .. 1); begin for Line of Release loop declare Normalized : constant String := To_Lower_Case (Line); Values : AAA.Strings.Vector; begin Match (Regexp, Normalized, Matches); if Matches (1) /= No_Match then -- Generate Values from space separated items Values := Split ( Normalized (Matches (1).First .. Matches (1).Last), ' '); for Value of Values loop begin return Platforms.Distributions'Value (Value); exception when others => null; -- Not a known distro. end; end loop; end if; exception when others => null; -- Not a known distro. end; end loop; return Distro_Unknown; end Get_Os_Release_Value_For_Key; begin -- First try with id key Cached_Distro := Get_Os_Release_Value_For_Key (Key => "id"); -- If no supported distribution found, fallback to id_like key if Cached_Distro = Distro_Unknown then Trace.Debug ("Unknown distro for key 'id', falling back to 'id_like'"); Cached_Distro := Get_Os_Release_Value_For_Key (Key => "id_like"); end if; -- Still an unsupported distribution ? if Cached_Distro = Distro_Unknown then Trace.Debug ("Found unsupported distro: " & Release (1)); end if; Distro_Cached := True; return Cached_Distro; end; end if; exception when E : Checked_Error => Trace.Debug ("Unable to detect distribution:"); Log_Exception (E); return Distro_Unknown; end Detected_Distribution; ----------------------- -- Distribution_Root -- ----------------------- function Distribution_Root return Absolute_Path is ("/"); ---------------------- -- Load_Environment -- ---------------------- procedure Load_Environment (Ctx : in out Alire.Environment.Context) is null; ---------------------- -- Operating_System -- ---------------------- function Operating_System return Alire.Platforms.Operating_Systems is (Alire.Platforms.Linux); end Alire.Platforms.Current; alire-1.2.1/src/alire/os_linux/alire-platforms-folders__linux.adb000066400000000000000000000005361430264165500251270ustar00rootroot00000000000000with Alire.Platforms.Common; package body Alire.Platforms.Folders is -- Linux implementation ----------- -- Cache -- ----------- function Cache return String is (Common.XDG_Config_Folder); ----------- -- Config-- ----------- function Config return String is (Common.XDG_Config_Folder); end Alire.Platforms.Folders; alire-1.2.1/src/alire/os_macos/000077500000000000000000000000001430264165500163035ustar00rootroot00000000000000alire-1.2.1/src/alire/os_macos/alire-check_absolute_path.adb000066400000000000000000000003431430264165500240340ustar00rootroot00000000000000separate (Alire) function Check_Absolute_Path (Path : Any_Path) return Boolean is begin return (Path'Length >= 1 and then Path (Path'First) = GNAT.OS_Lib.Directory_Separator); end Check_Absolute_Path; alire-1.2.1/src/alire/os_macos/alire-platforms-current__macos.adb000066400000000000000000000013631430264165500250600ustar00rootroot00000000000000with Alire.OS_Lib; package body Alire.Platforms.Current is -- macOS implementation ------------------ -- Distribution -- ------------------ function Detected_Distribution return Platforms.Distributions is (Platforms.Distro_Unknown); ----------------------- -- Distribution_Root -- ----------------------- function Distribution_Root return Absolute_Path is ("/"); ---------------------- -- Load_Environment -- ---------------------- procedure Load_Environment (Ctx : in out Alire.Environment.Context) is null; ---------------------- -- Operating_System -- ---------------------- function Operating_System return Platforms.Operating_Systems is (MacOS); end Alire.Platforms.Current; alire-1.2.1/src/alire/os_macos/alire-platforms-folders__macos.adb000066400000000000000000000005361430264165500250350ustar00rootroot00000000000000with Alire.Platforms.Common; package body Alire.Platforms.Folders is -- macOS implementation ----------- -- Cache -- ----------- function Cache return String is (Common.XDG_Config_Folder); ----------- -- Config-- ----------- function Config return String is (Common.XDG_Config_Folder); end Alire.Platforms.Folders; alire-1.2.1/src/alire/os_windows/000077500000000000000000000000001430264165500166735ustar00rootroot00000000000000alire-1.2.1/src/alire/os_windows/alire-check_absolute_path.adb000066400000000000000000000007271430264165500244320ustar00rootroot00000000000000separate (Alire) function Check_Absolute_Path (Path : Any_Path) return Boolean is begin return (Path'Length >= 3 and then Path (Path'First) in 'A' .. 'Z' | 'a' .. 'z' and then Path (Path'First + 1) = ':' and then Path (Path'First + 2) in '\' | '/'); -- Even strictly speaking, smthg like C:/ can only be an absolute path that -- comes from some non-Windows native program (git from msys2 or the like). end Check_Absolute_Path; alire-1.2.1/src/alire/os_windows/alire-platforms-current__windows.adb000066400000000000000000000264231430264165500260440ustar00rootroot00000000000000with Ada.Directories; with GNAT.OS_Lib; with AAA.Strings; with Alire.Environment; with Alire.OS_Lib; use Alire.OS_Lib; with Alire.Config; with Alire.Config.Edit; with Alire.Platforms.Folders; with Alire.Errors; with GNATCOLL.VFS; with CLIC.User_Input; package body Alire.Platforms.Current is package Cfg renames Config; Default_Msys2_Installer : constant String := "msys2-x86_64-20220503.exe"; Default_Msys2_Installer_URL : constant String := "https://github.com/msys2/msys2-installer/releases/download/2022-05-03/" & Default_Msys2_Installer; -- Windows implementation Distrib_Detected : Boolean := False; Distrib : Platforms.Distributions := Platforms.Distro_Unknown; ------------------ -- Detect_Msys2 -- ------------------ function Detect_Msys2 return Boolean is use AAA.Strings; begin -- Try to detect if Msys2's pacman tool is already in path declare Unused : Vector; begin Unused := OS_Lib.Subprocess.Checked_Spawn_And_Capture ("pacman", Empty_Vector & ("-V"), Err_To_Out => True); return True; exception when others => null; end; return False; end Detect_Msys2; ----------------------- -- Detect_Msys2_Root -- ----------------------- function Detect_Msys2_Root return Absolute_Path is Result : constant String := OS_Lib.Subprocess.Locate_In_Path ("pacman"); begin if Result /= "" then return GNAT.OS_Lib.Normalize_Pathname (Ada.Directories.Containing_Directory (Result) / ".." / ".."); else Raise_Checked_Error ("Cannot locate pacman in msys2 distrib"); end if; end Detect_Msys2_Root; -------------------- -- Detect_Distrib -- -------------------- procedure Detect_Distrib is begin Distrib_Detected := True; if Detect_Msys2 then Distrib := Platforms.Msys2; return; end if; Distrib := Platforms.Distro_Unknown; end Detect_Distrib; ------------------ -- Distribution -- ------------------ function Detected_Distribution return Platforms.Distributions is begin if not Distrib_Detected then Detect_Distrib; end if; return Distrib; end Detected_Distribution; ----------------------- -- Distribution_Root -- ----------------------- function Distribution_Root return Absolute_Path is begin case Distribution is when Platforms.Msys2 => return Detect_Msys2_Root; when others => return OS_Lib.Getenv ("HOMEDRIVE"); end case; end Distribution_Root; ---------------------- -- Load_Environment -- ---------------------- procedure Load_Environment (Ctx : in out Alire.Environment.Context) is begin case Distribution is when Platforms.Msys2 => declare Root : constant Absolute_Path := Detect_Msys2_Root; begin Ctx.Append ("PATH", Root / "mingw64" / "bin", "msys2"); Ctx.Append ("PATH", Root / "usr" / "bin", "msys2"); Ctx.Append ("PATH", Root / "usr" / "local" / "bin", "msys2"); Ctx.Append ("LIBRARY_PATH", Root / "mingw64" / "lib", "msys2"); Ctx.Append ("C_INCLUDE_PATH", Root / "mingw64" / "include", "msys2"); end; when others => null; end case; end Load_Environment; ---------------------- -- Operating_System -- ---------------------- function Operating_System return Operating_Systems is (Windows); ------------------- -- Set_Msys2_Env -- ------------------- procedure Set_Msys2_Env (Install_Dir : Alire.Absolute_Path) is begin -- Change PATH to have msys2 binaries available (unzip, curl, git, etc.) Setenv ("PATH", Install_Dir / "usr" / "bin" & ";" & Install_Dir / "usr" / "local" / "bin" & ";" & Getenv ("PATH")); end Set_Msys2_Env; ---------------------------------- -- Query_User_For_Msys2_Install -- ---------------------------------- function Query_User_For_Msys2_Install (Install_Dir : Alire.Absolute_Path) return Boolean is use CLIC.User_Input; begin if Cfg.DB.Get (Cfg.Keys.Msys2_Do_Not_Install, False) then -- User already requested that msys2 should not be installed Trace.Detail ("Alire is configured not to install msys2."); Trace.Detail ("Run 'alr config --global --set msys2.do_not_install false'" & " if you want Alire to install msys2."); return False; end if; Trace.Always ("Alire can use the msys2 Windows system package" & " manager to provide easy install"); Trace.Always ("of tools (git, unzip, make, etc.) as well as" & " libraries (libsdl, libusb, etc.)"); Trace.Always ("The use of msys2 is recommend for a better user experience."); Trace.Always ("(msys2 will be installed in '" & Install_Dir & "')."); if Query ("Do you want Alire to install msys2? (recommended)", Valid => (Yes | No => True, others => False), Default => Yes) = Yes then -- We can install return True; else if Query ("Do you want Alire to remember this choice?", Valid => (Yes | No => True, others => False), Default => No) = Yes then -- Save user choice in the global config Cfg.Edit.Set_Globally (Key => Cfg.Keys.Msys2_Do_Not_Install, Value => "true"); end if; -- We are not allowed to install return False; end if; end Query_User_For_Msys2_Install; ------------------- -- Install_Msys2 -- ------------------- function Install_Msys2 (Install_Dir : Alire.Absolute_Path) return Alire.Outcome is use AAA.Strings; ------------------- -- Download_File -- ------------------- function Download_File (URL : String; Filename : Any_Path; Folder : Directory_Path) return Outcome is use GNATCOLL.VFS; Archive_File : constant Directory_Path := Folder / Ada.Directories.Simple_Name (Filename); begin Trace.Debug ("Creating folder: " & Folder); Create (+Folder).Make_Dir; Trace.Detail ("Downloading file: " & URL); OS_Lib.Subprocess.Checked_Spawn ("curl", Empty_Vector & URL & "--location" & -- allow for redirects at the remote host (if Log_Level < Trace.Info then Empty_Vector & "--silent" else Empty_Vector & "--progress-bar") & "--output" & Archive_File); return Outcome_Success; exception when E : others => return Alire.Errors.Get (E); end Download_File; Msys2_Installer : constant String := Cfg.DB.Get (Cfg.Keys.Msys2_Installer, Default_Msys2_Installer); Msys2_Installer_URL : constant String := Cfg.DB.Get (Cfg.Keys.Msys2_Installer_URL, Default_Msys2_Installer_URL); Result : Alire.Outcome; begin if not Query_User_For_Msys2_Install (Install_Dir) then -- User does not want to install msys2 return Alire.Outcome_Success; end if; Result := Download_File (Msys2_Installer_URL, Msys2_Installer, Install_Dir); if not Result.Success then return Result; end if; begin -- Run msys2's installer Alire.OS_Lib.Subprocess.Checked_Spawn (Install_Dir / Msys2_Installer, Empty_Vector & "in" & "--confirm-command" & "--accept-messages" & "--root" & Install_Dir); exception when others => return Alire.Outcome_Failure ("Cannot setup msys2 environment"); end; if not Cfg.DB.Defined (Cfg.Keys.Msys2_Install_Dir) then -- Save msys2 install dir in the global config Cfg.Edit.Set_Globally (Key => Cfg.Keys.Msys2_Install_Dir, Value => Install_Dir); end if; -- Load msys2 environment to attempt first full update according to -- official setup instructions. declare Default_Install_Dir : constant Alire.Absolute_Path := Platforms.Folders.Cache / "msys64"; Cfg_Install_Dir : constant String := Cfg.DB.Get (Cfg.Keys.Msys2_Install_Dir, Default_Install_Dir); begin Set_Msys2_Env (Cfg_Install_Dir); end; -- First update for the index and core packages Alire.OS_Lib.Subprocess.Checked_Spawn ("pacman", AAA.Strings.Empty_Vector & "--noconfirm" & "-Syu"); -- Second update for remaining packages Alire.OS_Lib.Subprocess.Checked_Spawn ("pacman", AAA.Strings.Empty_Vector & "--noconfirm" & "-Su"); return Alire.Outcome_Success; end Install_Msys2; ----------------- -- Setup_Msys2 -- ----------------- procedure Setup_Msys2 is Result : Alire.Outcome; Default_Install_Dir : constant Alire.Absolute_Path := Platforms.Folders.Cache / "msys64"; Cfg_Install_Dir : constant String := Cfg.DB.Get (Cfg.Keys.Msys2_Install_Dir, Default_Install_Dir); Pacman : constant String := Alire.OS_Lib.Subprocess.Locate_In_Path ("pacman"); begin if Pacman /= "" then -- pacman already in PATH, no need to install msys2 Set_Msys2_Env (GNAT.OS_Lib.Normalize_Pathname (Ada.Directories.Containing_Directory (Pacman) / ".." / "..")); return; end if; if not Alire.Check_Absolute_Path (Cfg_Install_Dir) then -- This error is recoverable as msys2 is not required for alr to -- work. Alire.Recoverable_Error ("Invalid absolute install path for msys2 in configuration:" & " '" & Cfg_Install_Dir & "'"); return; end if; -- Check if msys2 is already installed for Alire if not Ada.Directories.Exists (Cfg_Install_Dir) then -- Msys2 is not installed yet Result := Install_Msys2 (Cfg_Install_Dir); if not Result.Success then -- This error is recoverable as msys2 is not required for alr to -- work. Alire.Recoverable_Error (Message (Result)); return; end if; else -- Msys2 was already installed and we need to load its environment. -- Otherwise the installation procedure already has loaded it for the -- first update. -- Set the PATH and other environment variable for msys2 Set_Msys2_Env (Cfg_Install_Dir); end if; end Setup_Msys2; begin Setup_Msys2; end Alire.Platforms.Current; alire-1.2.1/src/alire/os_windows/alire-platforms-folders__windows.adb000066400000000000000000000007341430264165500260150ustar00rootroot00000000000000with Alire.OS_Lib; use Alire.OS_Lib; package body Alire.Platforms.Folders is ---------- -- Home -- ---------- function Home return String is (OS_Lib.Getenv ("HOMEDRIVE") & OS_Lib.Getenv ("HOMEPATH")); ----------- -- Cache -- ----------- function Cache return String is (Home / ".cache" / "alire"); ------------ -- Config -- ------------ function Config return String is (Home / ".config" / "alire"); end Alire.Platforms.Folders; alire-1.2.1/src/alr/000077500000000000000000000000001430264165500141625ustar00rootroot00000000000000alire-1.2.1/src/alr/README.md000066400000000000000000000000401430264165500154330ustar00rootroot00000000000000Command-line tool specific code alire-1.2.1/src/alr/alr-actions.adb000066400000000000000000000026331430264165500170520ustar00rootroot00000000000000with Ada.Tags; with Alire.Utils; with Alr.OS_Lib; with Alr.Platform; with Alr.Spawn; package body Alr.Actions is use Alire.Actions; ----------------- -- Execute_Run -- ----------------- procedure Execute_Run (This : Run) is use OS_Lib; use Alire.Utils; Guard : Folder_Guard (Enter_Folder (This.Working_Folder)) with Unreferenced; Cmd : constant AAA.Strings.Vector := This.Command_Line; Args : AAA.Strings.Vector := Cmd; begin Args.Delete_First; Alr.Spawn.Command (Cmd.First_Element, Args); end Execute_Run; ------------- -- Execute -- ------------- procedure Execute (This : Action'Class) is begin -- Manual dispatch forced by alr/alire split if This in Run'Class then Execute_Run (Run (This)); else raise Program_Error with "Unknown action class: " & Ada.Tags.External_Tag (This'Tag); end if; end Execute; --------------------- -- Execute_Actions -- --------------------- procedure Execute_Actions (R : Alire.Releases.Release; Moment : Moments) is begin for Act of R.On_Platform_Actions (Platform.Properties) loop if Action'Class (Act).Moment = Moment then Trace.Detail ("Running action: " & Act.Image); Action'Class (Act).Execute (Execute'Access); end if; end loop; end Execute_Actions; end Alr.Actions; alire-1.2.1/src/alr/alr-actions.ads000066400000000000000000000004741430264165500170740ustar00rootroot00000000000000with Alire.Actions; with Alire.Releases; package Alr.Actions is -- Implements executors for Alire.Actions procedure Execute (This : Alire.Actions.Action'Class); procedure Execute_Actions (R : Alire.Releases.Release; Moment : Alire.Actions.Moments); end Alr.Actions; alire-1.2.1/src/alr/alr-bootstrap.adb000066400000000000000000000006321430264165500174240ustar00rootroot00000000000000with Alire.Directories; with Alr.OS_Lib; with GNAT.Ctrl_C; package body Alr.Bootstrap is ----------------- -- Interrupted -- ----------------- procedure Interrupted is begin Trace.Always (" Interrupted by user"); Alire.Directories.Delete_Temporaries; OS_Lib.Bailout (1); end Interrupted; begin GNAT.Ctrl_C.Install_Handler (Interrupted'Access); end Alr.Bootstrap; alire-1.2.1/src/alr/alr-bootstrap.ads000066400000000000000000000001561430264165500174460ustar00rootroot00000000000000package Alr.Bootstrap with Elaborate_Body is -- Body contains the handler for Ctrl-C end Alr.Bootstrap; alire-1.2.1/src/alr/alr-commands-action.adb000066400000000000000000000122471430264165500204700ustar00rootroot00000000000000with AAA.Enum_Tools; with Alire.Dependencies.States; with Alire.Directories; with Alire.Properties.Actions.Executor; with Alire.Releases; with Alire.Solutions; with Alire.TOML_Adapters; package body Alr.Commands.Action is ------------------------- -- Build_Custom_String -- ------------------------- function Build_Custom_String return String is use Alire.Properties.Actions; ----------- -- Build -- ----------- function Build (Moment : Alire.Properties.Actions.Moments) return String is ((if Moment /= Moments'First then "|" else "") & AAA.Strings.To_Lower_Case (Moment'Image) & (if Moment = Moments'Pred (On_Demand) then "" else Build (Moments'Succ (Moment)))); begin return Build (Alire.Properties.Actions.Moments'First); end Build_Custom_String; ---------- -- List -- ---------- procedure List (Cmd : in out Command) is Some_Output : Boolean := False; -------------- -- List_One -- -------------- procedure List_One (This : in out Alire.Roots.Root; Solution : Alire.Solutions.Solution; State : Alire.Dependencies.States.State) is pragma Unreferenced (Solution, This); ------------------ -- List_Release -- ------------------ procedure List_Release (Rel : Alire.Releases.Release) is begin if not Rel.On_Platform_Actions (Cmd.Root.Environment).Is_Empty then Some_Output := True; Put_Line (Rel.Milestone.TTY_Image & ":"); for Action of Rel.On_Platform_Actions (Cmd.Root.Environment) loop Put_Line (" " & Action.Image); end loop; end if; end List_Release; begin if Cmd.Recursive or else State.Crate = Cmd.Root.Release.Name then if State.Has_Release then List_Release (State.Release); end if; end if; end List_One; begin Cmd.Root.Traverse (Doing => List_One'Access); if not Some_Output then Put_Line ("No actions."); end if; end List; --------- -- Run -- --------- procedure Run (Cmd : in out Command; Arg : String) is use Alire.Properties.Actions; Moment : Moments; Some_Output : Boolean := False; ------------- -- Run_One -- ------------- procedure Run_One (This : in out Alire.Roots.Root; Solution : Alire.Solutions.Solution; State : Alire.Dependencies.States.State) is pragma Unreferenced (Solution, This); ----------------- -- Run_Release -- ----------------- procedure Run_Release (Rel : Alire.Releases.Release) is Selected_Moment : Alire.Releases.Moment_Array := (others => False); use Alire.Directories; begin Selected_Moment (Moment) := True; if not Rel.On_Platform_Actions (Cmd.Root.Environment, Selected_Moment).Is_Empty then Some_Output := True; declare CWD : Guard (Enter (Cmd.Root.Release_Base (Rel.Name))) with Unreferenced; begin Alire.Properties.Actions.Executor.Execute_Actions (Rel, Env => Cmd.Root.Environment, Moment => Moment); end; end if; end Run_Release; begin if Cmd.Recursive or else State.Crate = Cmd.Root.Release.Name then if State.Has_Release then Run_Release (State.Release); end if; end if; end Run_One; subtype Valid_Moments is Moments range Moments'First .. Moments'Pred (On_Demand); function Is_Valid is new AAA.Enum_Tools.Is_Valid (Valid_Moments); begin if Is_Valid (Alire.TOML_Adapters.Adafy (Arg)) then Moment := Moments'Value (Alire.TOML_Adapters.Adafy (Arg)); else Reportaise_Wrong_Arguments ("Invalid action: " & Arg); end if; Cmd.Root.Traverse (Doing => Run_One'Access); if not Some_Output then Put_Line ("No actions to run."); end if; end Run; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is begin if Args.Is_Empty then Cmd.List; else for Arg of Args loop Cmd.Run (Arg); end loop; end if; end Execute; -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config => Config, Output => Cmd.Recursive'Access, Switch => "-r", Long_Switch => "--recursive", Help => "List or trigger actions also in dependencies"); end Setup_Switches; end Alr.Commands.Action; alire-1.2.1/src/alr/alr-commands-action.ads000066400000000000000000000021241430264165500205020ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Action is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("action"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("List or manually trigger action hooks.")); overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("List or manually trigger action hooks"); function Build_Custom_String return String; overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[" & Build_Custom_String & "]"); private type Command is new Commands.Command with record Recursive : aliased Boolean := False; end record; end Alr.Commands.Action; alire-1.2.1/src/alr/alr-commands-build.adb000066400000000000000000000060071430264165500203070ustar00rootroot00000000000000with Stopwatch; with Alire.Utils; with Alire.Utils.Switches; with Alire.Crate_Configuration; package body Alr.Commands.Build is ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is use Alire.Utils.Switches; begin if Alire.Utils.Count_True ((Cmd.Release_Mode, Cmd.Validation_Mode, Cmd.Dev_Mode)) > 1 then Reportaise_Wrong_Arguments ("Only one build mode can be selected"); end if; if Cmd.Release_Mode then Alire.Crate_Configuration.Root_Build_Profile := Release; elsif Cmd.Validation_Mode then Alire.Crate_Configuration.Root_Build_Profile := Validation; elsif Cmd.Dev_Mode then Alire.Crate_Configuration.Root_Build_Profile := Development; end if; if not Execute (Cmd, Args, Export_Build_Env => True) then Reportaise_Command_Failed ("Compilation failed."); end if; end Execute; ------------- -- Execute -- ------------- function Execute (Cmd : in out Commands.Command'Class; Args : AAA.Strings.Vector; Export_Build_Env : Boolean) return Boolean is begin Cmd.Requires_Full_Index; Cmd.Requires_Valid_Session; declare Timer : Stopwatch.Instance; begin if Cmd.Root.Build (Args, Export_Build_Env) then Trace.Info ("Build finished successfully in " & TTY.Bold (Timer.Image) & " seconds."); Trace.Detail ("Use alr run --list to check available executables"); return True; else return False; end if; end; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Invokes gprbuild to compile all targets in the current" & " crate.")); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Release_Mode'Access, "", "--release", "Set root crate build mode to Release"); Define_Switch (Config, Cmd.Validation_Mode'Access, "", "--validation", "Set root crate build mode to Validation"); Define_Switch (Config, Cmd.Dev_Mode'Access, "", "--development", "Set root crate build mode to Development (default)"); end Setup_Switches; end Alr.Commands.Build; alire-1.2.1/src/alr/alr-commands-build.ads000066400000000000000000000033701430264165500203300ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Build is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("build"); overriding function Switch_Parsing (This : Command) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Before_Double_Dash); -- For the build command we want the args after -- to pass them to gprbuild overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); function Execute (Cmd : in out Commands.Command'Class; Args : AAA.Strings.Vector; Export_Build_Env : Boolean) return Boolean; -- Returns True if compilation succeeded. For invocations after some other -- command that already has set up the build environment we need to avoid -- redoing it, or it results in "variable already set" errors. overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("GPRbuild current working release"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[--] [gprbuild switches and arguments]"); private type Command is new Commands.Command with record Release_Mode : aliased Boolean := False; Validation_Mode : aliased Boolean := False; Dev_Mode : aliased Boolean := False; end record; end Alr.Commands.Build; alire-1.2.1/src/alr/alr-commands-clean.adb000066400000000000000000000144321430264165500202730ustar00rootroot00000000000000with Ada.Directories; with Alire.Config.Edit; with Alire.Directories; with Alire.Paths; with Alire.Platforms.Current; with Alire.Spawn; package body Alr.Commands.Clean is ----------------------- -- Delete_Temp_Files -- ----------------------- procedure Delete_Temp_Files is Freed : Ada.Directories.File_Size := 0; ----------------- -- Freed_Image -- ----------------- function Freed_Image return String is ("freeing " & Alire.Directories.TTY_Image (Freed) & "."); ------------ -- Delete -- ------------ procedure Delete (Path : String) is use type Ada.Directories.File_Size; begin Trace.Detail ("Deleting " & Alire.TTY.URL (Path)); Freed := Freed + Alire.Directories.Tree_Size (Path); Alire.Directories.Force_Delete (Path); end Delete; Targets : AAA.Strings.Set; ---------------- -- Add_Target -- ---------------- procedure Add_Target (Item : Ada.Directories.Directory_Entry_Type; Unused_Stop : in out Boolean) is use Ada.Directories; use AAA.Strings; Name : constant String := Simple_Name (Item); begin if Has_Prefix (Name, "alr-") and then Has_Suffix (Name, ".tmp") then Targets.Include (Ada.Directories.Full_Name (Item)); end if; end Add_Target; begin -- Current workspace Alire.Directories.Traverse_Tree (Start => ".", Doing => Add_Target'Access, Recurse => True); -- Configuration-wide cache, where interrupted binary downloads dwell... Alire.Directories.Traverse_Tree (Start => Alire.Config.Edit.Path, Doing => Add_Target'Access, Recurse => True); for Target of Targets loop Delete (Target); end loop; if Targets.Is_Empty then Trace.Info ("No temporaries found."); elsif Targets.Length in 1 then Trace.Info ("Deleted " & TTY.Emph ("1") & " temporary, " & Freed_Image); else Trace.Info ("Deleted" & TTY.Emph (Targets.Length'Image) & " temporaries, " & Freed_Image); end if; end Delete_Temp_Files; ---------------- -- Find_Cache -- ---------------- -- Return the cache dir, or "" if not found function Find_Cache return String is use Ada.Directories; use Alire.Directories.Operators; Root : constant String := Alire.Directories.Detect_Root_Path; begin if Root /= "" then if Exists (Root / Alire.Paths.Working_Folder_Inside_Root / Alire.Paths.Cache_Folder_Inside_Working_Folder) then return Root / Alire.Paths.Working_Folder_Inside_Root / Alire.Paths.Cache_Folder_Inside_Working_Folder; end if; end if; return ""; end Find_Cache; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is use AAA.Strings; begin if not (Cmd.Cache or else Cmd.Temp) then Cmd.Requires_Valid_Session; Cmd.Root.Export_Build_Environment; Trace.Detail ("Cleaning project and dependencies..."); -- Clean all the project files for Gpr_File of Cmd.Root.Release.Project_Files (Alire.Platforms.Current.Properties, With_Path => True) loop Alire.Spawn.Command ("gprclean", Empty_Vector & "-r" & "-P" & Gpr_File & Args, Understands_Verbose => True); end loop; return; end if; if Args.Count /= 0 then Reportaise_Wrong_Arguments (Cmd.Name & " doesn't take arguments"); end if; if Cmd.Cache then -- We do not want to use Cmd.Root here, as it will check for a valid -- root, in turn deploying any missing dependencies (which we want to -- delete). This might result in that running two `alr clean --cache` -- in a row would redownload everything, and delete it again. So we -- go lower level and use more basic parts of Alire. declare Cache_Dir : constant String := Find_Cache; begin if Cache_Dir /= "" then Trace.Detail ("Deleting working copy cache..."); Alire.Directories.Force_Delete (Cache_Dir); Trace.Info ("Cache folder deleted."); else Trace.Info ("Cache folder not present."); -- This is expected if the crate has no dependencies end if; end; end if; if Cmd.Temp then Delete_Temp_Files; end if; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("no options:") .Append (" gprclean -r will be called to clean up the" & " build environment.") .New_Line .Append ("--cache:") .Append (" All downloaded dependencies will be deleted.") .New_Line .Append ("--temp:") .Append (" All alr-???.tmp files in the subtree will be deleted." & " These files may remain when alr is interrupted via" & " Ctrl-C or other forceful means.") ); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Cache'Access, Long_Switch => "--cache", Help => "Delete cache of releases"); Define_Switch (Config, Cmd.Temp'Access, Long_Switch => "--temp", Help => "Delete dangling temporary files"); end Setup_Switches; end Alr.Commands.Clean; alire-1.2.1/src/alr/alr-commands-clean.ads000066400000000000000000000024221430264165500203100ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Clean is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("clean"); overriding function Switch_Parsing (This : Command) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Before_Double_Dash); -- For the clean command we want the args after -- to pass them to gprclean overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("GPRclean working release and manage cached releases"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[--cache] [--temp] [--] [gprclean switches and arguments]"); private type Command is new Commands.Command with record Cache : aliased Boolean := False; Temp : aliased Boolean := False; end record; end Alr.Commands.Clean; alire-1.2.1/src/alr/alr-commands-config.adb000066400000000000000000000164361430264165500204640ustar00rootroot00000000000000with CLIC.Config.Info; with CLIC.Config.Edit; with Alire.Config; with Alire.Config.Edit; with Alire.Root; package body Alr.Commands.Config is ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is Enabled : Natural := 0; Lvl : constant Alire.Config.Level := (if Cmd.Global then Alire.Config.Global else Alire.Config.Local); begin -- Check no multi-action Enabled := Enabled + (if Cmd.List then 1 else 0); Enabled := Enabled + (if Cmd.Get then 1 else 0); Enabled := Enabled + (if Cmd.Set then 1 else 0); Enabled := Enabled + (if Cmd.Unset then 1 else 0); Enabled := Enabled + (if Cmd.Builtins_Doc then 1 else 0); if Enabled > 1 then Reportaise_Wrong_Arguments ("Specify at most one subcommand"); end if; if Enabled = 0 then -- The default command is --list Cmd.List := True; end if; if Cmd.Show_Origin and then not Cmd.List then Reportaise_Wrong_Arguments ("--show-origin only valid with --list"); end if; if Cmd.Builtins_Doc then Alire.Config.Edit.Print_Builtins_Doc; return; end if; if not Cmd.Global and then not Alire.Root.Current.Is_Valid then Reportaise_Command_Failed ("Not in an Alire project directory." & " Use --global to edit the global configuration."); end if; if Cmd.List then case Args.Count is when 0 => Trace.Always (CLIC.Config.Info.List (Alire.Config.DB, Filter => ".*", Show_Origin => Cmd.Show_Origin).Flatten (ASCII.LF)); when 1 => Trace.Always (CLIC.Config.Info.List (Alire.Config.DB, Filter => Args.First_Element, Show_Origin => Cmd.Show_Origin).Flatten (ASCII.LF)); when others => Reportaise_Wrong_Arguments ("List expects at most one argument"); end case; elsif Cmd.Get then if Args.Count /= 1 then Reportaise_Wrong_Arguments ("Unset expects one argument"); end if; if not CLIC.Config.Is_Valid_Config_Key (Args.First_Element) then Reportaise_Wrong_Arguments ("Invalid configuration key '" & Args.First_Element & "'"); end if; if Alire.Config.DB.Defined (Args.First_Element) then Trace.Always (Alire.Config.DB.Get_As_String (Args.First_Element)); else Reportaise_Command_Failed ("Configuration key '" & Args.First_Element & "' is not defined"); end if; elsif Cmd.Set then if Args.Count /= 2 then Reportaise_Wrong_Arguments ("Set expects two arguments"); end if; declare Key : constant String := Args.Element (1); Val : constant String := Args.Element (2); begin if not CLIC.Config.Is_Valid_Config_Key (Key) then Reportaise_Wrong_Arguments ("Invalid configuration key '" & Key & "'"); end if; Alire.Config.Edit.Set (Lvl, Key, Val, Check => Alire.Config.Edit.Valid_Builtin'Access); end; elsif Cmd.Unset then if Args.Count /= 1 then Reportaise_Wrong_Arguments ("Unset expects one argument"); end if; declare Key : constant String := Args.Element (1); begin if not CLIC.Config.Is_Valid_Config_Key (Key) then Reportaise_Wrong_Arguments ("Invalid configuration key '" & Key & "'"); end if; if not CLIC.Config.Edit.Unset (Alire.Config.Edit.Filepath (Lvl), Key) then Reportaise_Command_Failed ("Cannot unset config key"); end if; end; end if; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Provides a command line interface to the Alire configuration" & " option files.") .New_Line .Append ("Option names (keys) can use lowercase and uppercase" & " alphanumeric characters") .Append ("from the Latin alphabet. Underscores and dashes can also be" & " used except as") .Append ("first or last character. Dot '.' is used to specify" & " sub-categories, e.g.") .Append ("'user.name' or 'user.email'.") .New_Line .Append ("Option values can be integers, float, Boolean (true or" & " false) or strings. The") .Append ("type detection is automatic, e.g. 10 is integer, 10.1 is" & " float, true is") .Append ("Boolean. You can force a value to be set a string by using" & " double-quotes, e.g.") .Append ("""10.1"" or ""true"". Extra type checking is used for" & " built-in options (see below).") .New_Line .Append ("Built-in configuration options:") .New_Line .Append (Alire.Config.Edit.Builtins_Info)); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config => Config, Output => Cmd.List'Access, Long_Switch => "--list", Help => "List configuration options"); Define_Switch (Config => Config, Output => Cmd.Show_Origin'Access, Long_Switch => "--show-origin", Help => "Show origin of configuration values in --list"); Define_Switch (Config => Config, Output => Cmd.Get'Access, Long_Switch => "--get", Help => "Print value of a configuration option"); Define_Switch (Config => Config, Output => Cmd.Set'Access, Long_Switch => "--set", Help => "Set a configuration option"); Define_Switch (Config => Config, Output => Cmd.Unset'Access, Long_Switch => "--unset", Help => "Unset a configuration option"); Define_Switch (Config => Config, Output => Cmd.Global'Access, Long_Switch => "--global", Help => "Set and Unset global configuration instead" & " of the local one"); Define_Switch (Config => Config, Output => Cmd.Builtins_Doc'Access, Long_Switch => "--builtins-doc", Help => "Print Markdown list of built-in configuration options"); end Setup_Switches; end Alr.Commands.Config; alire-1.2.1/src/alr/alr-commands-config.ads000066400000000000000000000025221430264165500204740ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Config is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("config"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("List, Get, Set or Unset configuration options"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[--list] [--show-origin] [key_regex] |" & " --get |" & " --set |" & " --unset "); private type Command is new Commands.Command with record Show_Origin : aliased Boolean := False; List : aliased Boolean := False; Get : aliased Boolean := False; Set : aliased Boolean := False; Unset : aliased Boolean := False; Global : aliased Boolean := False; Builtins_Doc : aliased Boolean := False; end record; end Alr.Commands.Config; alire-1.2.1/src/alr/alr-commands-dev.adb000066400000000000000000000040621430264165500177650ustar00rootroot00000000000000with Alire.Selftest; package body Alr.Commands.Dev is ------------ -- Custom -- ------------ procedure Custom is begin null; end Custom; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is begin if Args.Count /= 0 then Reportaise_Wrong_Arguments (Cmd.Name & " doesn't take arguments"); end if; if Cmd.Custom then Custom; end if; if Cmd.Filtering then Trace.Debug ("In dev --filter"); end if; if Cmd.Raise_Except then raise Program_Error with "Raising forcibly"; end if; if Cmd.Self_Test then Alire.Selftest.Run; end if; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Internal command for development help. Options and features" & " are not stable and may change without warning.")); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Custom'Access, "", "--custom", "Execute current custom code"); Define_Switch (Config, Cmd.Filtering'Access, "", "--filter", "Used by scope filtering test"); Define_Switch (Config, Cmd.Raise_Except'Access, "", "--raise", "Raise an exception"); Define_Switch (Config, Cmd.Self_Test'Access, "", "--test", "Run self-tests"); end Setup_Switches; end Alr.Commands.Dev; alire-1.2.1/src/alr/alr-commands-dev.ads000066400000000000000000000021331430264165500200030ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Dev is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("dev"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Developer helpers"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is (""); private type Command is new Commands.Command with record Custom : aliased Boolean := False; -- Custom code to run instead Filtering : aliased Boolean := False; -- Runs debug scope filtering Raise_Except : aliased Boolean := False; Self_Test : aliased Boolean := False; end record; end Alr.Commands.Dev; alire-1.2.1/src/alr/alr-commands-edit.adb000066400000000000000000000111761430264165500201400ustar00rootroot00000000000000with Ada.Containers; with Alire; use Alire; with Alire.Config; with Alire.OS_Lib.Subprocess; with Alire.Platforms.Current; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package body Alr.Commands.Edit is ------------------ -- Start_Editor -- ------------------ procedure Start_Editor (Args : in out AAA.Strings.Vector; Prj : Relative_Path) is Pattern : constant String := "${GPR_FILE}"; Cmd : constant String := Args.First_Element; Replaced_Args : AAA.Strings.Vector; begin Args.Delete_First; for Elt of Args loop -- Replace pattern in Elt, if any declare Us : Unbounded_String := +Elt; Index : Natural; begin Index := Ada.Strings.Unbounded.Index (Us, Pattern); if Index /= 0 then Replace_Slice (Us, Low => Index, High => Index + Pattern'Length - 1, By => Prj); end if; Replaced_Args.Append (+Us); end; end loop; Trace.Info ("Editing crate with: ['" & Cmd & "' '" & AAA.Strings.Flatten (Replaced_Args, "', '") & "']"); Alire.OS_Lib.Subprocess.Checked_Spawn (Cmd, Replaced_Args); end Start_Editor; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is use Ada.Containers; use GNAT.Strings; use Alire.Config; Editor_Cmd : constant String := Alire.Config.DB.Get (Keys.Editor_Cmd, "gnatstudio -P ${GPR_FILE}"); Edit_Args : AAA.Strings.Vector := AAA.Strings.Split (Editor_Cmd, ' '); begin if Args.Count /= 0 then Reportaise_Wrong_Arguments (Cmd.Name & " doesn't take arguments"); end if; if Edit_Args.Is_Empty then Reportaise_Command_Failed ("No editor defined in config key '" & Keys.Editor_Cmd & "'."); end if; Cmd.Requires_Full_Index; Cmd.Requires_Valid_Session; Cmd.Root.Export_Build_Environment; declare Exec : constant String := Edit_Args.First_Element; begin if Alire.OS_Lib.Subprocess.Locate_In_Path (Exec) = "" then if Exec = "gnatstudio" or else Exec = "gnatstudio.exe" then Reportaise_Command_Failed ("GNAT Studio not available or not in PATH. " & ASCII.LF & "You can download it at: " & ASCII.LF & "https://github.com/AdaCore/gnatstudio/releases"); else Reportaise_Command_Failed ("'" & Exec & "' not available or not in PATH."); end if; return; end if; end; declare Project_Files : constant AAA.Strings.Vector := Cmd.Root.Release.Project_Files (Platforms.Current.Properties, With_Path => True); begin if Project_Files.Length = 0 then Reportaise_Command_Failed ("No project file to open for this crate."); elsif Project_Files.Length = 1 then Start_Editor (Edit_Args, Project_Files.First_Element); elsif Cmd.Prj = null or else not Project_Files.Contains (Cmd.Prj.all) then Trace.Warning ("More than 1 project file for this crate."); Trace.Warning ("The list of project is:"); for Prj of Project_Files loop Trace.Warning (" - " & Prj); end loop; Reportaise_Command_Failed ("Please specify a project file with --project=."); else Start_Editor (Edit_Args, Cmd.Prj.all); end if; end; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Start GNATstudio with Alire build environment setup.") ); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Prj'Access, "", "--project=", "Select the project file to open if the crate " & "provides multiple project files, ignored otherwise"); end Setup_Switches; end Alr.Commands.Edit; alire-1.2.1/src/alr/alr-commands-edit.ads000066400000000000000000000017231430264165500201560ustar00rootroot00000000000000with AAA.Strings; private with GNAT.Strings; package Alr.Commands.Edit is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("edit"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Start GNATstudio with Alire build environment setup"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is (""); private type Command is new Commands.Command with record Prj : aliased GNAT.Strings.String_Access; end record; end Alr.Commands.Edit; alire-1.2.1/src/alr/alr-commands-exec.adb000066400000000000000000000075031430264165500201360ustar00rootroot00000000000000with Ada.Containers; with CLIC.Subcommand; with Alire.Spawn; with Alire.Platforms.Current; package body Alr.Commands.Exec is ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is use GNAT.Strings; use Ada.Containers; use AAA.Strings; begin if Args.Is_Empty then Reportaise_Wrong_Arguments (Cmd.Name & " takes at least one argument"); end if; declare Cmd_Args : AAA.Strings.Vector := Args; Cmd_Name : constant String := Cmd_Args.First_Element; begin Cmd.Requires_Valid_Session; Cmd.Root.Export_Build_Environment; -- Remove command name from the arguments Cmd_Args.Delete_First; if Cmd.Prj.all /= NO_PROJECT_STR then -- User requested -P switch declare Project_Files : constant AAA.Strings.Vector := Cmd.Root.Release.Project_Files (Alire.Platforms.Current.Properties, With_Path => True); Position : Integer := 1; -- Default switch position is set to first on the cmd line begin if Project_Files.Length = 0 then Reportaise_Command_Failed ("No project file declared for this crate."); elsif Project_Files.Length > 1 then Reportaise_Command_Failed ("More than 1 project file declared for this crate."); end if; if Cmd.Prj.all /= "" then -- Get position argument from user begin Position := Integer'Value (Cmd.Prj.all); exception when others => Reportaise_Wrong_Arguments ("Invalid position argument for -P switch ('" & Cmd.Prj.all & "')"); end; end if; -- Adjust the position if Position = 0 then Reportaise_Wrong_Arguments ("Invalid position argument for -P switch ('0')." & " Positions start at 1."); elsif Position > Integer (Cmd_Args.Length) then -- Set to last position Position := Integer (Cmd_Args.Length) + 1; elsif Position <= -Integer (Cmd_Args.Length) then -- Set to first position Position := 1; elsif Position < 0 then -- Set position from the end Position := Integer (Cmd_Args.Length) + Position + 2; end if; -- Insert declare To_Insert : constant AAA.Strings.Vector := Empty_Vector.Append ("-P") .Append (Project_Files.First_Element); begin if Cmd_Args.Is_Empty then Cmd_Args := To_Insert; else Cmd_Args.Insert (Position, To_Insert); end if; end; end; end if; Alire.Spawn.Command (Cmd => Cmd_Name, Args => Cmd_Args, Understands_Verbose => False); end; end Execute; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is begin CLIC.Subcommand.Define_Switch (Config, Cmd.Prj'Access, Switch => "-P?", Help => "Add ""-P "" to the command switches"); end Setup_Switches; end Alr.Commands.Exec; alire-1.2.1/src/alr/alr-commands-exec.ads000066400000000000000000000046371430264165500201640ustar00rootroot00000000000000with AAA.Strings; private with GNAT.Strings; package Alr.Commands.Exec is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("exec"); overriding function Switch_Parsing (This : Command) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Before_Double_Dash); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Alr sets up the environment variables (GPR_PROJECT_PATH, ") .Append ("PATH, etc.) and then spawns the given command.") .New_Line .Append ("This can be used to run tools or scripts on Alire projects.") .New_Line .Append ("The ""-P"" switch can be used to ask Alire to insert a ") .Append ("""-P "" switch to the command arguments.") .Append ("""-P"" takes an optional position argument to specify where") .Append ("to insert the extra switch. ""-P1"" means first position, ") .Append ("""-P2"" second position, etc. ""-P-1"" means last position, ") .Append ("""-P-2"" penultimate position, etc. ""-P"" equals ""-P1"".") .Append ("For example ""alr exec -P2 -- python3 main.py arg1"" will") .Append ("run the following command:") .Append ("[""python3"", ""main.py"", ""-P"", ""crate.gpr"", ""arg1""]") ); overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Run the given command in the alire project context"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[-P?] [--] []"); private NO_PROJECT_STR : constant String := "NO_PROJECT"; -- There is no way to see the difference between a -P switch without -- argument and no -P switch at all. So we set this default value to -- detect if it is changed by the command line parsing. type Command is new Commands.Command with record Prj : aliased GNAT.Strings.String_Access := new String'(NO_PROJECT_STR); end record; end Alr.Commands.Exec; alire-1.2.1/src/alr/alr-commands-get.adb000066400000000000000000000322211430264165500177640ustar00rootroot00000000000000with Ada.Directories; with Alire.Config.Edit; with Alire.Dependencies; with Alire.Directories; with Alire.Index; with Alire.Milestones; with Alire.Origins.Deployers; with Alire.Platforms.Current; with Alire.Root; with Alire.Solutions.Diffs; with Alire.Solver; with CLIC.User_Input; with Alr.Commands.Build; with Semantic_Versioning.Extended; package body Alr.Commands.Get is package Platform renames Alire.Platforms.Current; package Query renames Alire.Solver; package Semver renames Semantic_Versioning; -------------- -- Retrieve -- -------------- procedure Retrieve (Cmd : in out Command; Name : Alire.Crate_Name; Versions : Semver.Extended.Version_Set) is -- Find a release that satisfies the requested version. TODO: We should -- resolve the release as part of the dependencies at this point so if -- the latest release is not solvable we get another one that is. We -- should warn in that case that newer releases exist. Rel : constant Alire.Index.Release := Query.Find (Name, Versions, Query_Policy); Diff : Alire.Solutions.Diffs.Diff; -- Used to present dependencies to the user Build_OK : Boolean := False; Solution : Alire.Solutions.Solution; use all type Alire.Origins.Kinds; begin if Cmd.Dirname then Trace.Always (Rel.Base_Folder); return; end if; Trace.Detail ("Using " & Rel.Milestone.TTY_Image & " for requested " & Alire.Dependencies.New_Dependency (Name, Versions).TTY_Image); declare Result : Alire.Outcome; begin -- Check that itself is available (but overridable with --only) if not Cmd.Only and then not Rel.Is_Available (Platform.Properties) then Trace.Error ("The requested version (" & Rel.Milestone.Image & ") is not available"); Reportaise_Command_Failed ("You can retrieve it without dependencies with --only"); end if; -- Check if it's system first and thus we need not to check out. if Rel.Origin.Is_System then Result := Alire.Origins.Deployers.Deploy (Rel); if Result.Success then return; else Reportaise_Command_Failed (Alire.Message (Result)); end if; end if; end; -- Check if we are already in the fresh copy if not Alire.Root.Current.Outside then Reportaise_Command_Failed ("Cannot get a release inside another alr release, stopping."); end if; -- Check that the dependencies can be solved before retrieving anything if not Cmd.Only then declare use CLIC.User_Input; begin Solution := Query.Resolve (Rel.Dependencies (Platform.Properties), Platform.Properties, Alire.Solutions.Empty_Valid_Solution); Diff := Alire.Solutions.Empty_Valid_Solution.Changes (Solution); if not Solution.Is_Complete then Diff.Print (Changed_Only => False, Level => Warning); Trace.Warning (""); Trace.Warning ("Could not find a complete solution for " & Rel.Milestone.TTY_Image); if CLIC.User_Input.Query (Question => "Build will fail unless externals are made available," & " do you want to continue?", Valid => (Yes | No => True, others => False), Default => (if Alire.Force then Yes else No)) = No then Reportaise_Command_Failed ("Crate retrieval abandoned."); end if; end if; end; end if; -- Check out requested crate release under current directory, -- but delay its post-fetch: declare Root_Dir : Alire.Directories.Temp_File := Alire.Directories.With_Name (Rel.Deployment_Folder); begin -- Create the Root for the given release, and store it for possible -- future use. Cmd.Set (Alire.Roots.Create_For_Release (Rel, Ada.Directories.Current_Directory, Platform.Properties, Perform_Actions => False)); -- Set the initial solution we just found Cmd.Root.Set (Solution); -- At this point, both crate and lock files must exist and -- be correct, so the working session is correct. Errors with -- dependencies can still occur, but these are outside of the -- retrieved crate and might be corrected manipulating dependencies -- and updating. Root_Dir.Keep; end; declare Guard : Folder_Guard (Enter_Folder (Rel.Base_Folder)) with Unreferenced; begin -- When --only was used, mark as only to be updated manually and bail -- out already. if Cmd.Only then Trace.Detail ("By your command, dependencies not resolved nor" & " retrieved: compilation might fail"); Trace.Info ("Because --only was used, automatic dependency" & " retrieval is disabled in this workspace:" & " use `alr update` to apply dependency changes"); Alire.Config.Edit.Set_Locally (Alire.Config.Keys.Update_Manually, "true"); return; end if; -- Check out rest of dependencies and optionally compile. This will -- execute also all post-fetch actions, root itself included. Cmd.Root.Deploy_Dependencies; if Cmd.Build then if Rel.Origin.Kind in Binary_Archive then -- No need to build a binary release Alire.Put_Info ("Skipping build step for binary release " & Rel.Milestone.TTY_Image); Build_OK := True; else -- The complete build environment has been set up already by -- Deploy_Dependencies, so we must not do it again. Build_OK := Commands.Build.Execute (Cmd, AAA.Strings.Empty_Vector, Export_Build_Env => False); end if; else Build_OK := True; end if; end; -- Final report Trace.Info (""); Trace.Log (Rel.Milestone.TTY_Image & " successfully retrieved" & (if Solution.Is_Complete then "" else " with missing dependencies") & (if Cmd.Build then (if Build_OK then (if Rel.Origin.Kind in Binary_Archive then " and deployed." else " and built.") else " but its build failed.") else "."), Level => (if not Cmd.Build or else Build_OK then Info else Warning)); if Diff.Contains_Changes then Trace.Info ("Dependencies were solved as follows:"); Diff.Print (Changed_Only => False); else Trace.Info ("There are no dependencies."); end if; if not Build_OK then Reportaise_Command_Failed ("Build ended with errors"); -- This is not displayed at default level, but ensures exit code /= 0 end if; end Retrieve; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is procedure Check_Unavailable_External (Name : Alire.Crate_Name) is -- Better user feedback if crate is only available through externals. -- We distinguish if we are in a platform with system package manager -- or not. use all type Alire.Platforms.Toolchains; begin -- Crate has regular source releases, which take precedence if not Alire.Index.Crate (Name).Releases.Is_Empty then return; -- A regular source crate will be used end if; -- Crate exists but has no releases nor externals (?). Theoretically -- we shouldn't have those in the community index. if Alire.Index.Crate (Name).Externals.Is_Empty then Reportaise_Command_Failed ("No releases or externals found for the requested crate"); end if; -- Attempt detection of any defined externals, so they can be used -- afterwards for crate retrieval. Alire.Index.Detect_Externals (Name, Platform.Properties); -- If something was detected we are done if not Alire.Index.Crate (Name).Releases.Is_Empty then return; -- A detected external will be used end if; -- Otherwise emit appropriate information, according to environment if Alire.Platforms.Current.Distribution_Is_Known then -- At this point we are failing for sure. Warn if there are -- external definitions to raise user awareness. Trace.Info ("There are external definitions for the crate. " & "Use alr show --external to show them."); -- Emit any hints that apply to the current platform for Hint of Alire.Index.Crate (Name) .Externals.Hints (Name, Platform.Properties) loop Trace.Info ("Hint: " & Hint); end loop; -- Also warn when the system Ada compiler could be used but isn't if Platform.Toolchain = User then Trace.Warning ("Ada packages from the distribution are unavailable when " & "not using the system compiler"); end if; Reportaise_Command_Failed ("No source release or system package available for the " & "requested crate"); else Reportaise_Command_Failed ("No source release indexed for the requested crate, and " & "cannot use system packages in unknown distribution"); end if; end Check_Unavailable_External; begin if Args.Count > 1 then Reportaise_Wrong_Arguments ("Too many arguments"); end if; if Args.Count /= 1 then Trace.Error ("No crate requested"); Reportaise_Wrong_Arguments ("One crate to get expected"); end if; declare Allowed : constant Alire.Dependencies.Dependency := Alire.Dependencies.From_String (Args (1)); begin if Cmd.Build and Cmd.Only then Reportaise_Wrong_Arguments ("--only is incompatible with --build"); end if; if Cmd.Dirname and (Cmd.Build or else Cmd.Only) then Reportaise_Wrong_Arguments ("--dirname is incompatible with other switches"); end if; Cmd.Requires_Full_Index; if not Alire.Index.Exists (Allowed.Crate) then Reportaise_Command_Failed ("Crate [" & Args (1) & "] does not exist in the catalog."); end if; Check_Unavailable_External (Allowed.Crate); -- Final checks pre-retrieval if not Query.Exists (Allowed.Crate, Allowed.Versions) then Reportaise_Command_Failed ("Release within the requested versions [" & Allowed.TTY_Image & "] does not exist in the catalog."); end if; Retrieve (Cmd, Allowed.Crate, Allowed.Versions); end; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Retrieve a crate, in the case of regular ones, or install" & " a system package provided by the platform." & " A regular crate is deployed under an immediate folder" & " with naming 'name_version_hash'.") .New_Line .Append (Crate_Version_Sets)); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Build'Access, "-b", "--build", "Build after download"); Define_Switch (Config, Cmd.Dirname'Access, Long_Switch => "--dirname", Help => "Display deployment folder"); Define_Switch (Config, Cmd.Only'Access, "-o", "--only", "Retrieve requested crate only, without dependencies"); end Setup_Switches; end Alr.Commands.Get; alire-1.2.1/src/alr/alr-commands-get.ads000066400000000000000000000017741430264165500200160ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Get is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("get"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Fetches a crate release"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[allowed versions]"); private type Command is new Commands.Command with record Build : aliased Boolean := False; Dirname : aliased Boolean := False; Only : aliased Boolean := False; end record; end Alr.Commands.Get; alire-1.2.1/src/alr/alr-commands-index.adb000066400000000000000000000177631430264165500203320ustar00rootroot00000000000000with AAA.Table_IO; with Alire.Config.Edit; with Alire.Index_On_Disk.Loading; with Alire.Utils; package body Alr.Commands.Index is package Index_Load renames Alire.Index_On_Disk.Loading; -- Forward declarations procedure Add (Cmd : Command); procedure Check (Cmd : in out Command); procedure List; procedure Reset_Community; --------- -- Add -- --------- procedure Add (Cmd : Command) is Before : constant String := Cmd.Bfr.all; Result : constant Alire.Outcome := Alire.Index_On_Disk.Loading.Add (Origin => Cmd.Add.all, Name => Cmd.Name.all, Under => Alire.Config.Edit.Indexes_Directory, Before => Before); begin Trace.Debug ("Index before ID = " & Before); if not Result.Success then Reportaise_Command_Failed (Alire.Message (Result)); end if; end Add; ------------ -- Delete -- ------------ procedure Delete (Name : String) is Result : Alire.Outcome; Indexes : constant Index_Load.Set := Index_Load.Find_All (Alire.Config.Edit.Indexes_Directory, Result); Found : Boolean := False; begin if not Result.Success then Reportaise_Command_Failed (Alire.Message (Result)); return; end if; -- Find matching index and delete for Index of Indexes loop if Index.Name = Name then Found := True; declare Result : constant Alire.Outcome := Index.Delete; begin if Result.Success then exit; else Reportaise_Command_Failed (Alire.Message (Result)); end if; end; end if; end loop; if not Found then Reportaise_Command_Failed ("Given index not found: " & Name); end if; end Delete; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is begin if Args.Count /= 0 then Reportaise_Wrong_Arguments (Name (Cmd) & " doesn't take arguments"); end if; -- Check no multi-action case Alire.Utils.Count_True ((Cmd.Add.all /= "", Cmd.Del.all /= "", Cmd.Check, Cmd.List, Cmd.Rset, Cmd.Update_All)) is when 0 => -- Use --list as the default Cmd.List := True; when 1 => null; -- Usual case, just fall through when others => Reportaise_Wrong_Arguments ("Specify exactly one index subcommand"); end case; -- Dispatch to selected action if Cmd.Add.all /= "" then if Cmd.Name.all = "" then Reportaise_Wrong_Arguments ("Must provide a local name for new index"); end if; Add (Cmd); elsif Cmd.Del.all /= "" then Delete (Cmd.Del.all); elsif Cmd.Check then Check (Cmd); elsif Cmd.List then List; elsif Cmd.Update_All then Update_All; elsif Cmd.Rset then Reset_Community; else Reportaise_Wrong_Arguments ("Specify an index subcommand"); end if; end Execute; ----------- -- Check -- ----------- procedure Check (Cmd : in out Command) is begin Cmd.Requires_Full_Index (Strict => True); Alire.Put_Success ("No unknown values found in index contents."); end Check; ---------- -- List -- ---------- procedure List is use Alire; Result : Alire.Outcome; Indexes : constant Index_Load.Set := Index_Load.Find_All (Alire.Config.Edit.Indexes_Directory, Result); Table : AAA.Table_IO.Table; Count : Natural := 0; begin if not Result.Success then Reportaise_Command_Failed (Alire.Message (Result)); return; end if; Table .Append (TTY.Emph ("#")) .Append (TTY.Emph ("NAME")) .Append (TTY.Emph ("URL")) .Append (TTY.Emph ("PATH")); if Alire.Log_Level = Alire.Trace.Debug then Table.Append (TTY.Emph ("PRIORITY")); end if; for Index of Indexes loop Count := Count + 1; Table.New_Row; Table .Append (AAA.Strings.Trim (Count'Img)) .Append (Index.Name) .Append (Index.Origin) .Append (Index.Index_Directory); if Alire.Log_Level = Alire.Trace.Debug then Table.Append (AAA.Strings.Trim (Index.Priority'Img)); end if; end loop; if Count > 0 then Table.Print; else Trace.Info ("No index configured."); end if; end List; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Add, remove, list and update indexes used by the current" & " alr configuration.") .New_Line .Append ("Updating applies only to repository-stored indexes, in which" & " case a pull operation will be performed on them." & " An index initially set up with a specific commit will" & " not be updated.") ); --------------------- -- Reset_Community -- --------------------- procedure Reset_Community is Result : constant Alire.Outcome := Index_Load.Add_Or_Reset_Community; begin if not Result.Success then Reportaise_Command_Failed (Result.Message); end if; end Reset_Community; -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config => Config, Output => Cmd.Add'Access, Long_Switch => "--add=", Argument => "URL", Help => "Add an index"); Define_Switch (Config => Config, Output => Cmd.Bfr'Access, Long_Switch => "--before=", Argument => "NAME", Help => "Priority order (defaults to last)"); Define_Switch (Config => Config, Output => Cmd.Check'Access, Long_Switch => "--check", Help => "Check index contents for unknown configuration values"); Define_Switch (Config => Config, Output => Cmd.Del'Access, Long_Switch => "--del=", Argument => "NAME", Help => "Remove an index"); Define_Switch (Config => Config, Output => Cmd.List'Access, Long_Switch => "--list", Help => "List configured indexes (default)"); Define_Switch (Config => Config, Output => Cmd.Name'Access, Long_Switch => "--name=", Argument => "NAME", Help => "User given name for the index"); Define_Switch (Config => Config, Output => Cmd.Update_All'Access, Long_Switch => "--update-all", Help => "Update configured indexes"); Define_Switch (Config => Config, Output => Cmd.Rset'Access, Long_Switch => "--reset-community", Help => "Add the community index, or reset any local changes"); end Setup_Switches; ---------------- -- Update_All -- ---------------- procedure Update_All is Result : constant Alire.Outcome := Index_Load.Update_All (Alire.Config.Edit.Indexes_Directory); begin if not Result.Success then Reportaise_Command_Failed (Alire.Message (Result)); end if; end Update_All; end Alr.Commands.Index; alire-1.2.1/src/alr/alr-commands-index.ads000066400000000000000000000030041430264165500203320ustar00rootroot00000000000000with AAA.Strings; private with GNAT.Strings; package Alr.Commands.Index is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("index"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Manage indexes used by current configuration"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("--add --name [--before ] | --del | [--list]" & " | --update-all | --check"); procedure Update_All; -- Request update of configured indexes private type Command is new Commands.Command with record Add : aliased GNAT.Strings.String_Access; Bfr : aliased GNAT.Strings.String_Access; Del : aliased GNAT.Strings.String_Access; Name : aliased GNAT.Strings.String_Access; List : aliased Boolean := False; Rset : aliased Boolean := False; -- Reset the community index Check : aliased Boolean := False; -- Enable strict syntax in the index Update_All : aliased Boolean := False; end record; end Alr.Commands.Index; alire-1.2.1/src/alr/alr-commands-init.adb000066400000000000000000000312631430264165500201550ustar00rootroot00000000000000with AAA.Text_IO; with Ada.Directories; with Ada.Text_IO; with Alire.Config; with Alire.Utils.User_Input.Query_Config; with GNATCOLL.VFS; use GNATCOLL.VFS; with TOML; package body Alr.Commands.Init is package UI renames Alire.Utils.User_Input; Sed_Pattern : constant String := "PROJECT_SKEL"; -------------- -- Generate -- -------------- procedure Generate (Cmd : Command; Args : AAA.Strings.Vector) is package TIO renames Ada.Text_IO; use AAA.Strings; For_Library : constant Boolean := not Cmd.Bin; Name : constant String := Args (1); Lower_Name : constant String := AAA.Strings.To_Lower_Case (Name); Upper_Name : constant String := AAA.Strings.To_Upper_Case (Name); Mixed_Name : constant String := AAA.Strings.To_Mixed_Case (Name); Directory : constant Virtual_File := (if Cmd.In_Place then Get_Current_Dir else Create (+Name, Normalize => True)); Src_Directory : constant Virtual_File := Directory / "src"; Share_Directory : constant Virtual_File := Directory / "share" / Filesystem_String (Lower_Name); File : TIO.File_Type; function Create (Filename : String) return Boolean; -- Return False if the file already exists procedure Put_New_Line; procedure Put_Line (S : String); -- Shortcuts to write to File function Escape (S : String) return String -- We trick the TOML exporter to get a valid escaped string is use TOML; Table : constant TOML_Value := Create_Table; begin Table.Set ("key", TOML.Create_String (S)); -- Remove excess whitespace and quotation return Trim (Trim (Trim (Tail (TOML.Dump_As_String (Table), '=')), ASCII.LF), '"'); end Escape; function Q (S : String) return String is ("""" & S & """"); -- Quote string function Arr (S : String) return String is ("[" & S & "]"); -- Wrap string into TOML array procedure Generate_Project_File; -- Generate a project file for this crate procedure Generate_Root_Package; -- Generate the specification for the root package of this crate procedure Generate_Program_Main; -- Generate the procedure body for the program main of this crate procedure Generate_Gitignore; -- Generate or append .gitignore procedure Generate_Manifest; -- Generates the initial manifest by hand. This is more legible than -- exporting using To_TOML functions. We still use TOML encoding for -- the generated strings to be on the safe side. --------------------------- -- Generate_Project_File -- --------------------------- procedure Generate_Project_File is Filename : constant String := +Full_Name (Directory / (+Lower_Name & ".gpr")); begin -- Use more than 80 columns for more readable strings pragma Style_Checks ("M200"); -- Main project file if not Create (Filename) then Trace.Warning ("Cannot create '" & Filename & "'"); return; end if; Put_Line ("with ""config/" & Lower_Name & "_config.gpr"";"); Put_Line ("project " & Mixed_Name & " is"); Put_New_Line; if For_Library then Put_Line (" for Library_Name use """ & Mixed_Name & """;"); Put_Line (" for Library_Version use Project'Library_Name & "".so."" & " & Mixed_Name & "_Config.Crate_Version;"); Put_New_Line; end if; Put_Line (" for Source_Dirs use (""src/"", ""config/"");"); Put_Line (" for Object_Dir use ""obj/"" & " & Mixed_Name & "_Config.Build_Profile;"); Put_Line (" for Create_Missing_Dirs use ""True"";"); if For_Library then Put_Line (" for Library_Dir use ""lib"";"); Put_New_Line; Put_Line (" type Library_Type_Type is " & "(""relocatable"", ""static"", ""static-pic"");"); Put_Line (" Library_Type : Library_Type_Type :="); Put_Line (" external (""" & Upper_Name & "_LIBRARY_TYPE"", external (""LIBRARY_TYPE"", ""static""));"); Put_Line (" for Library_Kind use Library_Type;"); else Put_Line (" for Exec_Dir use ""bin"";"); Put_Line (" for Main use (""" & Lower_Name & ".adb"");"); end if; Put_New_Line; Put_Line (" package Compiler is"); Put_Line (" for Default_Switches (""Ada"") use " & Mixed_Name & "_Config.Ada_Compiler_Switches;"); Put_Line (" end Compiler;"); Put_New_Line; Put_Line (" package Binder is"); Put_Line (" for Switches (""Ada"") use (""-Es""); -- Symbolic traceback"); Put_Line (" end Binder;"); Put_New_Line; Put_Line (" package Install is"); Put_Line (" for Artifacts (""."") use (""share"");"); Put_Line (" end Install;"); Put_New_Line; TIO.Put (File, "end " & Mixed_Name & ";"); pragma Style_Checks ("M80"); TIO.Close (File); end Generate_Project_File; --------------------------- -- Generate_Root_Package -- --------------------------- procedure Generate_Root_Package is Filename : constant String := +Full_Name (Src_Directory / (+Lower_Name & ".ads")); begin if not Create (Filename) then return; end if; Put_Line ("package " & Mixed_Name & " is"); Put_New_Line; TIO.Put (File, "end " & Mixed_Name & ";"); TIO.Close (File); end Generate_Root_Package; --------------------------- -- Generate_Program_Main -- --------------------------- procedure Generate_Program_Main is Filename : constant String := +Full_Name (Src_Directory / (+Lower_Name & ".adb")); begin if not Create (Filename) then return; end if; Put_Line ("procedure " & Mixed_Name & " is"); Put_Line ("begin"); Put_Line (" null;"); TIO.Put (File, "end " & Mixed_Name & ";"); TIO.Close (File); end Generate_Program_Main; ------------------------ -- Generate_Gitignore -- ------------------------ procedure Generate_Gitignore is Filename : constant String := +Full_Name (Directory / ".gitignore"); begin if Ada.Directories.Exists (Filename) then TIO.Open (File, TIO.Append_File, Filename); else TIO.Create (File, TIO.Out_File, Filename); end if; Put_Line ("/obj/"); if For_Library then Put_Line ("/lib/"); else Put_Line ("/bin/"); end if; Put_Line ("/alire/"); Put_Line ("/config/"); TIO.Close (File); end Generate_Gitignore; ----------------------- -- Generate_Manifest -- ----------------------- procedure Generate_Manifest is use Alire.Config; begin if not DB.Defined (Keys.User_Email) or else not DB.Defined (Keys.User_Name) or else not DB.Defined (Keys.User_Github_Login) then AAA.Text_IO.Put_Paragraph ("Alire needs some user information to initialize the crate" & " author and maintainer, for eventual submission to" & " the Alire community index. This information will be" & " interactively requested now."); TIO.New_Line; TIO.Put_Line ("You can edit this information at any time with 'alr config'"); TIO.New_Line; end if; declare -- Retrieve initial values from config or user. Only the name may -- require encoding, as emails and logins cannot contain strange -- characters. Login : constant String := UI.Query_Config.User_GitHub_Login; Username : constant String := Escape (UI.Query_Config.User_Name); Email : constant String := UI.Query_Config.User_Email; Filename : constant String := +Full_Name (Directory / (+Alire.Roots.Crate_File_Name)); begin if not Create (Filename) then Reportaise_Command_Failed ("Cannot create '" & Filename & "'"); end if; Put_Line ("name = " & Q (Lower_Name)); Put_Line ("description = " & Q ("Shiny new project")); Put_Line ("version = " & Q ("0.1.0-dev")); Put_New_Line; Put_Line ("authors = " & Arr (Q (Username))); Put_Line ("maintainers = " & Arr (Q (Username & " <" & Email & ">"))); Put_Line ("maintainers-logins = " & Arr (Q (Login))); end; if Cmd.Bin then Put_New_Line; Put_Line ("executables = " & Arr (Q (Lower_Name))); end if; TIO.Close (File); end Generate_Manifest; ------------ -- Create -- ------------ function Create (Filename : String) return Boolean is begin if Ada.Directories.Exists (Filename) then Trace.Warning (Filename & " already exists."); return False; end if; TIO.Create (File, TIO.Out_File, Filename); return True; end Create; ------------------ -- Put_New_Line -- ------------------ procedure Put_New_Line is begin TIO.New_Line (File); end Put_New_Line; -------------- -- Put_Line -- -------------- procedure Put_Line (S : String) is begin TIO.Put_Line (File, S); end Put_Line; begin -- Crate dir Directory.Make_Dir; if not Cmd.No_Skel then Generate_Project_File; Src_Directory.Make_Dir; Share_Directory.Make_Dir; if For_Library then Generate_Root_Package; else Generate_Program_Main; end if; Generate_Gitignore; end if; Generate_Manifest; Alire.Put_Success (TTY.Emph (Lower_Name) & " initialized successfully."); end Generate; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is use AAA.Strings; begin if Args.Count /= 1 then Reportaise_Wrong_Arguments ("No crate name given"); end if; if not (Cmd.Bin or Cmd.Lib) then Reportaise_Wrong_Arguments ("Please provide either --bin or --lib"); end if; -- Validation finished declare Name : constant String := Args (1); Check : constant Alire.Crate_Name := +Name with Unreferenced; begin if To_Lower_Case (Name) = To_Lower_Case (Sed_Pattern) then Reportaise_Command_Failed ("The crate name is invalid, as it is used internally by" & " alr; please choose another name"); end if; Generate (Cmd, Args); end; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Initializes a new crate containing a ready-to-build GNAT" & " project. The crate is created as a child of the current" & " directory, containing minimal sources for an executable" & " or library, as specified.") .New_Line .Append ("--in-place is intended to be used inside the crate directory.") ); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Bin'Access, "", "--bin", "New project is an executable"); Define_Switch (Config, Cmd.Lib'Access, "", "--lib", "New project is a library"); Define_Switch (Config, Cmd.In_Place'Access, "", "--in-place", "Create alr files in current folder"); Define_Switch (Config, Cmd.No_Skel'Access, "", "--no-skel", "Do not generate non-alire skeleton files"); end Setup_Switches; end Alr.Commands.Init; alire-1.2.1/src/alr/alr-commands-init.ads000066400000000000000000000020221430264165500201650ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Init is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("init"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Creates a new working release with" & " alire metadata, or generate metadata"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("{--bin|--lib} "); private type Command is new Commands.Command with record Bin, Lib, In_Place, No_Skel : aliased Boolean := False; end record; end Alr.Commands.Init; alire-1.2.1/src/alr/alr-commands-pin.adb000066400000000000000000000226461430264165500200050ustar00rootroot00000000000000with Alire.Dependencies; with Alire.Optional; with Alire.Roots.Editable; with Alire.Solutions; with Alire.URI; with Alire.Utils.User_Input; with Alire.Utils.TTY; with Alr.Commands.User_Input; with Semantic_Versioning.Extended; with TOML_Slicer; package body Alr.Commands.Pin is package Semver renames Semantic_Versioning; -------------------- -- Change_One_Pin -- -------------------- procedure Change_One_Pin (Cmd : in out Command; Root : in out Alire.Roots.Editable.Root; Target : String) is Version : Semver.Version; Solution : constant Alire.Solutions.Solution := Root.Solution; Dep : constant Alire.Dependencies.Dependency := Alire.Dependencies.From_String (Target); -- Only crate=version should be allowed here, we check it shortly --------- -- Pin -- --------- procedure Pin is begin -- We let to re-pin without checks because the requested version may -- be different. Cmd.Requires_Full_Index; Root.Add_Version_Pin (Dep.Crate, Version); end Pin; ----------- -- Unpin -- ----------- procedure Unpin is begin if not Solution.State (Dep.Crate).Is_User_Pinned then Reportaise_Command_Failed ("Requested crate is already unpinned"); end if; Cmd.Requires_Full_Index; Root.Remove_Pin (Dep.Crate); end Unpin; begin -- Sanity checks if not Solution.Depends_On (Dep.Crate) then Reportaise_Command_Failed ("Cannot " & (if Cmd.Unpin then "unpin" else "pin") & " dependency not in solution: " & Alire.Utils.TTY.Name (Dep.Crate)); end if; -- Check if we are given a particular version if AAA.Strings.Contains (Target, "=") then if Cmd.Unpin then Reportaise_Wrong_Arguments ("Unpinning does not require version"); end if; Version := Semver.Parse (AAA.Strings.Tail (Dep.Image, '='), Relaxed => False); Trace.Debug ("Pin requested for exact version: " & Version.Image); elsif Solution.State (Dep.Crate).Is_Solved then Version := Solution.State (Dep.Crate).Release.Version; elsif not Cmd.Unpin then Reportaise_Wrong_Arguments ("An explicit version is required to pin a crate with" & " no release in the current solution: " & Alire.Utils.TTY.Name (Dep.Crate)); end if; -- Proceed to pin/unpin if Cmd.Unpin then Unpin; else Pin; end if; end Change_One_Pin; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is ------------------------- -- Validate_Crate_Spec -- ------------------------- procedure Validate_Crate_Spec (Spec : String) is Dep : constant Alire.Dependencies.Dependency := Alire.Dependencies.From_String (Spec); begin if not Dep.Versions.Is_Any then if not AAA.Strings.Has_Prefix (Dep.Versions.Image, "=") then Reportaise_Wrong_Arguments ("Plain crate name or crate=version argument expected for" & " pinning, but got: " & TTY.Emph (Spec)); end if; end if; end Validate_Crate_Spec; begin -- Argument validation if Cmd.Pin_All and then Args.Count /= 0 then Reportaise_Wrong_Arguments ("--all must appear alone"); elsif Cmd.URL.all /= "" and then (Args.Count /= 1 or else Cmd.Pin_All or else Cmd.Unpin) then Reportaise_Wrong_Arguments ("--use must be used alone with a crate name"); elsif Cmd.Commit.all /= "" and then Cmd.Branch.all /= "" then Reportaise_Wrong_Arguments ("Cannot specify both a branch and a commit simultaneously"); end if; Cmd.Requires_Valid_Session; -- Listing of pins if not Cmd.Pin_All and then Args.Count = 0 then Cmd.Root.Solution.Print_Pins; return; elsif Args.Count > 1 then Reportaise_Wrong_Arguments ("Pin expects a single crate or crate=version argument"); elsif Args.Count = 1 then -- Check that we get either a plain name or a crate=version Validate_Crate_Spec (Args (1)); end if; -- Apply changes; declare New_Root : Alire.Roots.Editable.Root := Alire.Roots.Editable.New_Root (Original => Cmd.Root); Optional_Crate : constant Alire.Optional.Crate_Name := (if Args.Count = 1 then Alire.Optional.Crate_Names.Unit (Alire.Dependencies .From_String (Args (1)).Crate) else Alire.Optional.Crate_Names.Empty); begin if Cmd.Pin_All then -- Change all pins for Crate of Cmd.Root.Solution.Crates loop Change_One_Pin (Cmd, New_Root, Crate.As_String); end loop; elsif Cmd.URL.all /= "" then if Cmd.Commit.all /= "" or else Cmd.Branch.all /= "" or else Alire.URI.Is_HTTP_Or_Git (Cmd.URL.all) then -- Pin to remote commit New_Root.Add_Remote_Pin (Crate => Optional_Crate, Origin => Cmd.URL.all, Ref => Cmd.Commit.all, Branch => Cmd.Branch.all); else -- Pin to dir if not Alire.Utils.User_Input.Approve_Dir (Cmd.URL.all) then Trace.Info ("Abandoned by user."); return; end if; Cmd.Requires_Full_Index; -- Next statement recomputes a solution New_Root.Add_Path_Pin (Crate => Optional_Crate, Path => Cmd.URL.all); end if; -- Report crate detection at target destination User_Input.Report_Pinned_Crate_Detection (Optional_Crate.Element, New_Root.Solution); else -- Change a single pin Change_One_Pin (Cmd, New_Root, Args (1)); end if; -- Consolidate changes New_Root.Confirm_And_Commit; end; exception when E : Semver.Malformed_Input => Alire.Log_Exception (E); Reportaise_Wrong_Arguments ("Improper version string"); when E : TOML_Slicer.Slicing_Error => Alire.Log_Exception (E); Reportaise_Command_Failed ("alr was unable to apply your request; " & "please edit the manifest manually."); end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Pin releases to a particular version." & " By default, the current solution version is used." & " A pinned release is not affected by automatic updates.") .New_Line .Append ("Without arguments, show existing pins.") .New_Line .Append ("Use --all to pin the whole current solution.") .New_Line .Append ("Specify a single crate to modify its pin.") .New_Line .Append ("Use the --use switch to" & " use the target to fulfill a dependency locally" & " instead of looking for indexed releases." & " An optional reference can be specified with --commit;" & " the pin will be frozen at the commit currently matching" & " the reference. Alternatively, a branch to track can be" & " specified with --branch. Use `alr update` to refresh the" & " tracking pin contents.") ); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Pin_All'Access, Long_Switch => "--all", Help => "Pin the complete solution"); Define_Switch (Config, Cmd.Unpin'Access, Long_Switch => "--unpin", Help => "Unpin a release"); Define_Switch (Config => Config, Output => Cmd.Branch'Access, Long_Switch => "--branch=", Argument => "NAME", Help => "Branch to be tracked in repository"); Define_Switch (Config => Config, Output => Cmd.Commit'Access, Long_Switch => "--commit=", Argument => "REF", Help => "Reference to be retrieved from repository"); Define_Switch (Config => Config, Output => Cmd.URL'Access, Long_Switch => "--use=", Argument => "PATH|URL", Help => "Use a directory or repository to fulfill a dependency"); end Setup_Switches; end Alr.Commands.Pin; alire-1.2.1/src/alr/alr-commands-pin.ads000066400000000000000000000023171430264165500200170ustar00rootroot00000000000000with AAA.Strings; with GNAT.Strings; package Alr.Commands.Pin is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("pin"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding function Short_Description (Cmd : Command) return String is ("Pin dependencies to exact versions"); overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[[crate[=]]" & " | crate --use= [--commit=REF] [--branch=NAME]" & " | --all]"); private type Command is new Commands.Command with record Branch : aliased GNAT.Strings.String_Access; Commit : aliased GNAT.Strings.String_Access; Pin_All : aliased Boolean; Unpin : aliased Boolean; URL : aliased GNAT.Strings.String_Access; end record; end Alr.Commands.Pin; alire-1.2.1/src/alr/alr-commands-printenv.adb000066400000000000000000000057571430264165500210700ustar00rootroot00000000000000with Alire.Environment; with Alire.Platforms; package body Alr.Commands.Printenv is ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is Enabled : Natural := 0; begin if Args.Count /= 0 then Reportaise_Wrong_Arguments (Cmd.Name & " doesn't take arguments"); end if; -- Check no multi-action Enabled := Enabled + (if Cmd.Details then 1 else 0); Enabled := Enabled + (if Cmd.Unix_Shell then 1 else 0); Enabled := Enabled + (if Cmd.Power_Shell then 1 else 0); Enabled := Enabled + (if Cmd.Cmd_Shell then 1 else 0); if Enabled > 1 then Reportaise_Wrong_Arguments ("Specify at most one subcommand"); end if; Cmd.Requires_Full_Index; Cmd.Requires_Valid_Session; declare Context : constant Alire.Environment.Context := Cmd.Root.Build_Context; begin if Cmd.Details then Context.Print_Details; elsif Cmd.Power_Shell then Context.Print_Shell (Alire.Platforms.PowerShell); elsif Cmd.Cmd_Shell then Context.Print_Shell (Alire.Platforms.WinCmd); else Context.Print_Shell (Alire.Platforms.Unix); end if; end; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Print the environment variables used to build the crate." & " This command can be used to setup a build environment," & " for instance before starting an IDE.") .New_Line .Append ("Examples:") .Append (" - eval $(alr printenv --unix)") .Append (" - alr printenv --powershell | Invoke-Expression") ); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Details'Access, "", "--details", "Print details about the environment variables and " & "their origin"); Define_Switch (Config, Cmd.Unix_Shell'Access, "", "--unix", "Use a UNIX shell format for the export (default)"); Define_Switch (Config, Cmd.Power_Shell'Access, "", "--powershell", "Use a Windows PowerShell format for the export"); Define_Switch (Config, Cmd.Cmd_Shell'Access, "", "--wincmd", "Use a Windows CMD shell format for the export"); end Setup_Switches; end Alr.Commands.Printenv; alire-1.2.1/src/alr/alr-commands-printenv.ads000066400000000000000000000020751430264165500210770ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Printenv is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("printenv"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Print the build environment variables"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is (""); private type Command is new Commands.Command with record Details : aliased Boolean := False; Unix_Shell : aliased Boolean := False; Power_Shell : aliased Boolean := False; Cmd_Shell : aliased Boolean := False; end record; end Alr.Commands.Printenv; alire-1.2.1/src/alr/alr-commands-publish.adb000066400000000000000000000100021430264165500206440ustar00rootroot00000000000000with Alire.Origins; with Alire.Publish; with Alire.URI; with Alire.Utils; package body Alr.Commands.Publish is package URI renames Alire.URI; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is function Revision return String is (if Args.Count >= 2 then Args (2) else ""); Options : constant Alire.Publish.All_Options := Alire.Publish.New_Options (Manifest => (if Cmd.Manifest.all /= "" then Cmd.Manifest.all else Alire.Roots.Crate_File_Name), Skip_Build => Cmd.Skip_Build); begin if Alire.Utils.Count_True ((Cmd.Tar, Cmd.Print_Trusted)) > 1 or else (Cmd.Manifest.all /= "" and then Cmd.Print_Trusted) then Reportaise_Wrong_Arguments ("Given switches cannot be simultaneously set"); end if; if Cmd.Print_Trusted then Alire.Publish.Print_Trusted_Sites; elsif Cmd.Tar then if Args.Count > 2 then Reportaise_Wrong_Arguments ("Unknown extra arguments, only a mandatory URL" & " and optional revision are expected"); end if; Alire.Publish.Directory_Tar (Path => (if Args.Count >= 1 then Args (1) else "."), Revision => (if Args.Count >= 2 then Args (2) else "HEAD"), Options => Options); else if Args.Count < 1 then Alire.Publish.Local_Repository (Options => Options); elsif Args.Count > 2 then Reportaise_Wrong_Arguments ("Unknown extra arguments, only a mandatory URL" & " and optional revision are expected"); else -- Choose between local path or remote declare use Alire.Origins; URL : constant String := Args (1); begin if URI.Scheme (URL) in URI.File_Schemes then if Archive_Format (URI.Local_Path (URL)) /= Unknown then -- This is a local tarball posing as a remote. Will fail -- unless forced. Alire.Publish.Remote_Origin (URL => URL, Commit => Revision, Options => Options); else -- Otherwise this is publishing based on local repo Alire.Publish.Local_Repository (Path => URL, Revision => Revision, Options => Options); end if; else Alire.Publish.Remote_Origin (URL => URL, Commit => Revision, -- TODO: allow non-commits Options => Options); end if; end; end if; end if; end Execute; -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Manifest'Access, "", "--manifest=", "Selects a manifest file other than ./alire.toml"); Define_Switch (Config, Cmd.Tar'Access, "", "--tar", "Start the publishing assistant to create a source archive" & " from a local directory"); Define_Switch (Config, Cmd.Print_Trusted'Access, "", "--trusted-sites", "Print a list of trusted git repository sites"); Define_Switch (Config, Cmd.Skip_Build'Access, "", "--skip-build", "Skip the build check step"); end Setup_Switches; end Alr.Commands.Publish; alire-1.2.1/src/alr/alr-commands-publish.ads000066400000000000000000000044411430264165500206770ustar00rootroot00000000000000with AAA.Strings; private with GNAT.Strings; package Alr.Commands.Publish is -- Publish lends a helping hand to automate submission of crates/releases. type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("publish"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Checks a release and generates an index manifest") .New_Line .Append ("See full details at") .New_Line .Append (" https://github.com/alire-project/alire/blob/master/" & "doc/publishing.md") .New_Line .Append ("URL is an optional path to a remote source archive, or" & " a local or remote git repository.") .New_Line .Append ("For the common use case of a github-hosted repository," & " issue `alr publish` after committing and pushing" & " the new release version.") .New_Line .Append ("Use --tar to create a source archive ready to be uploaded.") .New_Line .Append ("Use --manifest to use metadata in a non-default file.") .New_Line .Append ("See the above link for help with other scenarios.")); overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Help with the publication of a new release"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[--skip-build] [--tar] [--manifest ] [ [commit]]]"); private type Command is new Commands.Command with record Manifest : aliased GNAT.Strings.String_Access; -- A manifest to use instead of the default one. Print_Trusted : aliased Boolean := False; Skip_Build : aliased Boolean := False; -- Skip the build check Tar : aliased Boolean := False; -- Start the assistant from a local folder to be tar'ed and uploaded end record; end Alr.Commands.Publish; alire-1.2.1/src/alr/alr-commands-run.adb000066400000000000000000000213551430264165500200170ustar00rootroot00000000000000with Ada.Containers; with Alire.OS_Lib; with Alire.Platforms.Current; with Alr.Commands.Build; with Alr.Files; with Alr.OS_Lib; with Alire.Utils; with GNAT.OS_Lib; package body Alr.Commands.Run is use type Ada.Containers.Count_Type; Max_Search_Depth : constant := 3; -- How many levels to go down looking for built executables, -- relative to the build folder of the root crate ------------------ -- Check_Report -- ------------------ procedure Check_Report (Cmd : in out Command; Exe_Name : String) is use Ada.Text_IO; Found_At : constant AAA.Strings.Vector := Files.Locate_File_Under (Cmd.Root.Path, Exe_Name, Max_Depth => Max_Search_Depth); begin Put (" " & Exe_Name); case Found_At.Length is when 0 => Put_Line (" (not found)"); when 1 => Put_Line (" (found at " & Found_At.First_Element & ")"); when others => New_Line; for Bin of Found_At loop Put_Line (" (found at " & Bin & ")"); end loop; end case; end Check_Report; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is use type GNAT.Strings.String_Access; Name : constant String := Cmd.Root.Release.Name_Str; Declared : constant AAA.Strings.Vector := Cmd.Root.Release.Executables (Alire.Platforms.Current.Properties); ---------- -- List -- ---------- -- List declared/found executables procedure List is Candidates : constant AAA.Strings.Vector := Files.Locate_File_Under (Cmd.Root.Path, Cmd.Root.Release.Default_Executable, Max_Depth => Max_Search_Depth); -- Candidate default executable begin if Declared.Is_Empty then Put_Line ("Crate " & Name & " does not explicitly declares to build any executable"); if Candidates.Is_Empty then Put_Line ("No default executable has been automatically " & "found either by alr"); else Put_Line ("However, the following default executables" & " have been autodetected:"); Check_Report (Cmd, Cmd.Root.Release.Default_Executable); end if; else Put_Line ("Crate " & Name & " builds these executables:"); for Exe of Declared loop Check_Report (Cmd, Exe); end loop; -- Default one: if not Declared.Contains (Cmd.Root.Release.Default_Executable) and then not Candidates.Is_Empty then Put_Line ("In addition, the following default-named" & " executables have been detected:"); Check_Report (Cmd, Cmd.Root.Release.Default_Executable); end if; end if; end List; begin Cmd.Requires_Valid_Session; -- Validation if Cmd.List and then (Args.Count /= 0 or else (Cmd.Args /= null and then Cmd.Args.all /= "")) then Reportaise_Wrong_Arguments ("Listing is incompatible with execution"); end if; if not Cmd.List and then Args.Count > 1 then Reportaise_Wrong_Arguments ("Too many arguments"); end if; declare Declared : AAA.Strings.Vector; begin Declared := Cmd.Root.Release.Executables (Alire.Platforms.Current.Properties); -- LISTING -- if Cmd.List then List; return; end if; -- COMPILATION -- if not Cmd.No_Compile then if not Commands.Build.Execute (Cmd, Args => AAA.Strings.Empty_Vector, Export_Build_Env => True) then Reportaise_Command_Failed ("Build failed"); end if; end if; -- EXECUTION -- -- Do not default if more than one declared executable. Otherwise use -- either the declared executable or, by lack of that, an executable -- with the name of the crate. if Args.Count = 0 and then Natural (Declared.Length) > 1 then Trace.Error ("No executable specified but " & "the release builds more than one executable:"); List; return; end if; -- Also do not accept an explicit executable not listed (unless -- the release declares no executables and the requested one is -- the default one, e.g., same as running without argument). if Args.Count = 1 and then not Declared.Contains (Args (1)) and then Args (1) /= Cmd.Root.Release.Default_Executable then Reportaise_Wrong_Arguments ("The requested executable is not built by this release" & " (see declared list with 'alr run --list')"); end if; -- Proceed to run the requested executable, or if none requested, -- the single one declared, or if none, the default named one. declare Target_WO_Ext : constant String := (if Args.Count = 1 then Args (1) else (if Declared.Length = 1 then Declared.First_Element else Cmd.Root.Release.Default_Executable)); Target : constant String := (if Alire.OS_Lib.Exe_Suffix /= "" and then not AAA.Strings.Contains (Target_WO_Ext, Alire.OS_Lib.Exe_Suffix) then Target_WO_Ext & Alire.OS_Lib.Exe_Suffix else Target_WO_Ext); Target_Exes : AAA.Strings.Vector := Files.Locate_File_Under (Cmd.Root.Path, Target, Max_Depth => Max_Search_Depth); begin -- Ensure that a found default executable is indeed executable: if Declared.Is_Empty and then Target_Exes.Length = 1 and then not GNAT.OS_Lib.Is_Executable_File (Target_Exes.First_Element) then Trace.Warning ("Candidate to default executable is not an executable file: " & Target_Exes.First_Element); Target_Exes.Clear; end if; -- Finally launch a single target executable, or error otherwise: if Target_Exes.Is_Empty then Reportaise_Command_Failed ("Executable " & Alire.Utils.Quote (Target) & " not found"); elsif Natural (Target_Exes.Length) > 1 then Trace.Error ("Too many candidates found:"); for Candid of Target_Exes loop Log (Candid); end loop; else Trace.Detail ("Launching " & Target_Exes.First_Element); Trace.Detail ("..."); OS_Lib.Spawn_Raw (Target_Exes.First_Element, Cmd.Args.all); end if; end; end; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Compiles the crate (unless --skip-build is specified)" & " and then executes the default or given resulting" & " executable. ") .New_Line .Append ("With --list, a list of declared executables is produced" & " instead of invoking the compiler, and" & " its location (if already built) is given.") ); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Args'Access, "-a:", "--args=", "Arguments to pass through (quote them if more than one)", Argument => "ARGS"); Define_Switch (Config, Cmd.List'Access, "", "--list", "List executables produced by current release"); Define_Switch (Config, Cmd.No_Compile'Access, "-s", "--skip-build", "Skip building step"); end Setup_Switches; end Alr.Commands.Run; alire-1.2.1/src/alr/alr-commands-run.ads000066400000000000000000000021271430264165500200340ustar00rootroot00000000000000with AAA.Strings; with GNAT.Strings; package Alr.Commands.Run is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("run"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Launch an executable built by the release"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[executable] [--args=ARGS] [--skip-build] | [--list]"); private type Command is new Commands.Command with record Args : aliased GNAT.Strings.String_Access; List : aliased Boolean := False; No_Compile : aliased Boolean := False; end record; end Alr.Commands.Run; alire-1.2.1/src/alr/alr-commands-search.adb000066400000000000000000000260701430264165500204570ustar00rootroot00000000000000with Alire.Crates.Containers; with Alire.Externals; with Alire.Index.Search; with Alire.Platforms.Current; with Alire.Releases.Containers; with Alire.Solutions; with Alire.Solver; with Alire.Utils; with Alire.Utils.Tables; with Alire.Utils.TTY; with Semantic_Versioning; package body Alr.Commands.Search is package Platform renames Alire.Platforms.Current; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is Found : Natural := 0; Tab : Alire.Utils.Tables.Table; Flag_System : constant String := TTY.OK ("S"); Flag_Unav : constant String := TTY.Error ("U"); Flag_Unsolv : constant String := TTY.Error ("X"); Flag_External : constant String := TTY.Warn ("E"); ------------------ -- List_Release -- ------------------ procedure List_Release (R : Alire.Releases.Release) is package Solver renames Alire.Solver; begin Trace.Debug ("Listing release: " & R.Milestone.TTY_Image); if (Cmd.Prop.all = "" or else R.Property_Contains (Cmd.Prop.all) or else AAA.Strings.Contains (R.Notes, Cmd.Prop.all) or else AAA.Strings.Contains (R.Description, Cmd.Prop.all)) and then (Cmd.External or else not R.Origin.Is_System) then Found := Found + 1; Tab.New_Row; Tab.Append (Alire.Utils.TTY.Name (+R.Name)); Tab.Append ((if R.Origin.Is_System then Flag_System else " ") & (if R.Is_Available (Platform.Properties) then " " else Flag_Unav) & (if R.Origin.Is_System then " " else (if Solver.Is_Resolvable (R.Dependencies (Platform.Properties), Platform.Properties, Alire.Solutions.Empty_Valid_Solution, Options => (Age => Query_Policy, Interactive => False, others => <>)) then " " else Flag_Unsolv))); Tab.Append (TTY.Version (Semantic_Versioning.Image (R.Version))); Tab.Append (TTY.Description (R.Description)); Tab.Append (R.Notes); end if; end List_Release; --------------------- -- List_Undetected -- --------------------- procedure List_Undetected (Name : Alire.Crate_Name; Ext : Alire.Externals.External'Class) is begin Found := Found + 1; Tab.New_Row; Tab.Append (+Name); Tab.Append (Flag_External & (if Cmd.Detect then Flag_Unav else " ") & " "); Tab.Append ("external"); Tab.Append (Alire.Index.Crate (Name).TTY_Description); Tab.Append (Ext.Image); end List_Undetected; use Alire.Releases.Containers.Release_Sets; begin -- First, simpler case of search into crates if Cmd.Crates then -- Search into crates if Alire.Utils.Count_True ((Cmd.Detect, Cmd.External, Cmd.Full, Cmd.Prop.all /= "")) > 0 then Reportaise_Wrong_Arguments ("Extra switches are incompatible with --crates"); end if; if Cmd.List and then Args.Count /= 0 then Reportaise_Wrong_Arguments ("Search substring and --list are incompatible"); end if; Cmd.Requires_Full_Index; Alire.Index.Search.Print_Crates (Substring => (case Args.Count is when 0 => "", when 1 => Args (1), when others => raise Wrong_Command_Arguments with "Only one search substring supported")); return; end if; -- Remaining processing is for releases if Cmd.Detect then Cmd.External := True; end if; if Args.Count = 0 and then not Cmd.List and then Cmd.Prop.all = "" then -- no search term, nor --list, nor --prop Reportaise_Wrong_Arguments ("Please provide a search term, --property, or use" & " --list to show all available releases"); end if; if Args.Count = 0 and then Cmd.Prop.all /= "" then Cmd.List := True; end if; if Cmd.List and then Args.Count /= 0 then Reportaise_Wrong_Arguments ("Listing is incompatible with searching"); end if; -- End of option verification, start of search. First load the index, -- required to look at its entries. Cmd.Requires_Full_Index; Tab.Append (TTY.Bold ("NAME")); Tab.Append (TTY.Bold ("STATUS")); Tab.Append (TTY.Bold ("VERSION")); Tab.Append (TTY.Bold ("DESCRIPTION")); Tab.Append (TTY.Bold ("NOTES")); declare Busy : Simple_Logging.Ongoing := Simple_Logging.Activity ("Searching"); ------------------------ -- List_All_Or_Latest -- ------------------------ procedure List_All_Or_Latest (Crate : Alire.Crates.Crate) is begin if Cmd.Full then for Release of reverse Crate.Releases loop List_Release (Release); Busy.Step; end loop; elsif not Crate.Releases.Is_Empty then List_Release (Crate.Releases.Last_Element); Busy.Step; end if; end List_All_Or_Latest; -------------------- -- List_Externals -- -------------------- procedure List_Externals (Crate : Alire.Crates.Crate) is begin if Cmd.External then -- We must show only externals that have failed detection -- (otherwise they'll appear as normal releases with --detect). for External of Crate.Externals loop if not Cmd.Detect or else External.Detect (Crate.Name).Is_Empty then List_Undetected (Crate.Name, External); end if; end loop; end if; end List_Externals; ---------------- -- List_Crate -- ---------------- procedure List_Crate (Crate : Alire.Crates.Crate) is begin if Cmd.Detect then Alire.Index.Detect_Externals (Crate.Name, Platform.Properties); end if; List_All_Or_Latest (Crate); List_Externals (Crate); Busy.Step; end List_Crate; I : Alire.Crates.Containers.Maps.Cursor := Alire.Index.All_Crates.First; -- Cursor-based iteration because external detection during listing -- may cause addition of new crates, and that triggers tampering -- checks in some compiler versions. use Alire.Crates.Containers.Maps; begin if Cmd.List then Trace.Detail ("Searching..."); else Trace.Detail ("Searching " & Alire.Utils.Quote (Args (1)) & "..."); end if; while Has_Element (I) loop declare Crate : Alire.Crates.Crate renames Element (I); Pattern : constant String := (if Cmd.List then "" else Args (1)); begin if Cmd.List then -- List all releases List_Crate (Crate); else -- Search into release names if AAA.Strings.Contains (+Crate.Name, Pattern) then List_Crate (Crate); end if; end if; end; Next (I); end loop; end; if Found = 0 then Log ("No hits "); else Tab.Print (Always, Separator => " "); end if; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Searches the given substring in crate names (or properties" & " with --property), and shows the most recent release" & " of matching crates (unless --full is specified).") .New_Line .Append ("Use --crates to get a simple list of only crate names and " & " descriptions. Otherwise," & " besides version, description and release notes, a status" & " column with the following status flags is provided:") .New_Line .Append ("E: the release is externally provided.") .Append ("S: the release is available through a system package.") .Append ("U: the release is not available in the current platform.") .Append ("X: the release has dependencies that cannot be resolved.") .New_Line .Append ("The reasons for unavailability (U) can be ascertained with" & " 'alr show ='.") .New_Line .Append ("Unresolvable releases (X) should not happen in platforms" & " with assigned maintainers. Common reasons are missing" & " system dependencies that have been phased out by the" & " platform without being updated yet in the community" & " index.") ); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Crates'Access, "", "--crates", "Restrict search and output to crate names and descriptions"); Define_Switch (Config, Cmd.Detect'Access, "", "--external-detect", "Detect externally-provided releases (implies --external)"); Define_Switch (Config, Cmd.Full'Access, "", "--full", "Show all versions of a crate (newest only otherwise)"); Define_Switch (Config, Cmd.List'Access, "", "--list", "List all available releases"); Define_Switch (Config, Cmd.External'Access, "", "--external", "Include externally-provided releases in search"); Define_Switch (Config, Cmd.Prop'Access, "", "--property=", "Search TEXT in property values", Argument => "TEXT"); end Setup_Switches; end Alr.Commands.Search; alire-1.2.1/src/alr/alr-commands-search.ads000066400000000000000000000023311430264165500204720ustar00rootroot00000000000000with AAA.Strings; private with GNAT.Strings; package Alr.Commands.Search is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("search"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding function Short_Description (Cmd : Command) return String is ("Search a string in release names and properties"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is (" | [--crates] [--full] --list"); overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); private type Command is new Commands.Command with record Crates : aliased Boolean := False; Detect : aliased Boolean := False; Full : aliased Boolean := False; List : aliased Boolean := False; External : aliased Boolean := False; Prop : aliased GNAT.Strings.String_Access; end record; end Alr.Commands.Search; alire-1.2.1/src/alr/alr-commands-show.adb000066400000000000000000000274061430264165500201760ustar00rootroot00000000000000with Ada.Containers; with Alire.Conditional; with Alire.Dependencies; with Alire.Index; with Alire.Milestones; with Alire.Platforms.Current; with Alire.Releases.Containers; with Alire.Root; with Alire.Roots.Optional; with Alire.Solutions; with Alire.Solver; with Alire.Utils.Tables; with Alire.Utils; with Semantic_Versioning.Extended; package body Alr.Commands.Show is use type Ada.Containers.Count_Type; package Platform renames Alire.Platforms.Current; package Query renames Alire.Solver; package Semver renames Semantic_Versioning; ------------ -- Report -- ------------ procedure Report (Name : Alire.Crate_Name; Versions : Semver.Extended.Version_Set; Current : Boolean; -- session or command-line requested release Cmd : in out Command) is begin if Current then Trace.Debug ("Showing workspace definitions"); else Trace.Debug ("Showing definitions from index releases"); end if; declare -- Nested so a failure in Query.Find is caught below Candidates : constant Alire.Releases.Containers.Release_Set := (if Current then Alire.Releases.Containers.To_Set (Cmd.Root.Release) else Alire.Index.Releases_Satisfying (Alire.Dependencies.New_Dependency (Name, Versions), Platform.Properties, Use_Equivalences => False, Available_Only => False)); Rel : constant Alire.Releases.Release := (if Candidates.Is_Empty then raise Alire.Query_Unsuccessful else Candidates.Last_Element); -- Last is newest begin if Cmd.System then Rel.Whenever (Platform.Properties).Print; else Rel.Print; end if; if Rel.Origin.Is_System then Put_Line ("Platform package: " & Rel.Origin.Package_Name); end if; if Cmd.Graph or else Cmd.Solve or else Cmd.Tree then Cmd.Requires_Full_Index (Force_Reload => True); declare Needed : constant Query.Solution := (if Current then Cmd.Root.Solution else Query.Resolve (Rel.Dependencies (Platform.Properties), Platform.Properties, Alire.Solutions.Empty_Valid_Solution, Options => (Age => Query_Policy, others => <>))); begin if Cmd.Solve then Needed.Print (Rel, Platform.Properties, Cmd.Detail, Always); elsif Cmd.Tree then if Needed.Crates.Length not in 0 then Trace.Always ("Dependencies (tree):"); Needed.Print_Tree (Rel, Prefix => " ", Print_Root => False); end if; elsif Cmd.Graph then if Needed.Crates.Length not in 0 then Trace.Always ("Dependencies (graph):"); Needed.Print_Graph (Rel, Platform.Properties); end if; end if; if not Needed.Is_Complete then Put_Line ("Dependencies cannot be met"); end if; end; end if; end; exception when Alire.Query_Unsuccessful => Trace.Info ("Not found: " & Alire.Dependencies.New_Dependency (Name, Versions).TTY_Image); if not Alire.Index.Crate (Name).Externals.Is_Empty then Trace.Info ("There are external definitions for the crate. " & "Use --external to show them."); end if; end Report; ---------------------- -- Report_Externals -- ---------------------- procedure Report_Externals (Name : Alire.Crate_Name; Cmd : Command) is use Alire; Table : Utils.Tables.Table; begin if Alire.Index.Crate (Name).Externals.Is_Empty then Trace.Info ("No externals defined for the requested crate."); else Table .Append ("Kind") .Append ("Description") .Append ("Details") .Append ("Available"); for External of Alire.Index.Crate (Name).Externals loop Table.New_Row; declare Detail : constant AAA.Strings.Vector := External.Detail (if Cmd.System then Alire.Platforms.Current.Distribution else Alire.Platforms.Distro_Unknown); Available : Alire.Conditional.Availability := (if Cmd.System then External.On_Platform (Platform.Properties).Available else External.Available); begin -- Improve the looks of a default Available if Available.Is_Empty then Available := Alire.Conditional.Available_Default; end if; for I in Detail.First_Index .. Detail.Last_Index loop -- Skip last element, which is unknown distro Table .Append (if I = Detail.First_Index then External.Kind else "") .Append (if I = Detail.First_Index then External.Image else "") .Append (Detail (I)) .Append (if I = Detail.First_Index then Available.Image_One_Line else ""); if I /= Detail.Last_Index then Table.New_Row; end if; end loop; end; end loop; Table.Print (Always); end if; end Report_Externals; ------------------- -- Report_Jekyll -- ------------------- procedure Report_Jekyll (Cmd : in out Command; Name : Alire.Crate_Name; Versions : Semver.Extended.Version_Set; Current : Boolean) is begin declare Rel : constant Alire.Releases.Release := (if Current then Cmd.Root.Release else Query.Find (Name, Versions, Query_Policy)); begin Put_Line ("---"); Put_Line ("layout: crate"); -- TODO: conditional expressions can't be exported yet, we report in -- the interim the ones that apply to the current system. Put_Line (Rel.Whenever (Platform.Properties).To_YAML); Put_Line ("---"); Put_Line (Rel.Long_Description); Put_Line (Rel.Notes); end; exception when Alire.Query_Unsuccessful => Trace.Info ("Not found: " & Alire.Dependencies.New_Dependency (Name, Versions).TTY_Image); end Report_Jekyll; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is begin if Args.Count > 1 then Reportaise_Wrong_Arguments ("Too many arguments"); end if; if Args.Count = 0 then if Alire.Root.Current.Outside then Reportaise_Wrong_Arguments ("Cannot proceed without a crate name"); else Cmd.Requires_Valid_Session; end if; end if; if Cmd.External and then (Cmd.Detect or Cmd.Jekyll or Cmd.Graph or Cmd.Solve or Cmd.Tree) then Reportaise_Wrong_Arguments ("Switch --external can only be combined with --system"); end if; declare Allowed : constant Alire.Dependencies.Dependency := (if Args.Count = 1 then Alire.Dependencies.From_String (Args (1)) else Alire.Dependencies.From_String (Cmd.Root.Release.Milestone.Image)); begin if Args.Count = 1 then Cmd.Load (Allowed.Crate, Externals => Cmd.Detect); if not Alire.Index.Exists (Allowed.Crate) then raise Alire.Query_Unsuccessful; end if; end if; -- Execute if Cmd.Jekyll then Report_Jekyll (Cmd, Allowed.Crate, Allowed.Versions, Args.Count = 0); elsif Cmd.External then Report_Externals (Allowed.Crate, Cmd); else Report (Allowed.Crate, Allowed.Versions, Args.Count = 0, Cmd); end if; exception when Alire.Query_Unsuccessful => Reportaise_Command_Failed ("Crate " & Allowed.TTY_Image & " does not exist in the index"); end; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Shows information found in the loaded indexes about a" & " specific release (see below to narrow the searched" & " milestones). By default, only direct dependencies are" & " reported. With --solve, a full solution is resolved and" & " reported in list and graph form.") .New_Line .Append ("With --external, the external definitions for a crate are" & " shown, instead of information about a particular release") .New_Line .Append (Crate_Version_Sets)); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Detail'Access, "", "--detail", "Show additional details about dependencies"); Define_Switch (Config, Cmd.Detect'Access, "", "--external-detect", "Add detected externals to available releases"); Define_Switch (Config, Cmd.External'Access, "", "--external", "Show info about external definitions for a crate"); Define_Switch (Config, Cmd.Graph'Access, "", "--graph", "Print ASCII graph of dependencies"); Define_Switch (Config, Cmd.System'Access, "", "--system", "Show info relevant to current environment"); Define_Switch (Config, Cmd.Solve'Access, "", "--solve", "Solve dependencies and report"); Define_Switch (Config, Cmd.Tree'Access, "", "--tree", "Show complete dependency tree"); Define_Switch (Config, Cmd.Jekyll'Access, "", "--jekyll", "Enable Jekyll output format"); end Setup_Switches; end Alr.Commands.Show; alire-1.2.1/src/alr/alr-commands-show.ads000066400000000000000000000024651430264165500202150ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Show is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("show"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("See information about a release"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[[allowed versions]] [--system] [--external[-detect]" & " | --graph | --jekyll | --solve | --tree"); private type Command is new Commands.Command with record Detail : aliased Boolean := False; Detect : aliased Boolean := False; External : aliased Boolean := False; Graph : aliased Boolean := False; Solve : aliased Boolean := False; System : aliased Boolean := False; Tree : aliased Boolean := False; Jekyll : aliased Boolean := False; end record; end Alr.Commands.Show; alire-1.2.1/src/alr/alr-commands-skeleton.ads000066400000000000000000000027301430264165500210540ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Skeleton is -- Empty command that you can rename to provide a new command. See also -- subprogram documentation in Alr.Commands spec. You need also to add its -- entry in the Alr.Commands.Dispatch_Table (in the body). type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return String is ("skeleton"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is null; -- This is called once the command-line is parsed. overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Replace this description with yours.") .Append ("Every single line will be reformatted into 79-column-wide" & " paragraphs.") .New_Line .Append ("You can use empty lines for structure with New_Line")); overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is null; overriding function Short_Description (Cmd : Command) return String is ("Your one-liner description of the command"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("Parameters expected after the command name"); private type Command is new Commands.Command with null record; end Alr.Commands.Skeleton; alire-1.2.1/src/alr/alr-commands-test.adb000066400000000000000000000526731430264165500202010ustar00rootroot00000000000000with Ada.Calendar; with Ada.Directories; with Ada.Exceptions; with Ada.Containers; with Alire.Crates; with Alire.Defaults; with Alire.Dependencies; with Alire.Directories; with Alire.Index; with Alire.Milestones; with Alire.Origins; with Alire.OS_Lib.Subprocess; with Alire.Platforms.Current; with Alire.Properties.Actions.Executor; with Alire.Releases.Containers; with Alire.Solutions; with Alire.Solver; with Alire.Utils; with Alr.Files; with Alr.Paths; with Alr.Testing.Collections; with Alr.Testing.Console; with Alr.Testing.JUnit; with Alr.Testing.Markdown; with Alr.Testing.Text; with GNATCOLL.VFS; with CLIC.User_Input; package body Alr.Commands.Test is use type Ada.Containers.Count_Type; package Platform renames Alire.Platforms.Current; package Query renames Alire.Solver; Docker_Switch : constant String := "--docker"; ----------------- -- Check_Files -- ----------------- function Check_Files (Output : in out AAA.Strings.Vector; R : Alire.Index.Release) return Boolean is use AAA.Strings; use Ada.Directories; begin -- Declared GPR files in include paths declare Guard : Folder_Guard (Enter_Folder (R.Base_Folder)) with Unreferenced; begin -- Check project files. We allow a binary release to not contain -- project files, but if it declares a non-standard one (why?) it -- should be there. for Gpr of R.Project_Files (Platform.Properties, With_Path => True) loop if OS_Lib.Is_Regular_File (Gpr) then Output.Append_Line ("Found declared GPR file: " & Gpr); elsif R.Origin.Kind in Alire.Origins.Binary_Archive and then To_Lower_Case (Base_Name (Gpr)) = R.Name_Str then Output.Append_Line ("Warning: Binary release does not contain default " & "project file: " & Simple_Name (Gpr)); else Output.Append_Line ("FAIL: Declared project file not found: " & Gpr & " while at " & Ada.Directories.Current_Directory); return False; end if; end loop; end; -- Generated executables for Exe of R.Executables (Platform.Properties) loop if Files.Locate_File_Under (Folder => R.Base_Folder, Name => Exe, Max_Depth => Natural'Last).Is_Empty then Output.Append_Line ("FAIL: Declared executable not found after compilation: " & Exe); return False; end if; end loop; return True; end Check_Files; ------------- -- Do_Test -- ------------- procedure Do_Test (Cmd : Command; Releases : Alire.Releases.Containers.Release_Sets.Set; Docker_Image : String) is use Ada.Calendar; use GNATCOLL.VFS; use OS_Lib.Paths; Some_Failed : Boolean := False; Reporters : Testing.Collections.Collection; No_Log : constant AAA.Strings.Vector := (AAA.Strings.Vectors.Empty_Vector with null record); Is_Available, Is_Resolvable : Boolean; Timestamp : constant String := AAA.Strings.Trim (Long_Long_Integer'Image (Long_Long_Integer (Clock - Time_Of (1970, 1, 1)))); Newline : constant String := "" & ASCII.LF; ------------------ -- Test_Release -- ------------------ procedure Test_Release (R : Alire.Releases.Release) is Output : AAA.Strings.Vector; Start : Time; ----------------- -- Test_Action -- ----------------- procedure Test_Action is use AAA.Strings; use Ada.Directories; use Alire.OS_Lib.Subprocess; Docker_Prefix : constant AAA.Strings.Vector := Empty_Vector & "sudo" & "docker" & "run" & String'("-v" & Locate_In_Path ("alr") & ":/usr/bin/alr") -- Map executable & String'("-v" & Current_Directory & ":/work") -- Map working folder & "-w" & "/work" & "--user" & Alire.OS_Lib.Getenv ("UID", "1000") -- Map current user & Docker_Image; Custom_Alr : constant AAA.Strings.Vector := Empty_Vector & "alr" & "-c" & "/tmp/alire"; -- When running inside docker as regular user we need config to be -- stored in a writable folder. ------------------ -- Default_Test -- ------------------ procedure Default_Test is Alr_Args : constant AAA.Strings.Vector := Empty_Vector & "-d" & "-n" & "get" & (if R.Origin.Kind in Alire.Origins.Binary_Archive then Empty_Vector else To_Vector ("--build")) & R.Milestone.Image; Docker_Default : constant AAA.Strings.Vector := Docker_Prefix & Custom_Alr & Alr_Args; Alr_Default : constant AAA.Strings.Vector := "alr" & Alr_Args; Exit_Code : Integer; begin if Alire.Utils.Command_Line_Contains (Docker_Switch) then Exit_Code := Unchecked_Spawn_And_Capture (Docker_Default.First_Element, Docker_Default.Tail, Output, Err_To_Out => True); else Exit_Code := Unchecked_Spawn_And_Capture (Alr_Default.First_Element, Alr_Default.Tail, Output, Err_To_Out => True); end if; if Exit_Code /= 0 then raise Child_Failed; end if; -- Check declared gpr/executables in place if not R.Origin.Is_System and then not Check_Files (Output, R) then raise Child_Failed with "Declared executable(s) missing"; end if; end Default_Test; ----------------- -- Custom_Test -- ----------------- procedure Custom_Test is Exit_Code : Integer; begin -- Fetch the crate if Alire.Utils.Command_Line_Contains (Docker_Switch) then Exit_Code := Unchecked_Spawn_And_Capture (Docker_Prefix.First_Element, Docker_Prefix.Tail & Custom_Alr & "get" & R.Name_Str, Output, Err_To_Out => True); else Exit_Code := Unchecked_Spawn_And_Capture ("alr", Empty_Vector & "-d" & "-n" & "get" & R.Name_Str, Output, Err_To_Out => True); end if; if Exit_Code /= 0 then raise Child_Failed; end if; -- And run its actions in its working directory declare Guard : Alire.Directories.Guard (Alire.Directories.Enter (R.Base_Folder)) with Unreferenced; begin for Action of R.On_Platform_Actions (Platform.Properties, (Alire.Properties.Actions.Test => True, others => False)) loop Alire.Properties.Actions.Executor.Execute_Actions (Release => R, Env => Platform.Properties, Moment => Alire.Properties.Actions.Test, Capture => True, Err_To_Out => True, Code => Exit_Code, Output => Output, Prefix => (if Alire.Utils.Command_Line_Contains (Docker_Switch) then Docker_Prefix else AAA.Strings.Empty_Vector)); if Exit_Code /= 0 then raise Child_Failed; end if; end loop; end; end Custom_Test; begin -- Run test actions if there are any, or a default get+build if R.On_Platform_Actions (Platform.Properties, (Alire.Properties.Actions.Test => True, others => False)).Is_Empty then Default_Test; else Custom_Test; end if; end Test_Action; begin Reporters.Start_Test (R); Start := Clock; Is_Available := R.Is_Available (Platform.Properties); Is_Resolvable := Query.Is_Resolvable (R.Dependencies (Platform.Properties), Platform.Properties, Alire.Solutions.Empty_Valid_Solution); if not Is_Available then Reporters.End_Test (R, Testing.Unavailable, Clock - Start, No_Log); elsif not Is_Resolvable then Some_Failed := True; Reporters.End_Test (R, Testing.Unresolvable, Clock - Start, No_Log); elsif not R.Origin.Is_System and then Ada.Directories.Exists (R.Base_Folder) and then not Cmd.Redo then Reporters.End_Test (R, Testing.Skip, Clock - Start, No_Log); Trace.Detail ("Skipping already tested " & R.Milestone.Image); else begin -- Perform default or custom actions Test_Action; Reporters.End_Test (R, Testing.Pass, Clock - Start, Output); Trace.Detail (Output.Flatten (Newline)); exception when E : Alire.Checked_Error => Reporters.End_Test (R, Testing.Fail, Clock - Start, Output); Trace.Detail (Output.Flatten (Newline)); Some_Failed := True; Output.Append ("****** Checked Error raised during test:"); Output.Append (Ada.Exceptions.Exception_Information (E)); Output.Append ("****** TRACE END"); when Child_Failed => Reporters.End_Test (R, Testing.Fail, Clock - Start, Output); Trace.Detail (Output.Flatten (Newline)); Some_Failed := True; when E : others => Reporters.End_Test (R, Testing.Error, Clock - Start, Output); Trace.Detail (Output.Flatten (Newline)); Some_Failed := True; Output.Append ("****** UNEXPECTED EXCEPTION FOLLOWS:"); Output.Append (Ada.Exceptions.Exception_Information (E)); Output.Append ("****** TRACE END"); end; end if; Make_Dir (Create (+R.Base_Folder) / Create (+Paths.Alr_Working_Folder)); -- Might not exist for system/failed/skipped Output.Write (R.Base_Folder / Paths.Alr_Working_Folder / "alr_test_" & Timestamp & ".log"); end Test_Release; begin Reporters.Add (Testing.Console.New_Reporter); Reporters.Add (Testing.JUnit.New_Reporter); Reporters.Add (Testing.Markdown.New_Reporter); Reporters.Add (Testing.Text.New_Reporter); Reporters.Start_Run ("alr_test_" & Timestamp, Natural (Releases.Length)); declare Old_Level : constant Simple_Logging.Levels := Alire.Log_Level; begin -- While we test the releases we do not want any info level output to -- interfere. So, if the level is set at the default, we temporarily -- silence it. if Old_Level = Info then Alire.Log_Level := Simple_Logging.Warning; end if; for R of Releases loop Test_Release (R); end loop; Alire.Log_Level := Old_Level; end; Reporters.End_Run; if Some_Failed then Reportaise_Command_Failed ("Some releases failed to pass testing"); end if; end Do_Test; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is Test_All : constant Boolean := Args.Count = 0; procedure Not_Empty (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean) is pragma Unreferenced (Item, Stop); begin Reportaise_Command_Failed ("Current folder is not empty, testing aborted " & "(use --continue to resume a partial test)"); end Not_Empty; Candidates : Alire.Releases.Containers.Release_Sets.Set; Docker_Image : constant String := (if Cmd.Docker.all = "" then Alire.Defaults.Docker_Test_Image else AAA.Strings.Replace (Cmd.Docker.all, "=", "")); use Alire.Releases.Containers.Release_Sets; --------------------- -- Find_Candidates -- --------------------- procedure Find_Candidates is -------------- -- Is_Match -- -------------- function Is_Match (Name : Alire.Crate_Name) return Boolean is (for some I in Args.First_Index .. Args.Last_Index => AAA.Strings.Contains (+Name, Args (I))); begin -- We must go over all crates when listing is requested, or when we -- need to match the search term against crate names. Otherwise, we -- can directly retrieve the given crates. if Test_All or else Cmd.Search then for Crate of Alire.Index.All_Crates.all loop if not Crate.Releases.Is_Empty then if Test_All or else Is_Match (Crate.Name) then if Cmd.Last then Candidates.Include (Crate.Releases.Last_Element); else for Release of Crate.Releases loop Candidates.Include (Release); end loop; end if; end if; end if; end loop; else for J in Args.First_Index .. Args.Last_Index loop declare Allowed : constant Alire.Dependencies.Dependency := Alire.Dependencies.From_String (Args (J)); Crate : constant Alire.Crates.Crate := Alire.Index.Crate (Allowed.Crate); Releases : constant Alire.Releases.Containers.Release_Set := Crate.Releases; begin for I in Releases.Iterate loop if Allowed.Versions.Contains (Releases (I).Version) then if not Cmd.Last or else I = Releases.Last or else not Allowed.Versions.Contains (Releases (Next (I)).Version) then Candidates.Include (Releases (I)); end if; end if; end loop; end; end loop; end if; end Find_Candidates; -------------------- -- Prepare_Docker -- -------------------- procedure Pull_Docker is use Alire.OS_Lib.Subprocess; use AAA.Strings; Output : AAA.Strings.Vector; Exit_Code : Integer; begin if Alire.Utils.Command_Line_Contains (Docker_Switch) then Trace.Info ("Running builds in docker image: " & Docker_Image); Exit_Code := Unchecked_Spawn_And_Capture ("sudo", Empty_Vector & "docker" & "pull" & Docker_Image, Output, Err_To_Out => True); if Exit_Code /= 0 then Reportaise_Command_Failed ("Failed to pull docker image " & Docker_Image & " with output: " & Output.Flatten (Separator => "" & ASCII.LF)); end if; end if; end Pull_Docker; begin -- Validate command line if not Cmd.Search then for I in Integer range Args.First_Index .. Args.Last_Index loop declare Cry_Me_A_River : constant Alire.Dependencies.Dependency := Alire.Dependencies.From_String (Args (I)) with Unreferenced; begin null; -- Just check that no exception is raised end; end loop; end if; -- Validate exclusive options if Cmd.Full and then (Args.Count /= 0 or else Cmd.Search) then Reportaise_Command_Failed ("Either use --full or specify crate names, but not both"); end if; -- Check in empty folder! if Cmd.Cont then Trace.Detail ("Resuming tests"); elsif Cmd.Redo then Trace.Detail ("Redoing tests"); else Alire.Directories.Traverse_Tree (Ada.Directories.Current_Directory, Not_Empty'Access); end if; CLIC.User_Input.Not_Interactive := True; -- Start testing if Test_All then if Cmd.Full then if Cmd.Last then Trace.Detail ("Testing newest release of every crate"); else Trace.Detail ("Testing all releases"); end if; else Reportaise_Command_Failed ("No releases specified; use --full to test'em all!"); end if; end if; Cmd.Requires_Full_Index; -- Pre-find candidates to not have duplicate tests if overlapping -- requested. Find_Candidates; if Candidates.Is_Empty then Reportaise_Command_Failed ("No releases for the requested crates"); else Trace.Detail ("Testing" & Candidates.Length'Img & " releases"); end if; Pull_Docker; Do_Test (Cmd, Candidates, Docker_Image); end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Tests the retrievability and buildability of all or" & " specific releases. Unless --continue or --redo is given," & " the command expects to be run in an empty folder.") .New_Line .Append ("After completion, a report in text, markup and junit format" & " will be available in the current directory. A complete log" & " of each release building process will be available in" & " respective /alire/alr_test.log files.") .New_Line .Append (Crate_Version_Sets)); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Cont'Access, Long_Switch => "--continue", Help => "Skip testing of releases already in folder"); Define_Switch (Config, Cmd.Docker'Access, Long_Switch => Docker_Switch & "?", -- ? for optional image tag Help => "Test releases within docker IMAGE" & " (or " & Alire.Defaults.Docker_Test_Image & ")", Argument => "=IMAGE"); Define_Switch (Config, Cmd.Full'Access, Long_Switch => "--full", Help => "Test all indexed crates"); Define_Switch (Config, Cmd.Last'Access, Long_Switch => "--newest", Help => "Test only the newest release in crates"); Define_Switch (Config, Cmd.Redo'Access, Long_Switch => "--redo", Help => "Retest releases already in folder (implies --continue)"); Define_Switch (Config, Cmd.Search'Access, Long_Switch => "--search", Help => "Interpret arguments as substrings instead of " & "exact crate names"); -- Define_Switch -- (Config, -- Cmd.Jobs'Access, -- "-j:", "--jobs=", -- "Tests up to N jobs in parallel, or as many as processors " & -- "if 0 (default)", -- Default => 0, -- Argument => "N"); end Setup_Switches; end Alr.Commands.Test; alire-1.2.1/src/alr/alr-commands-test.ads000066400000000000000000000022521430264165500202060ustar00rootroot00000000000000with AAA.Strings; with GNAT.Strings; package Alr.Commands.Test is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("test"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Tests the compilation of all or some releases"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[crate[versions]]..."); private type Command is new Commands.Command with record Cont : aliased Boolean := False; Docker : aliased GNAT.Strings.String_Access; Full : aliased Boolean := False; Last : aliased Boolean := False; Redo : aliased Boolean := False; Search : aliased Boolean := False; end record; end Alr.Commands.Test; alire-1.2.1/src/alr/alr-commands-toolchain.adb000066400000000000000000000420011430264165500211620ustar00rootroot00000000000000 with GNAT.Strings; use GNAT.Strings; with AAA.Table_IO; with Alire.Config.Edit; with Alire.Containers; with Alire.Dependencies; with Alire.Errors; with Alire.Index; with Alire.Milestones; with Alire.Origins.Deployers; with Alire.Platforms.Current; with Alire.Releases.Containers; with Alire.Shared; with Alire.Solver; with Alire.Toolchains; with Alire.Utils; use Alire.Utils; with Alire.Utils.TTY; with Alire.Warnings; with Semantic_Versioning.Extended; package body Alr.Commands.Toolchain is package Name_Sets renames Alire.Containers.Crate_Name_Sets; -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Disable'Access, Long_Switch => "--disable-assistant", Help => "Disable autorun of selection assistant"); Define_Switch (Config, Cmd.Install'Access, Switch => "-i", Long_Switch => "--install", Help => "Install one or more toolchain component"); Define_Switch (Config, Cmd.Install_Dir'Access, Long_Switch => "--install-dir=", Help => "Toolchain component(s) installation directory"); Define_Switch (Config, Cmd.Local'Access, Switch => "", Long_Switch => "--local", Help => "Store toolchain configuration in local workspace"); Define_Switch (Config, Cmd.S_Select'Access, Switch => "", Long_Switch => "--select", Help => "Run the toolchain selection assistant"); Define_Switch (Config, Cmd.Uninstall'Access, Switch => "-u", Long_Switch => "--uninstall", Help => "Uninstall one or more toolchain component"); end Setup_Switches; ------------- -- Install -- ------------- procedure Install (Cmd : in out Command; Request : String; Pending : Name_Sets.Set; Set_As_Default : Boolean) is use Alire; use all type Origins.Kinds; Dep : constant Dependencies.Dependency := Dependencies.From_String (Request); type Origin_States is (Unset, Frozen, Mixed); -- To detect what tool origins are already in use: Unset none, Frozen -- one kind, Mixed more than one kind. Origin_Status : Origin_States := Unset; Origin_Kind : Origins.Kinds; -- The Frozen kind in use ---------------------- -- Identify_Origins -- ---------------------- procedure Identify_Origins is ---------------------- -- Equivalent_Crate -- ---------------------- function Equivalent_Crate (L, R : Crate_Name) return Boolean is (L = R or else (AAA.Strings.Has_Prefix (L.As_String, "gnat_") and then R = GNAT_Crate) or else (AAA.Strings.Has_Prefix (R.As_String, "gnat_") and then L = GNAT_Crate) or else (AAA.Strings.Has_Prefix (L.As_String, "gnat_") and then AAA.Strings.Has_Prefix (R.As_String, "gnat_"))); begin for Tool of Toolchains.Tools loop -- A tool that is already configured, and not pending in the -- command-line, will impose an origin compatibility constraint if Toolchains.Tool_Is_Configured (Tool) and then not (for some P of Pending => Toolchains.Tool_Release (Tool).Provides (P) or else Equivalent_Crate (P, Tool)) and then not Toolchains.Tool_Release (Tool).Provides (Dep.Crate) then declare -- The one already selected we want to be compatible with Other_Tool : constant Releases.Release := Toolchains.Tool_Release (Tool); begin Trace.Debug ("Configured tool " & Utils.TTY.Name (Tool) & " has origin kind " & Other_Tool.Origin.Kind'Image); case Origin_Status is when Unset => Origin_Status := Frozen; Origin_Kind := Other_Tool.Origin.Kind; when Frozen => if Other_Tool.Origin.Kind /= Origin_Kind then Origin_Status := Mixed; end if; when Mixed => null; -- We are beyond salvation at this point end case; end; end if; end loop; if Origin_Status = Mixed then Warnings.Warn_Once ("Default toolchain contains mixed-origin tools"); else Trace.Debug ("Tool compatibility identified as " & Origin_Status'Image); end if; end Identify_Origins; begin -- We want to ensure that we are installing compatible tools. The user -- can force through this, so we consider that a bad situation may -- already exist. The following call checks what origins are already in -- use by configured tools. This is only relevant when setting defaults, -- though. if Set_As_Default then Identify_Origins; if Origin_Status = Frozen then Put_Info ("Already selected tool imposes on remaining tools to be " & "of origin " & Origin_Kind'Image, Trace.Detail); end if; end if; Cmd.Requires_Full_Index; Installation : declare ------------------- -- Origin_Filter -- ------------------- function Origin_Filter return Origins.Kinds_Set is Filter : Origins.Kinds_Set := (others => False); begin Filter (Origin_Kind) := True; return Filter; end Origin_Filter; Any_Origin : constant Origins.Kinds_Set := (others => True); Rel : constant Releases.Release := Solver.Find (Name => Dep.Crate, Allowed => Dep.Versions, Policy => Query_Policy, Origins => (if not Force and then Origin_Status = Frozen then Origin_Filter else Any_Origin)); function The_Other (Tool : Crate_Name) return Crate_Name is (if Tool = GPRbuild_Crate then GNAT_Crate else GPRbuild_Crate); -- This will break the moment we have another tool in the toolchain, -- so leave a canary here: pragma Assert (Natural (Alire.Toolchains.Tools.Length) = 2); begin -- Only allow sharing toolchain elements in this command: if not (for some Crate of Alire.Toolchains.Tools => Rel.Provides (Crate)) then Reportaise_Wrong_Arguments ("The requested crate is not a toolchain component"); end if; -- Inform of how the requested crate has been narrowed down if not AAA.Strings.Has_Prefix (Dep.Versions.Image, "=") then Put_Info ("Requested crate resolved as " & Rel.Milestone.TTY_Image); end if; -- Check for mixed-origin clashes if Origin_Status = Frozen and then Rel.Origin.Kind /= Origin_Kind then Recoverable_Error ("Currently configured " & Utils.TTY.Name (The_Other (Dep.Crate)) & " has origin " & TTY.Emph (Origin_Kind'Image) & " but newly selected " & Utils.TTY.Name (Dep.Crate) & " has origin " & TTY.Emph (Rel.Origin.Kind'Image) & ASCII.LF & "Mixing tool origins may result in a broken toolchain"); end if; -- And perform the actual installation if Cmd.Install_Dir.all /= "" then if Rel.Origin.Is_Regular then Shared.Share (Rel, Cmd.Install_Dir.all); else Reportaise_Command_Failed ("Releases with external origins cannot be installed at " & "specific locations; origin for " & Rel.Milestone.TTY_Image & " is: " & Rel.Origin.Kind'Image); end if; else if Rel.Origin.Is_Regular then Shared.Share (Rel); elsif Rel.Origin.Is_System then Origins.Deployers.Deploy (Rel).Assert; elsif Rel.Origin.Kind = External then Put_Info ("External tool needs no installation: " & Rel.Milestone.TTY_Image); else Raise_Checked_Error ("Unexpected release origin: " & Rel.Origin.Kind'Image); end if; end if; if Set_As_Default then Alire.Toolchains.Set_As_Default (Rel, Level => (if Cmd.Local then Alire.Config.Local else Alire.Config.Global)); Alire.Put_Info (Rel.Milestone.TTY_Image & " set as default in " & TTY.Emph (if Cmd.Local then "local" else "global") & " configuration."); end if; end Installation; exception when E : Alire.Query_Unsuccessful => Alire.Log_Exception (E); if Set_As_Default then Trace.Error (Alire.Errors.Get (E)); Reportaise_Command_Failed ("Use --force to override compatibility checks between " & "installed toolchain components"); else Reportaise_Command_Failed (Alire.Errors.Get (E)); end if; end Install; ---------- -- List -- ---------- procedure List (Cmd : in out Command) is use Alire; use type Dependencies.Dependency; Table : AAA.Table_IO.Table; begin Cmd.Requires_Full_Index; if Alire.Shared.Available.Is_Empty then Trace.Info ("Nothing installed in configuration prefix " & TTY.URL (Alire.Config.Edit.Path)); return; end if; Table .Append (TTY.Emph ("CRATE")) .Append (TTY.Emph ("VERSION")) .Append (TTY.Emph ("STATUS")) .Append (TTY.Emph ("NOTES")) .New_Row; for Dep of Alire.Shared.Available loop if (for some Crate of Toolchains.Tools => Dep.Provides (Crate)) then declare Tool : constant Crate_Name := (if Dep.Provides (GNAT_Crate) then GNAT_Crate else Dep.Name); begin Table .Append (Alire.Utils.TTY.Name (Dep.Name)) .Append (TTY.Version (Dep.Version.Image)) .Append (if Toolchains.Tool_Is_Configured (Tool) and then Dep.To_Dependency.Value = Toolchains.Tool_Dependency (Tool) then TTY.Description ("Default") else "Available") .Append (TTY.Dim (Dep.Notes)) .New_Row; end; end if; end loop; Table.Print; end List; --------------- -- Uninstall -- --------------- procedure Uninstall (Cmd : in out Command; Target : String) is ------------------ -- Find_Version -- ------------------ function Find_Version return String is -- Obtain all installed releases for the crate; we will proceed if -- only one exists. Available : constant Alire.Releases.Containers.Release_Set := Alire.Shared.Available.Satisfying (Alire.Dependencies.New_Dependency (Crate => Alire.To_Name (Target), Versions => Semantic_Versioning.Extended.Any)); begin if Available.Is_Empty then Reportaise_Command_Failed ("Requested crate has no installed releases: " & Alire.Utils.TTY.Name (Alire.To_Name (Target))); elsif Available.Length not in 1 then Reportaise_Command_Failed ("Requested crate has several installed releases, " & "please provide an exact target version"); end if; return Available.First_Element.Milestone.Version.Image; end Find_Version; begin Cmd.Requires_Full_Index; -- If no version was given, find if only one is installed if not AAA.Strings.Contains (Target, "=") then Uninstall (Cmd, Target & "=" & Find_Version); return; end if; -- Otherwise we proceed with a complete milestone Alire.Shared.Remove (Alire.Milestones.New_Milestone (Target)); end Uninstall; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is Pending : Name_Sets.Set; -- We do not want tools that are later in the command-line to be taken -- into account prematurely for compatibility of origins. We store here -- crates still to be dealt with. begin -- Validation if Alire.Utils.Count_True ((Cmd.Install, Cmd.S_Select, Cmd.Uninstall)) > 1 then Reportaise_Wrong_Arguments ("The provided switches cannot be used simultaneously"); end if; if (Cmd.Install or Cmd.Uninstall) and then Args.Is_Empty then Reportaise_Wrong_Arguments ("No release specified"); end if; if not Args.Is_Empty and then not (Cmd.Install or Cmd.Uninstall or Cmd.S_Select) then Reportaise_Wrong_Arguments ("Specify the action to perform with the crate"); end if; if Cmd.Local and then not (Cmd.S_Select or else Cmd.Disable) then Reportaise_Wrong_Arguments ("--local requires --select or --disable-assistant"); end if; if Cmd.Install_Dir.all /= "" and then not Cmd.Install then Reportaise_Wrong_Arguments ("--install-dir is only compatible with --install action"); end if; -- Dispatch to subcommands if Cmd.Disable then Alire.Toolchains.Set_Automatic_Assistant (False, (if Cmd.Local then Alire.Config.Local else Alire.Config.Global)); Alire.Put_Info ("Assistant disabled in " & TTY.Emph (if Cmd.Local then "local" else "global") & " configuration."); end if; if Cmd.S_Select then Cmd.Requires_Full_Index; Alire.Index.Detect_Externals (Alire.GNAT_External_Crate, Alire.Platforms.Current.Properties); if Cmd.Local then Cmd.Requires_Valid_Session; end if; if Args.Count = 0 then Alire.Toolchains.Assistant ((if Cmd.Local then Alire.Config.Local else Alire.Config.Global), Allow_Incompatible => Alire.Force); else for Elt of Args loop Pending.Insert (Alire.Dependencies.From_String (Elt).Crate); end loop; for Elt of Args loop Install (Cmd, Elt, Pending, Set_As_Default => True); Pending.Exclude (Alire.Dependencies.From_String (Elt).Crate); end loop; Alire.Toolchains.Set_Automatic_Assistant (False, (if Cmd.Local then Alire.Config.Local else Alire.Config.Global)); Trace.Detail ("Assistant disabled in " & TTY.Emph (if Cmd.Local then "local" else "global") & " configuration because of toolchain selection via " & "command line."); end if; elsif Cmd.Uninstall then for Elt of Args loop Uninstall (Cmd, Elt); end loop; elsif Cmd.Install then Cmd.Requires_Full_Index; Alire.Index.Detect_Externals (Alire.GNAT_External_Crate, Alire.Platforms.Current.Properties); for Elt of Args loop Install (Cmd, Elt, Name_Sets.Empty_Set, Set_As_Default => False); end loop; elsif not Cmd.Disable then -- When no command is specified, print the list Cmd.List; end if; exception when E : Semantic_Versioning.Malformed_Input => Alire.Log_Exception (E); Reportaise_Wrong_Arguments ("Improper version specification"); end Execute; end Alr.Commands.Toolchain; alire-1.2.1/src/alr/alr-commands-toolchain.ads000066400000000000000000000050631430264165500212120ustar00rootroot00000000000000with AAA.Strings; private with GNAT.Strings; package Alr.Commands.Toolchain is -- Installation of binary toolchain crates into the ${ALR_CONFIG}/cache -- shared configuration. type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("toolchain"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Download toolchain elements, like" & " " & TTY.Emph ("GNAT") & " and " & TTY.Emph ("gprbuild") & ", in the shared cache of the" & " active configuration.") .New_Line .Append ("Run it without arguments to get a list of downloaded tools.") .New_Line .Append ("Use --select without arguments to run the assistant to " & "select the default toolchain for this configuration. " & "Adding --local will instead make the selection apply " & "only to the workspace (overriding a possible " & "configuration-wide selection). Giving one or more releases" & " argument will skip the assistant and set the release as the" & " default.") .New_Line .Append ("Specify --install/--uninstall and one or more crates name with" & " optional version set to make available or remove a tool.") .New_Line .Append ("Run `" & TTY.Terminal ("alr help toolchains") & "` for further " & "information about toolchain management and use.") ); overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Manage Alire-provided toolchains"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[-u|--uninstall] [-i|--install crate[version set]] |" & " --select [--local] [releases] [--disable-assistant]"); private type Command is new Commands.Command with record Disable : aliased Boolean := False; Install : aliased Boolean := False; Install_Dir : aliased GNAT.Strings.String_Access := null; Local : aliased Boolean := False; S_Select : aliased Boolean := False; Uninstall : aliased Boolean := False; end record; end Alr.Commands.Toolchain; alire-1.2.1/src/alr/alr-commands-topics-aliases.ads000066400000000000000000000016631430264165500221540ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; package Alr.Commands.Topics.Aliases is type Topic is new CLIC.Subcommand.Help_Topic with null record; overriding function Name (This : Topic) return CLIC.Subcommand.Identifier is ("aliases"); overriding function Title (This : Topic) return String is ("User defined command aliases"); overriding function Content (This : Topic) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Command aliases can be defined in local or global ") .Append ("configuration.") .New_Line .Append ("For example the following command:") .Append ("""$ alr config --set --global alias.graph 'show --graph'""") .Append ("Defines a global alias for the 'show' command with a ") .Append ("'--graph' switch.") .New_Line .Append ("""$ alr graph"" is equivalent to ""alr show --graph""")); end Alr.Commands.Topics.Aliases; alire-1.2.1/src/alr/alr-commands-topics-naming_convention.ads000066400000000000000000000010521430264165500242360ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; with Alire.Crates; package Alr.Commands.Topics.Naming_Convention is type Topic is new CLIC.Subcommand.Help_Topic with null record; overriding function Name (This : Topic) return CLIC.Subcommand.Identifier is ("identifiers"); overriding function Title (This : Topic) return String is ("Naming rules for crate and index names"); overriding function Content (This : Topic) return AAA.Strings.Vector is (Alire.Crates.Naming_Convention); end Alr.Commands.Topics.Naming_Convention; alire-1.2.1/src/alr/alr-commands-topics-toolchains.ads000066400000000000000000000010321430264165500226640ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; with Alire.Toolchains; package Alr.Commands.Topics.Toolchains is type Topic is new CLIC.Subcommand.Help_Topic with null record; overriding function Name (This : Topic) return CLIC.Subcommand.Identifier is ("toolchains"); overriding function Title (This : Topic) return String is ("Configuration and use of toolchains"); overriding function Content (This : Topic) return AAA.Strings.Vector is (Alire.Toolchains.Description); end Alr.Commands.Topics.Toolchains; alire-1.2.1/src/alr/alr-commands-topics.ads000066400000000000000000000000711430264165500205250ustar00rootroot00000000000000package Alr.Commands.Topics is end Alr.Commands.Topics; alire-1.2.1/src/alr/alr-commands-update.adb000066400000000000000000000051351430264165500204730ustar00rootroot00000000000000with Alire.Containers; with Alire.Errors; with Alr.Commands.Index; package body Alr.Commands.Update is ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is ------------------- -- Parse_Allowed -- ------------------- function Parse_Allowed return Alire.Containers.Crate_Name_Sets.Set is begin return Set : Alire.Containers.Crate_Name_Sets.Set do for I in Args.First_Index .. Args.Last_Index loop Set.Include (+Args (I)); end loop; end return; exception when E : Alire.Checked_Error => -- Bad crate names in the command line is an expected error, so -- re-raise it under the proper exception to avoid the 'unexpected -- error' message. Reportaise_Wrong_Arguments (Alire.Errors.Get (E)); return Alire.Containers.Crate_Name_Sets.Empty_Set; end Parse_Allowed; begin Cmd.Requires_Valid_Session (Sync => False); -- The user has explicitly requested an update, so it makes no sense to -- sync previously, or the update would never find changes. if Cmd.Online then Index.Update_All; end if; Cmd.Requires_Full_Index; Cmd.Root.Update (Parse_Allowed, Silent => False, Interact => True); end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Resolves unpinned dependencies using available indexes.") .New_Line .Append ("Invoked without arguments will consider all unpinned crates" & " for updating.") .New_Line .Append ("One or more crates can be given as argument, in which case" & " only these crates will be candidates for updating." & " Requesting the update of a pinned crate is not allowed.")); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Online'Access, Long_Switch => "--online", Help => "Fetch index updates before attempting crate updates"); end Setup_Switches; end Alr.Commands.Update; alire-1.2.1/src/alr/alr-commands-update.ads000066400000000000000000000017041430264165500205120ustar00rootroot00000000000000with AAA.Strings; package Alr.Commands.Update is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("update"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Updates alire catalog and working release dependencies"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[crate]..."); private type Command is new Commands.Command with record Online : aliased Boolean := False; end record; end Alr.Commands.Update; alire-1.2.1/src/alr/alr-commands-user_input.adb000066400000000000000000000013161430264165500214030ustar00rootroot00000000000000package body Alr.Commands.User_Input is ----------------------------------- -- Report_Pinned_Crate_Detection -- ----------------------------------- procedure Report_Pinned_Crate_Detection (Crate : Alire.Crate_Name; Solution : Alire.Solutions.Solution) is begin if Solution.State (Crate).Has_Release then Trace.Info ("Alire crate detected at given destination: " & Solution.State (Crate).Release .Milestone.TTY_Image); else Trace.Warning ("No crate detected at destination;" & " using it as a raw GNAT project."); end if; end Report_Pinned_Crate_Detection; end Alr.Commands.User_Input; alire-1.2.1/src/alr/alr-commands-user_input.ads000066400000000000000000000006021430264165500214210ustar00rootroot00000000000000with Alire.Solutions; package Alr.Commands.User_Input is -- Reusable user interactions procedure Report_Pinned_Crate_Detection (Crate : Alire.Crate_Name; Solution : Alire.Solutions.Solution); -- When pinning a directory, report if the target already contains an -- initialized crate or not. For reuse from several commands. end Alr.Commands.User_Input; alire-1.2.1/src/alr/alr-commands-version.adb000066400000000000000000000123771430264165500207040ustar00rootroot00000000000000with Alire.Config.Edit; with Alire.Index; with Alire.Index_On_Disk.Loading; with Alire.Milestones; with Alire.Properties; with Alire.Roots.Optional; with Alire.Toolchains; with Alire.Utils.Tables; with Alr.Bootstrap; with Alr.Paths; with GNAT.Compiler_Version; with GNAT.Source_Info; with CLIC.User_Input; package body Alr.Commands.Version is package GNAT_Version is new GNAT.Compiler_Version; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is use all type Alire.Roots.Optional.States; Table : Alire.Utils.Tables.Table; Index_Outcome : Alire.Outcome; Indexes : constant Alire.Index_On_Disk.Loading.Set := Alire.Index_On_Disk.Loading.Find_All (Alire.Config.Edit.Indexes_Directory, Index_Outcome); Root : constant Alire.Roots.Optional.Root := Alire.Roots.Optional.Search_Root (Alire.Directories.Current); begin if Args.Count /= 0 then Reportaise_Wrong_Arguments (Cmd.Name & " doesn't take arguments"); end if; Table.Append ("APPLICATION").Append ("").New_Row; Table.Append ("alr version:").Append (Alire.Version.Current).New_Row; Table.Append ("libalire version:") .Append (Alire.Version.Current).New_Row; Table.Append ("compilation date:") .Append (GNAT.Source_Info.Compilation_ISO_Date & " " & GNAT.Source_Info.Compilation_Time).New_Row; Table.Append ("compiler version:").Append (GNAT_Version.Version).New_Row; Table.Append ("").New_Row; Table.Append ("CONFIGURATION").New_Row; Table.Append ("config folder:").Append (Paths.Alr_Config_Folder).New_Row; Table.Append ("force flag:").Append (Alire.Force'Image).New_Row; Table.Append ("non-interactive flag:") .Append (CLIC.User_Input.Not_Interactive'Image).New_Row; Table.Append ("community index branch:") .Append (Alire.Index.Community_Branch).New_Row; Table.Append ("compatible index versions:") .Append (Alire.Index.Valid_Versions.Image).New_Row; Table.Append ("indexes folder:") .Append (Alire.Config.Edit.Indexes_Directory).New_Row; Table.Append ("indexes metadata:") .Append (if Index_Outcome.Success then "OK" else "ERROR: " & Index_Outcome.Message).New_Row; for Index of Indexes loop Table.Append ("index #" & AAA.Strings.Trim (Index.Priority'Image) & ":") .Append ("(" & Index.Name & ") " & Index.Origin).New_Row; end loop; Table.Append ("toolchain assistant:") .Append (if Alire.Toolchains.Assistant_Enabled then "enabled" else "disabled").New_Row; declare I : Positive := 1; begin for Tool of Alire.Toolchains.Tools loop Table .Append ("tool #" & AAA.Strings.Trim (I'Image) & " " & Tool.As_String & ":") .Append (if Alire.Toolchains.Tool_Is_Configured (Tool) then Alire.Toolchains.Tool_Milestone (Tool).Image else "not configured").New_Row; I := I + 1; end loop; end; Table.Append ("").New_Row; Table.Append ("WORKSPACE").New_Row; Table.Append ("root status:") .Append (Root.Status'Image).New_Row; Table.Append ("root release:") .Append (case Root.Status is when Valid => Root.Value.Release.Milestone.Image, when others => "N/A").New_Row; Table.Append ("root load error:") .Append (case Root.Status is when Broken => Cmd.Optional_Root.Message, when Valid => "none", when Outside => "N/A").New_Row; Table.Append ("root folder:") .Append (case Root.Status is when Outside => "N/A", when Broken => "N/A", when Valid => Root.Value.Path).New_Row; Table.Append ("current folder:").Append (Alire.Directories.Current) .New_Row; Table.Append ("").New_Row; Table.Append ("SYSTEM").New_Row; for Prop of Platform.Properties loop Table.Append (Prop.Key & ":").Append (Prop.Image).New_Row; end loop; Table.Print (Level => Always); exception when E : others => Alire.Log_Exception (E); Trace.Error ("Unexpected error during information gathering"); Trace.Error ("Gathered information up to the error is:"); Table.Print (Level => Always); raise; end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Shows assorted metadata about the alr executable," & " and about the crate or sandbox found in the current" & " directory, if any.")); ------------------- -- Print_Version -- ------------------- procedure Print_Version is begin Trace.Always ("alr " & Alire.Version.Current); end Print_Version; end Alr.Commands.Version; alire-1.2.1/src/alr/alr-commands-version.ads000066400000000000000000000023201430264165500207100ustar00rootroot00000000000000with AAA.Strings; with Alire.Platforms.Current; package Alr.Commands.Version is package Platform renames Alire.Platforms.Current; type Command is new Commands.Command with null record; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("version"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding function Short_Description (Cmd : Command) return String is ("Shows detailed version, configuration, and environment information"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is (""); function Fingerprint return String; procedure Print_Version; -- Print a one-liner version report private ----------------- -- Fingerprint -- ----------------- function Fingerprint return String is (AAA.Strings.To_Mixed_Case (Platform.Operating_System'Img) & " " & AAA.Strings.To_Mixed_Case (Platform.Word_Size'Img) & " " & AAA.Strings.To_Mixed_Case (Platform.Distribution'Img)); end Alr.Commands.Version; alire-1.2.1/src/alr/alr-commands-withing.adb000066400000000000000000000320301430264165500206540ustar00rootroot00000000000000with Ada.Strings; with Ada.Strings.Fixed; with Ada.Strings.Maps; with Ada.Text_IO; with Alire.Dependencies; with Alire.Optional; with Alire.Platforms.Current; with Alire.Releases; with Alire.Roots.Editable; with Alire.Solutions; with Alire.URI; with Alr.OS_Lib; with Semantic_Versioning.Extended; with TOML_Slicer; package body Alr.Commands.Withing is Switch_URL : constant String := "--use"; --------- -- Add -- --------- procedure Add (Root : in out Alire.Roots.Editable.Root; Args : AAA.Strings.Vector) is begin for I in Args.First_Index .. Args.Last_Index loop Root.Add_Dependency (Alire.Dependencies.From_String (Args (I))); end loop; end Add; --------- -- Del -- --------- procedure Del (Root : in out Alire.Roots.Editable.Root; Args : AAA.Strings.Vector) is begin for I in Args.First_Index .. Args.Last_Index loop Root.Remove_Dependency (Alire.To_Name (Args (I))); end loop; end Del; ---------- -- From -- ---------- procedure From (Root : in out Alire.Roots.Editable.Root; Args : AAA.Strings.Vector) is use Ada.Text_IO; use AAA.Strings; ------------- -- Extract -- ------------- procedure Extract (Line : String) is use Ada.Strings; use Ada.Strings.Fixed; use Ada.Strings.Maps; -- Line contains "alr with", is crunched and lowercased First, Last : Natural := Line'First - 1; type Found_Steps is (Nothing, Dashes, Alr, Withh); Found : Found_Steps := Nothing; begin loop Find_Token (Line, To_Set (' '), From => Last + 1, Test => Outside, First => First, Last => Last); exit when First > Line'Last; case Found is when Nothing => if Line (First .. Last) = "--" then Found := Dashes; end if; when Dashes => if Line (First .. Last) = "alr" then Found := Alr; end if; when Alr => if Line (First .. Last) = "with" then Found := Withh; end if; when Withh => Root.Add_Dependency (Alire.Dependencies.From_String (Line (First .. Last))); end case; exit when Last = Line'Last; end loop; end Extract; ---------------- -- Check_File -- ---------------- procedure Check_File (Name : String) is File : File_Type; begin if not OS_Lib.Is_Regular_File (Name) then Reportaise_Command_Failed ("Given file not found: " & Name); end if; Open (File, In_File, Name); while not End_Of_File (File) loop declare Line : constant String := Crunch (To_Lower_Case (Get_Line (File))); begin exit when Contains (Line, "project"); if Contains (Line, "alr with") then Extract (Line); end if; end; end loop; Close (File); end Check_File; begin for I in Args.First_Index .. Args.Last_Index loop Check_File (Args (I)); end loop; end From; ---------- -- List -- ---------- procedure List (Cmd : in out Command) is Root_Release : constant Alire.Releases.Release := Cmd.Root.Release; begin Put_Line ("Dependencies (direct):"); Root_Release.Dependencies.Print (Prefix => " ", Verbose => False, And_Or => Root_Release.Dependencies.Contains_ORs, Sorted => True); if not Root_Release.Pins.Is_Empty then Put_Line ("Pins (direct):"); Root_Release.Pins.Print (Prefix => " "); end if; if Cmd.Solve then Cmd.Requires_Full_Index; -- Load possible hints Cmd.Root.Solution.Print (Root_Release, Alire.Platforms.Current.Properties, Detailed => True, Level => Always); end if; end List; ------------------ -- Add_With_Pin -- ------------------ procedure Add_With_Pin (Cmd : in out Command; Root : in out Alire.Roots.Editable.Root; Args : AAA.Strings.Vector) is Crate : constant Alire.Optional.Crate_Name := (if Args.Count = 1 then Alire.Optional.Crate_Names.Unit (Alire.Dependencies.From_String (Args (1)).Crate) else Alire.Optional.Crate_Names.Empty); begin -- First, add the dependency if given if Args.Count = 1 then declare use type Semantic_Versioning.Extended.Version_Set; Dep : constant Alire.Dependencies.Dependency := Alire.Dependencies.From_String (Args (1)); begin if Dep.Versions /= Semantic_Versioning.Extended.Any and then not Cmd.Root.Solution.Depends_On (Dep.Crate) then Root.Add_Dependency (Dep); end if; end; end if; -- Now, add the pin to the path/remote if Cmd.Commit.all /= "" or else Cmd.Branch.all /= "" or else Alire.URI.Is_HTTP_Or_Git (Cmd.URL.all) then -- Pin to remote repo, with optional dependency first Root.Add_Remote_Pin (Crate => Crate, Origin => Cmd.URL.all, Ref => Cmd.Commit.all, Branch => Cmd.Branch.all); else -- Pin to local folder Root.Add_Path_Pin (Crate => Crate, Path => Cmd.URL.all); end if; end Add_With_Pin; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is Flags : Natural := 0; procedure Check (Flag : Boolean) is begin if Flag then Flags := Flags + 1; end if; if Flags > 1 then Reportaise_Wrong_Arguments ("Only one simultaneous switch allowed."); end if; end Check; begin Cmd.Requires_Valid_Session; if Cmd.URL.all /= "" then Flags := Flags + 1; end if; Check (Cmd.Del); Check (Cmd.From); Check (Cmd.Graph); Check (Cmd.Solve); Check (Cmd.Tree); Check (Cmd.Versions); if Cmd.Commit.all /= "" and then Cmd.Branch.all /= "" then Reportaise_Wrong_Arguments ("Cannot specify both a branch and a commit simultaneously"); end if; -- No parameters: give requested info and return. There is still the -- possibility of a `with --use` that is processed later. if Args.Count = 0 then if Flags = 0 or else Cmd.Solve then List (Cmd); return; elsif Cmd.Tree then Cmd.Root.Solution.Print_Tree (Cmd.Root.Release); return; elsif Cmd.Graph then Cmd.Root.Solution.Print_Graph (Cmd.Root.Release, Alire.Platforms.Current.Properties); return; elsif Cmd.Versions then Cmd.Root.Solution.Print_Versions (Cmd.Root); return; end if; end if; if Args.Count < 1 then if Cmd.Del then Reportaise_Wrong_Arguments ("At least one dependency required"); elsif Cmd.From then Reportaise_Wrong_Arguments ("At least one GPR file to process required"); end if; end if; -- At this point, we are modifying the manifest to incorporate changes, -- so we create a temporary copy of the root for these changes declare New_Root : Alire.Roots.Editable.Root := Alire.Roots.Editable.New_Root (Cmd.Root); begin if not (Cmd.Del or else Cmd.From) then -- Must be Add, but it could be regular or softlink if Cmd.URL.all /= "" then Cmd.Add_With_Pin (New_Root, Args); else Cmd.Requires_Full_Index; Add (New_Root, Args); end if; elsif Cmd.Del then Del (New_Root, Args); elsif Cmd.From then Cmd.Requires_Full_Index; From (New_Root, Args); else raise Program_Error with "List should have already happened"; end if; -- Apply changes New_Root.Confirm_And_Commit; end; exception when E : TOML_Slicer.Slicing_Error => Alire.Log_Exception (E); Reportaise_Command_Failed ("alr was unable to apply your request; " & "please edit the manifest manually."); end Execute; ---------------------- -- Long_Description -- ---------------------- overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Inspect and manage dependencies.") .New_Line .Append ("* Inspecting dependencies:") .Append ("Run without arguments prints current dependencies. Use" & " --solve to print the solution in use for these" & " dependencies.") .New_Line .Append ("* Adding dependencies from the command line:") .Append ("Dependencies are added by giving their name, and removed" & " by using the --del flag. Dependencies cannot be" & " simultaneously added and removed in a single invocation.") .New_Line .Append ("* Adding dependencies pinned to external sources:") .Append ("When a single crate name is accompanied by an --use PATH|URL" & " argument, the crate is always fulfilled for any required" & " version by the sources found at the given target." & " An optional reference can be specified with --commit;" & " the pin will be frozen at the commit currently matching" & " the reference. Alternatively, a branch to track can be" & " specified with --branch. Use `alr update` to refresh the" & " tracking pin contents.") .New_Line .Append ("* Adding dependencies from a GPR file:") .Append ("The project file given with --from will be scanned looking" & " for comments that contain the sequence 'alr with'. " & " These will be processed individually as if they had been" & " given in the command line, starting with no dependencies." & " That is, only dependencies given in the GPR file will be" & " preserved.") .New_Line .Append ("Example of GPR file contents:") .New_Line .Append ("with ""libhello""; -- alr with libhello") .New_Line .Append (Crate_Version_Sets)); -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Cmd.Del'Access, "", "--del", "Remove given dependencies"); Define_Switch (Config, Cmd.From'Access, "", "--from", "Use dependencies declared within GPR project file"); Define_Switch (Config, Cmd.Graph'Access, "", "--graph", "Show ASCII graph of dependencies"); Define_Switch (Config => Config, Output => Cmd.Branch'Access, Long_Switch => "--branch=", Argument => "NAME", Help => "Branch to track in repository"); Define_Switch (Config => Config, Output => Cmd.Commit'Access, Long_Switch => "--commit=", Argument => "REF", Help => "Commit to retrieve from repository"); Define_Switch (Config => Config, Output => Cmd.URL'Access, Long_Switch => Switch_URL & "=", Argument => "PATH|URL", Help => "Add a dependency pinned to some external source"); Define_Switch (Config, Cmd.Solve'Access, "", "--solve", "Show complete solution to dependencies"); Define_Switch (Config, Cmd.Tree'Access, "", "--tree", "Show complete dependency tree"); Define_Switch (Config, Cmd.Versions'Access, "", "--versions", "Show version status of dependencies"); end Setup_Switches; end Alr.Commands.Withing; alire-1.2.1/src/alr/alr-commands-withing.ads000066400000000000000000000027531430264165500207060ustar00rootroot00000000000000with AAA.Strings; private with GNAT.Strings; package Alr.Commands.Withing is type Command is new Commands.Command with private; overriding function Name (Cmd : Command) return CLIC.Subcommand.Identifier is ("with"); overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Command) return AAA.Strings.Vector; overriding procedure Setup_Switches (Cmd : in out Command; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Manage release dependencies"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[{ [--del] [versions]..." & " | --from ..." & " | [versions] --use [--commit REF] [--branch NAME]} ]" & " | --solve | --tree | --versions"); private type Command is new Commands.Command with record Branch : aliased GNAT.Strings.String_Access; Commit : aliased GNAT.Strings.String_Access; Del : aliased Boolean := False; From : aliased Boolean := False; Graph : aliased Boolean := False; Solve : aliased Boolean := False; Tree : aliased Boolean := False; URL : aliased GNAT.Strings.String_Access; Versions : aliased Boolean := False; end record; end Alr.Commands.Withing; alire-1.2.1/src/alr/alr-commands.adb000066400000000000000000000445301430264165500172150ustar00rootroot00000000000000with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Command_Line; with Ada.Directories; with Ada.Text_IO; use Ada.Text_IO; with CLIC.TTY; with CLIC.User_Input; with Alire.Platforms; with Alire_Early_Elaboration; with Alire.Config.Edit; with Alire.Errors; with Alire.Index_On_Disk.Loading; with Alire.Lockfiles; with Alire.Paths; with Alire.Platforms.Current; with Alire.Root; with Alire.Solutions; with Alire.Toolchains; with Alr.Commands.Action; with Alr.Commands.Build; with Alr.Commands.Clean; with Alr.Commands.Config; with Alr.Commands.Dev; with Alr.Commands.Edit; with Alr.Commands.Exec; with Alr.Commands.Get; with Alr.Commands.Index; with Alr.Commands.Init; with Alr.Commands.Pin; with Alr.Commands.Printenv; with Alr.Commands.Publish; with Alr.Commands.Run; with Alr.Commands.Search; with Alr.Commands.Show; with Alr.Commands.Test; with Alr.Commands.Toolchain; with Alr.Commands.Update; with Alr.Commands.Version; with Alr.Commands.Withing; with Alr.Commands.Topics.Naming_Convention; with Alr.Commands.Topics.Toolchains; with Alr.Commands.Topics.Aliases; with GNAT.OS_Lib; with GNATCOLL.VFS; package body Alr.Commands is use type GNAT.OS_Lib.String_Access; -- To add a command: update the dispatch table below Command_Line_Config_Path : aliased GNAT.OS_Lib.String_Access; -- Following aliased booleans are used by GNAT.Command_Line processing: Log_Quiet : Boolean renames Alire_Early_Elaboration.Switch_Q; Log_Detail : Boolean renames Alire_Early_Elaboration.Switch_V; -- For the regular verbosity levels Debug_Channel : Boolean renames Alire_Early_Elaboration.Switch_D; -- For the stderr debug channel Help_Switch : aliased Boolean := False; -- Catches the -h/--help help switch Prefer_Oldest : aliased Boolean := False; -- Catches the --prefer-oldest policy switch No_Color : aliased Boolean := False; -- Force-disable color output No_TTY : aliased Boolean := False; -- Used to disable control characters in output Version_Only : aliased Boolean := False; -- Just display the current version and exit --------------- -- Put_Error -- --------------- procedure Put_Error (Str : String) is begin Trace.Error (Str); end Put_Error; -------------- -- Is_Quiet -- -------------- function Is_Quiet return Boolean is (Log_Quiet); ------------------------- -- Set_Builtin_Aliases -- ------------------------- procedure Set_Builtin_Aliases is begin Sub_Cmd.Set_Alias ("gnatprove", AAA.Strings.Empty_Vector .Append ("exec") .Append ("-P1") .Append ("--") .Append ("gnatprove")); Sub_Cmd.Set_Alias ("gnatcov", AAA.Strings.Empty_Vector .Append ("exec") .Append ("-P2") .Append ("--") .Append ("gnatcov")); end Set_Builtin_Aliases; ------------------------- -- Set_Global_Switches -- ------------------------- procedure Set_Global_Switches (Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Command_Line_Config_Path'Access, "-c=", "--config=", "Override configuration folder location"); Define_Switch (Config, Alire.Force'Access, "-f", "--force", "Keep going after a recoverable troublesome situation"); Define_Switch (Config, Help_Switch'Access, "-h", "--help", "Display general or command-specific help"); Define_Switch (Config, CLIC.User_Input.Not_Interactive'Access, "-n", "--non-interactive", "Assume default answers for all user prompts"); Define_Switch (Config, No_Color'Access, Long_Switch => "--no-color", Help => "Disables colors in output"); Define_Switch (Config, No_TTY'Access, Long_Switch => "--no-tty", Help => "Disables control characters in output"); Define_Switch (Config, Prefer_Oldest'Access, Long_Switch => "--prefer-oldest", Help => "Prefer oldest versions instead of " & "newest when resolving dependencies"); Define_Switch (Config, Version_Only'Access, Long_Switch => "--version", Help => "Displays version and exits"); Define_Switch (Config, Log_Quiet'Access, "-q", Help => "Limit output to errors"); Define_Switch (Config, Log_Detail'Access, "-v", Help => "Be more verbose (use twice for extra detail)"); Define_Switch (Config, Debug_Channel'Access, "-d?", Long_Switch => "--debug?", Help => "Enable debug-specific log messages"); end Set_Global_Switches; -------------------------- -- Create_Alire_Folders -- -------------------------- procedure Create_Alire_Folders is use GNATCOLL.VFS; begin Make_Dir (Create (+Alire.Config.Edit.Path)); end Create_Alire_Folders; -------------------------- -- Enter_Working_Folder -- -------------------------- function Enter_Working_Folder return Alire.Directories.Destination is begin declare Candidate_Folder : constant String := Alire.Directories.Detect_Root_Path; begin if Candidate_Folder /= "" then Trace.Detail ("Using candidate alire root: " & Candidate_Folder); return new String'(Candidate_Folder); else Trace.Debug ("Not entering working folder, no valid alire root found"); return Alire.Directories.Stay_In_Current; end if; end; end Enter_Working_Folder; ------------------ -- Query_Policy -- ------------------ function Query_Policy return Alire.Solver.Age_Policies is (if Prefer_Oldest then Alire.Solver.Oldest else Alire.Solver.Newest); ------------------------------- -- Reportaise_Command_Failed -- ------------------------------- procedure Reportaise_Command_Failed (Message : String) is begin Alire.Errors.Pretty_Print (Message); raise Command_Failed with Alire.Errors.Set (Message); end Reportaise_Command_Failed; -------------------------------- -- Reportaise_Wrong_Arguments -- -------------------------------- procedure Reportaise_Wrong_Arguments (Message : String) is begin Alire.Errors.Pretty_Print (Message); raise Wrong_Command_Arguments with Alire.Errors.Set (Message); end Reportaise_Wrong_Arguments; ---------- -- Load -- ---------- procedure Load (Cmd : Command'Class; Crate : Alire.Crate_Name; Externals : Boolean := False; Strict : Boolean := False) is pragma Unreferenced (Cmd); begin Alire.Index_On_Disk.Loading.Load (Crate => Crate, Detect_Externals => Externals, Strict => Strict); end Load; ------------------------- -- Requires_Full_Index -- ------------------------- procedure Requires_Full_Index (Cmd : in out Command'Class; Strict : Boolean := False; Force_Reload : Boolean := False) is pragma Unreferenced (Cmd); begin Alire.Index_On_Disk.Loading.Setup_And_Load (From => Alire.Config.Edit.Indexes_Directory, Strict => Strict, Force => Force_Reload); end Requires_Full_Index; ---------------------------- -- Requires_Valid_Session -- ---------------------------- procedure Requires_Valid_Session (Cmd : in out Command'Class; Sync : Boolean := True) is use Alire; Unchecked : Alire.Roots.Optional.Root renames Cmd.Optional_Root; Manual_Only : constant Boolean := Alire.Config.DB.Get (Alire.Config.Keys.Update_Manually, False); package Conf renames Alire.Config; begin -- If the root has been already loaded, then all following checks have -- been already performed, and we are done: if Cmd.Optional_Root.Is_Valid then Trace.Debug ("Workspace is valid [already loaded]"); return; end if; -- Unless the command is precisely to configure the toolchain, ask the -- user for its preference at this time. if Cmd not in Commands.Toolchain.Command'Class and then Alire.Toolchains.Assistant_Enabled then Cmd.Requires_Full_Index; Alire.Toolchains.Assistant (Conf.Global); end if; Trace.Debug ("Workspace is being checked and loaded for the first time"); Unchecked := Alire.Root.Current; if not Unchecked.Is_Valid then Raise_Checked_Error (Alire.Errors.Wrap ("Cannot continue with invalid session", Unchecked.Message)); end if; Unchecked.Value.Check_Stored; declare Checked : Roots.Root := Unchecked.Value; begin -- For workspaces created pre-lockfiles, or with older format, -- recreate: case Lockfiles.Validity (Checked.Lock_File) is when Lockfiles.Valid => Trace.Debug ("Lockfile at " & Checked.Lock_File & " is valid"); -- If only manual updates are allowed, exit already if Manual_Only then Trace.Detail ("Skipping automatic dependency update" & " per configuration setting."); return; end if; if Sync then -- If the stored solution is not really solved and Sync is -- requested, we need to generate a proper solution anyway. if Checked.Solution.Is_Attempted then -- Check deps on disk match those in lockfile Cmd.Requires_Full_Index (Strict => False); Checked.Sync_From_Manifest (Silent => False, Interact => False); return; end if; else -- We have a lockfile with valid solution, which we never -- want to update automatically, so we are done here. return; end if; when Lockfiles.Invalid => Trace.Warning ("This workspace was created with a previous alr version." & " Internal data is going to be updated and, as a result," & " a fresh solution will be computed that may result in" & " crate upgrades"); Alire.Directories.Backup_If_Existing (Checked.Lock_File, Base_Dir => Alire.Paths.Working_Folder_Inside_Root); Ada.Directories.Delete_File (Checked.Lock_File); when Lockfiles.Missing => -- For the record, with the full path Trace.Debug ("Workspace has no lockfile at " & Checked.Lock_File); end case; Trace.Debug ("Generating lockfile on the fly..."); -- Update current root dependencies to create a complete lock file. -- Before doing that, we need a trivial lock file as "old" solution. Alire.Lockfiles.Write ((Solution => Alire.Solutions.Empty_Valid_Solution), Checked.Lock_File); -- If only manual updates are allowed, exit already. Since this point -- is only reached in case of missing/broken lockfile, it warrants -- extra reporting. if Manual_Only then Trace.Info ("Skipping automatic dependency update" & " per configuration setting."); return; end if; -- If Syncing has not been requested (because a manual sync is -- upcoming) we are done. Otherwise, do a silent update. if Sync then Cmd.Requires_Full_Index (Strict => False); Checked.Sync_From_Manifest (Silent => False, Interact => False, Force => True); -- As we just created the empty lockfile, we force the update end if; end; end Requires_Valid_Session; ------------- -- Execute -- ------------- procedure Execute is ---------------------- -- Log_Command_Line -- ---------------------- procedure Log_Command_Line is use Ada.Command_Line; begin Trace.Debug ("Begin command line:"); Trace.Debug (" Arg 0 (len" & Command_Name'Length'Image & "): " & Command_Name); for I in 1 .. Argument_Count loop Trace.Debug (" Arg" & I'Image & " (len" & Argument (I)'Length'Image & "): " & Argument (I)); end loop; Trace.Debug ("End command line."); end Log_Command_Line; use all type Alire.Platforms.Operating_Systems; begin Log_Command_Line; Sub_Cmd.Parse_Global_Switches; -- Early catch of single --version switch without command if Version_Only then Version.Print_Version; return; end if; if No_TTY then CLIC.TTY.Force_Disable_TTY; end if; -- Use CLIC.TTY selection/detection of TTY Trace.Is_TTY := CLIC.TTY.Is_TTY; if Alire.Platforms.Current.Operating_System /= Alire.Platforms.Windows and then not No_Color and then not No_TTY then CLIC.TTY.Enable_Color (Force => False); -- This may still not enable color if TTY is detected to be incapable Simple_Logging.ASCII_Only := False; -- Also use a fancier busy spinner end if; if Command_Line_Config_Path /= null and then Command_Line_Config_Path.all /= "" then if not Alire.Check_Absolute_Path (Command_Line_Config_Path.all) then -- Make an absolute path from user relative path Alire.Config.Edit.Set_Path (Ada.Directories.Full_Name (Command_Line_Config_Path.all)); else -- Use absolute path from user Alire.Config.Edit.Set_Path (Command_Line_Config_Path.all); end if; end if; Create_Alire_Folders; begin Set_Builtin_Aliases; Sub_Cmd.Load_Aliases (Alire.Config.DB); Sub_Cmd.Execute; Log ("alr " & Sub_Cmd.What_Command & " done", Detail); exception when E : Alire.Checked_Error => Alire.Errors.Pretty_Print (Alire.Errors.Get (E, Clear => False)); if Alire.Log_Level = Debug then raise; else OS_Lib.Bailout (1); end if; when Child_Failed | Command_Failed | Wrong_Command_Arguments => Trace.Detail ("alr " & Sub_Cmd.What_Command & " unsuccessful"); if Alire.Log_Level = Debug then raise; else OS_Lib.Bailout (1); end if; when CLIC.User_Input.User_Interrupt => Trace.Error ("Canceled."); if Alire.Log_Level = Debug then raise; else OS_Lib.Bailout (1); end if; end; end Execute; ------------------------ -- Crate_Version_Sets -- ------------------------ function Crate_Version_Sets return AAA.Strings.Vector is begin return AAA.Strings.Empty_Vector .Append ("Version selection syntax (global policy applies " & "within the allowed version subsets):") .New_Line .Append ("crate " & ASCII.HT & "Newest/oldest version") .Append ("crate=version" & ASCII.HT & "Exact version") .Append ("crate^version" & ASCII.HT & "Major-compatible version") .Append ("crate~version" & ASCII.HT & "Minor-compatible version"); end Crate_Version_Sets; ---------- -- Root -- ---------- function Root (Cmd : in out Command'Class) return Alire.Roots.Optional.Reference is begin if not Cmd.Optional_Root.Is_Valid then Cmd.Requires_Valid_Session; end if; return Cmd.Optional_Root.Value; end Root; --------- -- Set -- --------- procedure Set (Cmd : in out Command'Class; Root : Alire.Roots.Root) is begin Cmd.Optional_Root := Alire.Roots.Optional.Outcome_Success (Root); end Set; begin -- Commands -- Sub_Cmd.Register ("General", new Sub_Cmd.Builtin_Help); Sub_Cmd.Register ("General", new Config.Command); Sub_Cmd.Register ("General", new Printenv.Command); Sub_Cmd.Register ("General", new Toolchain.Command); Sub_Cmd.Register ("General", new Version.Command); Sub_Cmd.Register ("Build", new Action.Command); Sub_Cmd.Register ("Build", new Build.Command); Sub_Cmd.Register ("Build", new Clean.Command); Sub_Cmd.Register ("Build", new Dev.Command); Sub_Cmd.Register ("Build", new Edit.Command); Sub_Cmd.Register ("Build", new Run.Command); Sub_Cmd.Register ("Build", new Test.Command); Sub_Cmd.Register ("Build", new Exec.Command); Sub_Cmd.Register ("Index", new Get.Command); Sub_Cmd.Register ("Index", new Index.Command); Sub_Cmd.Register ("Index", new Init.Command); Sub_Cmd.Register ("Index", new Pin.Command); Sub_Cmd.Register ("Index", new Search.Command); Sub_Cmd.Register ("Index", new Show.Command); Sub_Cmd.Register ("Index", new Update.Command); Sub_Cmd.Register ("Index", new Withing.Command); Sub_Cmd.Register ("Publish", new Publish.Command); -- Help topics -- Sub_Cmd.Register (new Topics.Naming_Convention.Topic); Sub_Cmd.Register (new Topics.Toolchains.Topic); Sub_Cmd.Register (new Topics.Aliases.Topic); end Alr.Commands; alire-1.2.1/src/alr/alr-commands.ads000066400000000000000000000115251430264165500172340ustar00rootroot00000000000000with AAA.Strings; with Alire.Directories; with Alire.Roots.Optional; with Alire.Solver; with Alire.Version; with CLIC.Subcommand; private with Ada.Text_IO; private with CLIC.Subcommand.Instance; pragma Warnings (Off); private with Alr.OS_Lib; -- For the benefit of many child packages that use it pragma Warnings (On); package Alr.Commands is Wrong_Command_Arguments : exception; ------------- -- Execute -- ------------- procedure Execute; -- Entry point into alr, will parse the command line and proceed as needed. ------------- -- Command -- ------------- type Command is abstract limited new CLIC.Subcommand.Command with private; -- This type encapsulates configuration and execution of a specific -- command. overriding function Switch_Parsing (This : Command) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Parse_All); -- Default for alr commands is to parse the switches ----------------------------------------- -- Supporting subprograms for commands -- ----------------------------------------- function Root (Cmd : in out Command'Class) return Alire.Roots.Optional.Reference; -- Using this call will ensure the Root detection has been attempted procedure Set (Cmd : in out Command'Class; Root : Alire.Roots.Root); -- Replace the current root in use by the command. Modifying the root via -- the Cmd.Root reference is valid and intended usage that does not require -- resetting the root. procedure Requires_Full_Index (Cmd : in out Command'Class; Strict : Boolean := False; Force_Reload : Boolean := False); -- Unless Force_Reload, if the index is not empty we no nothing. When -- strict, don't allow unknown values in enums. procedure Requires_Valid_Session (Cmd : in out Command'Class; Sync : Boolean := True); -- Verifies that a valid working dir is in scope. After calling it, -- Cmd.Root will be usable if alr was run inside a Root. If Sync, enforce -- that the manifest, lockfile and dependencies on disk are in sync, by -- performing a silent update. If not Sync, only a minimal empty lockfile -- is created. procedure Load (Cmd : Command'Class; Crate : Alire.Crate_Name; Externals : Boolean := False; Strict : Boolean := False); -- Load a specific crate from the index. Optionally detect externals and -- enforce no unknown enum index values. --------------------------- -- command-line helpers -- --------------------------- function Is_Quiet return Boolean; -- Says if -q was in the command line function Query_Policy return Alire.Solver.Age_Policies; -- Current policy -- Declared here so they are available to the help metacommand child -- package and Spawn. function Crate_Version_Sets return AAA.Strings.Vector; -- Returns the instructions to restrict version sets, for use in -- Long_Description help functions. function Enter_Working_Folder return Alire.Directories.Destination; -- Attempt to find the root alire working dir if deeper inside it private type Command is abstract limited new CLIC.Subcommand.Command with record Optional_Root : Alire.Roots.Optional.Root; end record; -- Facilities for command/argument identification. These are available to -- commands. procedure Reportaise_Command_Failed (Message : String); procedure Reportaise_Wrong_Arguments (Message : String); -- Report and Raise :P -- Folder guards conveniences for commands: subtype Folder_Guard is Alire.Directories.Guard; function Enter_Folder (Path : String) return Alire.Directories.Destination renames Alire.Directories.Enter; -- Common generalities procedure New_Line (Spacing : Ada.Text_IO.Positive_Count := 1) renames Ada.Text_IO.New_Line; procedure Put_Line (S : String) renames Ada.Text_IO.Put_Line; procedure Put_Error (Str : String); procedure Set_Global_Switches (Config : in out CLIC.Subcommand.Switches_Configuration); package Sub_Cmd is new CLIC.Subcommand.Instance (Main_Command_Name => "alr", Version => Alire.Version.Current, Put => Ada.Text_IO.Put, Put_Line => Ada.Text_IO.Put_Line, Put_Error => Put_Error, Error_Exit => OS_Lib.Bailout, Set_Global_Switches => Set_Global_Switches, TTY_Chapter => Alire.TTY.Bold, TTY_Description => Alire.TTY.Description, TTY_Version => Alire.TTY.Version, TTY_Underline => Alire.TTY.Underline, TTY_Emph => Alire.TTY.Emph); end Alr.Commands; alire-1.2.1/src/alr/alr-defaults.ads000066400000000000000000000007561430264165500172460ustar00rootroot00000000000000with Alire; package Alr.Defaults with Preelaborate is Alr_Repository : constant Alire.URL := "https://github.com/alire-project/alire.git"; Index_Repository : constant Alire.URL := "https://github.com/alire-project/alire-index.git"; -- Semver_Repository : constant Alire.URL := -- "https://bitbucket.org/aleteolabs/semver.git"; -- Simple_Logging_Repo : constant Alire.URL := -- "https://github.com/mosteo/simple_logging.git"; end Alr.Defaults; alire-1.2.1/src/alr/alr-exceptions.adb000066400000000000000000000005471430264165500175750ustar00rootroot00000000000000package body Alr.Exceptions is ------------ -- Report -- ------------ procedure Report (Preamble : String; E : Ada.Exceptions.Exception_Occurrence) is begin Trace.Debug ("Reporting exception: " & Preamble); Trace.Debug (Ada.Exceptions.Exception_Information (E)); end Report; end Alr.Exceptions; alire-1.2.1/src/alr/alr-exceptions.ads000066400000000000000000000003061430264165500176070ustar00rootroot00000000000000with Ada.Exceptions; package Alr.Exceptions with Preelaborate is procedure Report (Preamble : String; E : Ada.Exceptions.Exception_Occurrence); end Alr.Exceptions; alire-1.2.1/src/alr/alr-files.adb000066400000000000000000000011601430264165500165060ustar00rootroot00000000000000with Ada.Directories; package body Alr.Files is ------------------------- -- Locate_Any_GPR_File -- ------------------------- function Locate_Any_GPR_File return Natural is use Ada.Directories; Candidates : AAA.Strings.Vector; procedure Check (File : Directory_Entry_Type) is begin Candidates.Append (Full_Name (File)); end Check; begin Search (Current_Directory, "*.gpr", (Ordinary_File => True, others => False), Check'Access); return Natural (Candidates.Length); end Locate_Any_GPR_File; end Alr.Files; alire-1.2.1/src/alr/alr-files.ads000066400000000000000000000013251430264165500165320ustar00rootroot00000000000000with Alire.Directories; with AAA.Strings; package Alr.Files is -- The files specific to alr/alire working, and related facilities function Locate_File_Under (Folder : String; Name : String; Max_Depth : Natural := Natural'Last) return AAA.Strings.Vector renames Alire.Directories.Find_Files_Under; -- Recursively search for a file -- Depth 0 means given folder only -- Returns all instances found function Locate_Any_GPR_File return Natural; -- Says if there's any *.gpr file in current folder (making the cwd a -- plausible alr working dir). end Alr.Files; alire-1.2.1/src/alr/alr-last_chance_handler.adb000066400000000000000000000006741430264165500213560ustar00rootroot00000000000000with Alire.Errors; with Alr.OS_Lib; procedure Alr.Last_Chance_Handler (E : Ada.Exceptions.Exception_Occurrence) is begin -- Ensure we do not show an exception trace to unsuspecting users Alire.Log_Exception (E); Alire.Errors.Pretty_Print (Alire.Errors.Get (E)); Alr.Trace.Error ("alr encountered an unexpected error," & " re-run with -d for details."); Alr.OS_Lib.Bailout (1); end Alr.Last_Chance_Handler; alire-1.2.1/src/alr/alr-last_chance_handler.ads000066400000000000000000000002511430264165500213660ustar00rootroot00000000000000with Ada.Exceptions; procedure Alr.Last_Chance_Handler (E : Ada.Exceptions.Exception_Occurrence); pragma Export (C, Last_Chance_Handler, "__gnat_last_chance_handler"); alire-1.2.1/src/alr/alr-main.adb000066400000000000000000000004541430264165500163350ustar00rootroot00000000000000with Alire_Early_Elaboration; pragma Elaborate_All (Alire_Early_Elaboration); with Alr.Commands; with Alr.Last_Chance_Handler; procedure Alr.Main is begin Trace.Debug ("alr platform configured"); Commands.Execute; exception when E : others => Last_Chance_Handler (E); end Alr.Main; alire-1.2.1/src/alr/alr-os_lib.adb000066400000000000000000000030241430264165500166540ustar00rootroot00000000000000with Alire.OS_Lib.Subprocess; package body Alr.OS_Lib is ------------ -- Getenv -- ------------ function Getenv (Var : String; Default : String := "") return String is use GNAT.OS_Lib; Env_Access : GNAT.OS_Lib.String_Access := GNAT.OS_Lib.Getenv (Var); Env : constant String := Env_Access.all; begin Free (Env_Access); if Env = "" then return Default; else return Env; end if; end Getenv; -------------- -- Is_Older -- -------------- function Is_Older (This : String; Than : String) return Boolean is use GNAT.OS_Lib; begin if Is_Regular_File (This) then if not Is_Regular_File (Than) then return True; elsif File_Time_Stamp (This) < File_Time_Stamp (Than) then Trace.Debug (This & " is older than " & Than); return True; else return False; end if; else return False; end if; end Is_Older; --------------- -- Spawn_Raw -- --------------- procedure Spawn_Raw (Command : String; Arguments : String := "") is Code : Integer; begin Trace.Debug ("Spawning " & Command & " " & Arguments); Code := GNAT.OS_Lib.Spawn (Alire.OS_Lib.Subprocess.Locate_In_Path (Command), GNAT.OS_Lib.Argument_String_To_List (Arguments).all); if Code /= 0 then raise Child_Failed with "Exit code:" & Code'Image; end if; end Spawn_Raw; end Alr.OS_Lib; alire-1.2.1/src/alr/alr-os_lib.ads000066400000000000000000000043411430264165500167000ustar00rootroot00000000000000with Ada.Directories; with Alire.Directories; with Alire.OS_Lib; with GNAT.OS_Lib; package Alr.OS_Lib is Line_Separator : constant String; -- Environment function Getenv (Var : String; Default : String := "") return String; procedure Setenv (Var : String; Value : String) renames GNAT.OS_Lib.Setenv; function Exists_In_Path (File : String) return Boolean is (GNAT.OS_Lib."/=" (GNAT.OS_Lib.Locate_Exec_On_Path (File), null)); -- FIXME: memory leak in this call -- Process spawning procedure Spawn_Raw (Command : String; Arguments : String := ""); -- Direct launch, without any shenanigangs on output, for example for -- respawning the canonical version. -- Raises CHILD_FAILED if exit code /= 0. -- OS PORTABLE FUNCTIONS procedure Bailout (Code : Integer := 0) renames Alire.OS_Lib.Bailout; function Is_Older (This : String; Than : String) return Boolean; -- Says if This file is older than Than -- GENERAL COMMAND LINE function Current_Folder return String renames Ada.Directories.Current_Directory; -- PATH BUILDING function "/" (L, R : String) return String; -- Shorthand for path composition package Paths is function "/" (L, R : String) return String renames Alr.OS_Lib."/"; end Paths; ----------------------------- -- WORKING FOLDER MANAGEMENT subtype Folder_Guard is Alire.Directories.Guard; function Enter_Folder (Path : String) return Alire.Directories.Destination renames Alire.Directories.Enter; function Stay_In_Current_Folder return Alire.Directories.Destination renames Alire.Directories.Stay_In_Current; ---------------------------- -- FILE / FOLDER MANAGEMENT function Is_Executable_File (Path : String) return Boolean renames GNAT.OS_Lib.Is_Executable_File; function Is_Regular_File (Path : String) return Boolean renames GNAT.OS_Lib.Is_Regular_File; function Is_Folder (Path : Alire.Any_Path) return Boolean renames GNAT.OS_Lib.Is_Directory; private Line_Separator : constant String := ASCII.LF & ""; -- This should be made OS independent function "/" (L, R : String) return String is (L & GNAT.OS_Lib.Directory_Separator & R); end Alr.OS_Lib; alire-1.2.1/src/alr/alr-paths.ads000066400000000000000000000054461430264165500165570ustar00rootroot00000000000000with Ada.Directories; with Alire; with Alire.Config.Edit; with Alire.Environment; with Alr.Defaults; with Alr.OS_Lib; package Alr.Paths is -- NOTE: none of the functions in this spec can be used before elaboration -- is complete. -- TODO: this note will be obsolete once Alire.Platform supersedes -- Alr.Platform. function "/" (L, R : String) return String; -- Equivalent to Ada.Directories.Compose function Parent (Folder : String) return String renames Ada.Directories.Containing_Directory; -- To clarify constants/functions declared herein: subtype Absolute_File is String; -- Filenames with full path subtype Absolute_Path is String; subtype Relative_File is String; -- Filenames with relative paths subtype Relative_Path is String; -- A relative path subtype Simple_File is String; -- Filenames without path -- Paths used thorough alr Alr_Repo : constant Alire.URL := Defaults.Alr_Repository; -- Repository where alr sources can be found function Alr_Config_Folder return Absolute_Path; -- Root folder containing persistent configuration: indexes, templates function Alr_Source_Folder return Absolute_Path; -- Folder inside Alr_Config_Folder containing a clone of the alr repo -- This folder can be overridden via environment variable -- Alire.Environment.Source. Alr_Working_Folder : constant Relative_Path; -- Folder within a working release that will contain metadata/build files, -- dependency releases, and session. Alr_Working_Cache_Folder : constant Relative_Path; -- Folder inside the working folder with transient files (can be safely -- deleted). Alr_Working_Deps_Path : constant Relative_Path; -- Path from inside the working folder to dependency folders -- Functions that return Paths-derived files function Dependencies_Folder return Relative_Path; -- Location in the working dir where dependencies are deployed private function "/" (L, R : String) return String is (Ada.Directories.Compose (L, R)); -- Constants Alr_Working_Folder : constant String := "alire"; Alr_Working_Cache_Folder : constant Relative_Path := Alr_Working_Folder / "cache"; Alr_Working_Deps_Path : constant Relative_Path := "cache" / "dependencies"; -- Pseudo-constants (due to elaboration finished requirement) -- Or because they can be set after elaboration (e.g. via config switches) function Alr_Config_Folder return String is (Alire.Config.Edit.Path); function Alr_Source_Folder return String is (OS_Lib.Getenv (Alire.Environment.Source, Alr_Config_Folder / "alire")); function Dependencies_Folder return String is (Alr_Working_Cache_Folder / "dependencies"); end Alr.Paths; alire-1.2.1/src/alr/alr-testing-collections.adb000066400000000000000000000030571430264165500214040ustar00rootroot00000000000000package body Alr.Testing.Collections is --------- -- Add -- --------- procedure Add (This : in out Collection; Reporter : Testing.Reporter'Class) is begin This.Append (Reporter); end Add; --------------- -- Start_Run -- --------------- overriding procedure Start_Run (This : in out Collection; Name : String; Tests : Natural) is begin for Reporter of This loop Reporter.Start_Run (Name, Tests); end loop; end Start_Run; ------------- -- End_Run -- ------------- overriding procedure End_Run (This : in out Collection) is begin for Reporter of This loop Reporter.End_Run; end loop; end End_Run; ---------------- -- Start_Test -- ---------------- overriding procedure Start_Test (This : in out Collection; Rel : Alire.Types.Release) is begin for Reporter of This loop Reporter.Start_Test (Rel); end loop; end Start_Test; -------------- -- End_Test -- -------------- overriding procedure End_Test (This : in out Collection; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector) is begin for Reporter of This loop Reporter.End_Test (Rel, Outcome, Elapsed, Log); end loop; end End_Test; end Alr.Testing.Collections; alire-1.2.1/src/alr/alr-testing-collections.ads000066400000000000000000000024211430264165500214170ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; package Alr.Testing.Collections is type Collection is new Reporter with private; procedure Add (This : in out Collection; Reporter : Testing.Reporter'Class); overriding function New_Reporter return Collection; overriding procedure Start_Run (This : in out Collection; Name : String; Tests : Natural); overriding procedure End_Run (This : in out Collection); -- These refer to a whole run of tests overriding procedure Start_Test (This : in out Collection; Rel : Alire.Types.Release); overriding procedure End_Test (This : in out Collection; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector); private package Reporter_Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Testing.Reporter'Class); type Collection is new Reporter_Lists.List and Reporter with null record; overriding function New_Reporter return Collection is (Reporter_Lists.List with null record); end Alr.Testing.Collections; alire-1.2.1/src/alr/alr-testing-console.adb000066400000000000000000000051001430264165500205170ustar00rootroot00000000000000with Alr.Commands.Version; with GNAT.IO; use GNAT.IO; with Stopwatch; package body Alr.Testing.Console is Tab : constant Character := ASCII.HT; --------------- -- Start_Run -- --------------- overriding procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural) is begin This.Tests := Tests; Put_Line ("Starting test run " & Name & " for " & Commands.Version.Fingerprint); end Start_Run; ---------------- -- Start_Test -- ---------------- overriding procedure Start_Test (This : in out Reporter; Rel : Alire.Types.Release) is begin This.Current := This.Current + 1; Put ("PASS:" & This.Results (Pass)'Img & " FAIL:" & This.Results (Fail)'Img & " SKIP:" & This.Results (Skip)'Img & " UNAV:" & This.Results (Unavailable)'Img & " UNRS:" & This.Results (Unresolvable)'Img & " CURR:" & This.Current'Img & "/" & AAA.Strings.Trim (This.Tests'Img) & " " & Rel.Milestone.Image); end Start_Test; -------------- -- End_Test -- -------------- overriding procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector) is pragma Unreferenced (Rel, Log); Elapsed_Image : String renames Stopwatch.Image (Elapsed, Decimals => 2); begin This.Results (Outcome) := This.Results (Outcome) + 1; case Outcome is when Error => Put_Line (Tab & "ERRED"); when Fail => Put_Line (Tab & "FAILED"); when Pass => Put_Line (Tab & "tested in " & Elapsed_Image & "s"); when Skip => Put_Line (Tab & "skipped"); when Unavailable => Put_Line (Tab & "unavailable"); when Unresolvable => Put_Line (Tab & "unresolvable in " & Elapsed_Image & "s"); end case; end End_Test; ------------- -- End_Run -- ------------- overriding procedure End_Run (This : in out Reporter) is begin Put_Line ("PASS:" & This.Results (Pass)'Img & " FAIL:" & This.Results (Fail)'Img & " SKIP:" & This.Results (Skip)'Img & " UNAV:" & This.Results (Unavailable)'Img & " Done"); end End_Run; end Alr.Testing.Console; alire-1.2.1/src/alr/alr-testing-console.ads000066400000000000000000000021251430264165500205440ustar00rootroot00000000000000package Alr.Testing.Console is type Reporter is new Testing.Reporter with private; overriding function New_Reporter return Reporter; overriding procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural); overriding procedure End_Run (This : in out Reporter); overriding procedure Start_Test (This : in out Reporter; Rel : Alire.Types.Release); overriding procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector); private type Counters is array (Outcomes) of Natural; type Reporter is new Testing.Reporter with record Tests : Natural := 0; Current : Natural := 0; Results : Counters := (others => 0); end record; overriding function New_Reporter return Reporter is (others => <>); end Alr.Testing.Console; alire-1.2.1/src/alr/alr-testing-junit.adb000066400000000000000000000055101430264165500202130ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; with Alr.Commands.Version; package body Alr.Testing.JUnit is Newline : constant String := "" & ASCII.LF; --------------- -- Start_Run -- --------------- overriding procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural) is pragma Unreferenced (Tests); begin This.Name := new String'(Name); This.Jsuite := new AJUnitGen.Test_Suite'(AJUnitGen.New_Suite (Name)); end Start_Run; ------------- -- End_Run -- ------------- overriding procedure End_Run (This : in out Reporter) is begin This.Flush; -- TODO: free name end End_Run; -------------- -- End_Test -- -------------- overriding procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector) is pragma Unreferenced (Elapsed); begin case Outcome is when Error => This.Jsuite.Add_Case (AJUnitGen.New_Case (Rel.Milestone.Image, AJUnitGen.Error, Classname => "ERROR", Message => "alr test unexpected error: " & Commands.Version.Fingerprint, Output => Log.Flatten (Newline))); when Fail => This.Jsuite.Add_Case (AJUnitGen.New_Case (Rel.Milestone.Image, AJUnitGen.Fail, Classname => "FAIL", Message => "get --build failure: " & Commands.Version.Fingerprint, Output => Log.Flatten (Newline))); when Pass => This.Jsuite.Add_Case (AJUnitGen.New_Case (Rel.Milestone.Image)); when Skip => This.Jsuite.Add_Case (AJUnitGen.New_Case (Rel.Milestone.Image, AJUnitGen.Skip, Message => "Already tested", Output => Commands.Version.Fingerprint)); when Unavailable | Unresolvable => This.Jsuite.Add_Case (AJUnitGen.New_Case (Rel.Milestone.Image, AJUnitGen.Skip, Message => Outcome'Img, Output => Commands.Version.Fingerprint)); end case; This.Flush; end End_Test; ----------- -- Flush -- ----------- not overriding procedure Flush (This : Reporter) is File : File_Type; begin Create (File, Out_File, This.Name.all & ".xml"); This.Jsuite.To_Collection.Write (File); Close (File); end Flush; end Alr.Testing.JUnit; alire-1.2.1/src/alr/alr-testing-junit.ads000066400000000000000000000022141430264165500202320ustar00rootroot00000000000000with AJUnitGen; package Alr.Testing.JUnit is type Reporter is new Testing.Reporter with private; overriding function New_Reporter return Reporter; overriding procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural); overriding procedure End_Run (This : in out Reporter); -- These refer to a whole run of tests overriding procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector); private type String_Access is access String; type Test_Suite_Access is access AJUnitGen.Test_Suite; type Reporter is new Testing.Reporter with record Name : String_Access; Jsuite : Test_Suite_Access; end record; not overriding procedure Flush (This : Reporter); -- Ensure partial test results are dumped to file overriding function New_Reporter return Reporter is (others => <>); end Alr.Testing.JUnit; alire-1.2.1/src/alr/alr-testing-markdown.adb000066400000000000000000000047011430264165500207050ustar00rootroot00000000000000with Alr.Commands.Version; with Semantic_Versioning; with Stopwatch; package body Alr.Testing.Markdown is use Ada.Text_IO; function BT (S : String) return String is (S); -- ("`" & S & "`"); --------------- -- Start_Run -- --------------- overriding procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural) is pragma Unreferenced (Tests); begin This.File := new File_Type; Create (This.File.all, Out_File, Name & ".md"); Put_Line (This.File.all, "#### " & BT (Commands.Version.Fingerprint)); New_Line (This.File.all); Put_Line (This.File.all, "| Status | Crate | Version | Build time |"); Put_Line (This.File.all, "| --- | --- | --- | --- |"); end Start_Run; ------------- -- End_Run -- ------------- overriding procedure End_Run (This : in out Reporter) is begin Close (This.File.all); -- TODO: free File, but alr is exiting anyway... end End_Run; -------------- -- End_Test -- -------------- overriding procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector) is pragma Unreferenced (Log); Elapsed_Image : String renames Stopwatch.Image (Elapsed, Decimals => 2); begin Put_Line (This.File.all, "|" & (case Outcome is when Pass => "![green](https://placehold.it/8/00aa00/000000?text=+)", when Error | Fail => "![red](https://placehold.it/8/ff0000/000000?text=+)", when others => "![yellow](https://placehold.it/8/ffbb00/000000?text=+)") & " " & BT (case Outcome is when Error => "ERR ", when Fail => "FAIL", when Pass => "pass", when Skip => "SKIP", when Unavailable => "UNAV", when Unresolvable => "DEPS") & " | " & BT (+Rel.Milestone.Crate) & " | " & BT (Semantic_Versioning.Image (Rel.Milestone.Version)) & " | " & BT (Elapsed_Image) & " s |"); Flush (This.File.all); end End_Test; end Alr.Testing.Markdown; alire-1.2.1/src/alr/alr-testing-markdown.ads000066400000000000000000000017221430264165500207260ustar00rootroot00000000000000with Ada.Text_IO; package Alr.Testing.Markdown is type Reporter is new Testing.Reporter with private; overriding function New_Reporter return Reporter; overriding procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural); overriding procedure End_Run (This : in out Reporter); -- These refer to a whole run of tests overriding procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector); private type File_Access is access Ada.Text_IO.File_Type; type Reporter is new Testing.Reporter with record File : File_Access; end record; overriding function New_Reporter return Reporter is (others => <>); end Alr.Testing.Markdown; alire-1.2.1/src/alr/alr-testing-text.adb000066400000000000000000000033241430264165500200470ustar00rootroot00000000000000with Alr.Commands.Version; package body Alr.Testing.Text is use Ada.Text_IO; Tab : constant Character := ASCII.HT; --------------- -- Start_Run -- --------------- overriding procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural) is pragma Unreferenced (Tests); begin This.File := new File_Type; Create (This.File.all, Out_File, Name & ".txt"); Put_Line (This.File.all, "os-fingerprint:" & Commands.Version.Fingerprint); end Start_Run; ------------- -- End_Run -- ------------- overriding procedure End_Run (This : in out Reporter) is begin Close (This.File.all); -- TODO: free File, but alr is exiting anyway... end End_Run; -------------- -- End_Test -- -------------- overriding procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector) is pragma Unreferenced (Log); begin Put_Line (This.File.all, (case Outcome is when Error => "ERR :", when Fail => "FAIL:", when Pass => "pass:", when Skip => "SKIP:", when Unavailable => "UNAV:", when Unresolvable => "DEPS:") & Rel.Milestone.Image & Tab & Tab & " in" & Elapsed'Img & " s"); Flush (This.File.all); end End_Test; end Alr.Testing.Text; alire-1.2.1/src/alr/alr-testing-text.ads000066400000000000000000000017121430264165500200670ustar00rootroot00000000000000with Ada.Text_IO; package Alr.Testing.Text is type Reporter is new Testing.Reporter with private; overriding function New_Reporter return Reporter; overriding procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural); overriding procedure End_Run (This : in out Reporter); -- These refer to a whole run of tests overriding procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector); private type File_Access is access Ada.Text_IO.File_Type; type Reporter is new Testing.Reporter with record File : File_Access; end record; overriding function New_Reporter return Reporter is (others => <>); end Alr.Testing.Text; alire-1.2.1/src/alr/alr-testing.ads000066400000000000000000000023361430264165500171100ustar00rootroot00000000000000with AAA.Strings; with Alire.Types; package Alr.Testing is -- Reporters for the testing of release type Outcomes is (Error, -- Alr failed Fail, -- Release build failed Pass, -- Success Skip, -- Skipped (already tested) Unavailable, -- Unavailable in the platform Unresolvable); -- Dependencies can't be solved type Reporter is interface; function New_Reporter return Reporter is abstract; procedure Start_Run (This : in out Reporter; Name : String; Tests : Natural) is null; procedure End_Run (This : in out Reporter) is null; -- These refer to a whole run of tests procedure Start_Test (This : in out Reporter; Rel : Alire.Types.Release) is null; procedure End_Test (This : in out Reporter; Rel : Alire.Types.Release; Outcome : Outcomes; Elapsed : Duration; Log : AAA.Strings.Vector) is null; end Alr.Testing; alire-1.2.1/src/alr/alr-utils-temp_file.adb000066400000000000000000000022351430264165500205120ustar00rootroot00000000000000with Ada.Directories; with Ada.Numerics.Discrete_Random; package body Alr.Utils.Temp_File is -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out File) is use Ada.Directories; begin if Exists (This.Name) then Delete_File (This.Name); null; end if; end Finalize; -------------- -- New_File -- -------------- function New_File return File is type Parts is ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); package Rand is new Ada.Numerics.Discrete_Random (Parts); Gen : Rand.Generator; Suffix : String (1 .. 10); begin Rand.Reset (Gen); for C of Suffix loop C := Parts'Image (Rand.Random (Gen))(2); end loop; declare Name : constant String := "alrtmp." & Suffix; begin return (Ada.Finalization.Limited_Controlled with Name'Length, Name); end; end New_File; end Alr.Utils.Temp_File; alire-1.2.1/src/alr/alr-utils-temp_file.ads000066400000000000000000000011551430264165500205330ustar00rootroot00000000000000with Ada.Finalization; package Alr.Utils.Temp_File is -- Scopes a unique name that could be used for a file. -- At finalization will delete the file, if it exists type File (<>) is new Ada.Finalization.Limited_Controlled with private; function New_File return File; function Name (This : File) return String; private type File (Len : Natural) is new Ada.Finalization.Limited_Controlled with record Name : String (1 .. Len); end record; overriding procedure Finalize (This : in out File); function Name (This : File) return String is (This.Name); end Alr.Utils.Temp_File; alire-1.2.1/src/alr/alr-utils.adb000066400000000000000000000005461430264165500165530ustar00rootroot00000000000000package body Alr.Utils is -------------- -- Contains -- -------------- function Contains (V : AAA.Strings.Vector; Subst : String) return Boolean is begin for Str of V loop if AAA.Strings.Contains (Str, Subst) then return True; end if; end loop; return False; end Contains; end Alr.Utils; alire-1.2.1/src/alr/alr-utils.ads000066400000000000000000000003151430264165500165660ustar00rootroot00000000000000with AAA.Strings; package Alr.Utils is -- Miscellaneous utilities function Contains (V : AAA.Strings.Vector; Subst : String) return Boolean; -- Any of the strings contains it end Alr.Utils; alire-1.2.1/src/alr/alr.ads000066400000000000000000000017371430264165500154410ustar00rootroot00000000000000with Alire; with Simple_Logging; with CLIC.TTY; package Alr with Preelaborate is -- Nothing of note in this root package. Entities declared here are -- generally useful everywhere or in many packages: Exceptions for -- commands, tracing for all Child_Failed : exception; -- Used to notify that a subprocess completed with non-zero error Command_Failed : exception; -- Signals "normal" command completion with failure (i.e., no need to print -- stack trace). -- Use some general types for the benefit of all child packages: pragma Warnings (Off); use all type Alire.Crate_Name; use all type Simple_Logging.Levels; pragma Warnings (On); package Trace renames Simple_Logging; package TTY renames CLIC.TTY; function "+" (S : Alire.UString) return String renames Alire.UStrings.To_String; -- Some Paths constants that help to break circularities Bootstrap_Hash : constant String := "bootstrap"; end Alr; alire-1.2.1/src/alr/default_session/000077500000000000000000000000001430264165500173515ustar00rootroot00000000000000alire-1.2.1/src/alr/default_session/alr-session.ads000066400000000000000000000022721430264165500223040ustar00rootroot00000000000000package Alr.Session is -- Warning: withing this file will cause the dependent file to be recompiled in every rebuild -- Try to minimize dependencies (currently Alr.Self isolates them all, so is the only file rebuilt) -- private -- To prevent use besides from Alr.Self -- Making this private was ideal, but that causes the recompilation of every file depending -- on Alr.Session.Child, since it has visibility of the private part. So, in all, it's worse. Alr_Src_Folder : constant String := ""; -- For alr instances that are session specific, we need a way to locate the src folder -- (just for the case where it is not the canonical one, that is: while developing) Hash : constant String := "bootstrap"; -- In the current per-session setup, this should always match unless the dependencies files has been -- tampered with in such a way that its timestamp has not been updated Full_Index : constant Boolean := False; -- Some commands require a full index and some others not. -- We use this to separate bootstrap from index status Session_Build : constant Boolean := False; -- True in session-specific builds end Alr.Session; alire-1.2.1/src/alr/obsolete/000077500000000000000000000000001430264165500157765ustar00rootroot00000000000000alire-1.2.1/src/alr/obsolete/alr-commands-depend.adb000066400000000000000000000203771430264165500222710ustar00rootroot00000000000000with Ada.Strings; with Ada.Strings.Fixed; with Ada.Strings.Maps; with Ada.Text_IO; with Alire.Conditional; with Alire.Dependencies; with Alire.Index; with Alire.Releases; with Alire.Roots; with Alr.Parsers; with Alr.Platform; with Alr.Root; with Alr.Spawn; with Alr.Templates; with GNAT.Command_Line; with Semantic_Versioning; package body Alr.Commands.Depend is --------- -- Add -- --------- function Add (Deps : Alire.Conditional.Dependencies; New_Dep : String) return Alire.Conditional.Dependencies is use all type Alire.Conditional.Dependencies; Requested : constant Parsers.Allowed_Milestones := Parsers.Project_Versions (New_Dep); begin if not Query.Exists (Requested.Project) then Reportaise_Command_Failed ("The requested project was not found in the catalog: " & (+Requested.Project)); end if; return Result : constant Alire.Conditional.Dependencies := Deps and Alire.Conditional.New_Dependency (Requested.Project, Requested.Versions) do if not Query.Is_Resolvable (Result.Evaluate (Platform.Properties)) then Reportaise_Command_Failed ("Adding " & New_Dep & " has no dependency solution"); else Trace.Detail ("Dependency " & New_Dep & " successfully added"); end if; end return; end Add; --------- -- Del -- --------- function Del (Deps : Alire.Conditional.Dependencies; Old_Dep : String) return Alire.Conditional.Dependencies is use all type Alire.Conditional.Dependencies; use all type Semantic_Versioning.Version_Set; Requested : constant Parsers.Allowed_Milestones := Parsers.Project_Versions (Old_Dep); begin if Requested.Versions /= Semantic_Versioning.Any then Trace.Warning ("Version is not used when removing dependencies: " & Old_Dep); end if; -- Iterate over actual dependencies and remove any matching the given return Filtered : Alire.Conditional.Dependencies do declare procedure Check (Dep : Alire.Conditional.Dependencies) is use all type Alire.Conditional.For_Dependencies.Kinds; begin case Dep.Kind is when Condition => Trace.Warning ("Skipping unsupported conditional dependency"); when Value => -- A value is a vector of dependencies! if Dep.Value.Project /= Requested.Project then Filtered := Filtered and Alire.Conditional.New_Dependency (Dep.Value.Project, Dep.Value.Versions); end if; when Vector => for I in Dep.Iterate loop Check (Dep (I)); end loop; end case; end Check; begin Deps.Iterate_Children (Check'Access); end; end return; end Del; --------------------- -- Replace_Current -- --------------------- procedure Replace_Current (Deps : Alire.Conditional.Dependencies) is begin -- Set, regenerate and update declare New_Root : constant Alire.Roots.Root := Alire.Index.Set_Root (Root.Project, Deps) with Unreferenced; Needed : constant Types.Platform_Dependencies := Deps.Evaluate (Platform.Properties); begin Templates.Generate_Prj_Alr (Templates.Unreleased, Root.Project, Deps => Needed); Trace.Detail ("Regeneration finished, updating now"); end; Spawn.Alr (Cmd_Update); end Replace_Current; --------- -- Add -- --------- procedure Add is Deps : Alire.Conditional.Dependencies := Root.Current.Dependencies; begin for I in 1 .. Num_Arguments loop Deps := Add (Deps, Argument (I)); end loop; Replace_Current (Deps); end Add; --------- -- Del -- --------- procedure Del is Deps : Alire.Conditional.Dependencies := Root.Current.Dependencies; begin for I in 1 .. Num_Arguments loop Deps := Del (Deps, Argument (I)); end loop; Replace_Current (Deps); end Del; ---------- -- From -- ---------- procedure From is use Ada.Text_IO; use Utils; Deps : Alire.Conditional.Dependencies; ------------- -- Extract -- ------------- procedure Extract (Line : String) is use Ada.Strings; use Ada.Strings.Fixed; use Ada.Strings.Maps; -- Line contains "alr depend", is crunched and lowercased First, Last : Natural := Line'First - 1; Found : Boolean := False; begin loop Find_Token (Line, To_Set (' '), From => Last + 1, Test => Outside, First => First, Last => Last); exit when First > Line'Last; if Found then Deps := Add (Deps, Line (First .. Last)); elsif Line (First .. Last) = "--add" then Found := True; end if; exit when Last = Line'Last; end loop; end Extract; ---------------- -- Check_File -- ---------------- procedure Check_File (Name : String) is File : File_Type; begin if not OS_Lib.Is_Regular_File (Name) then Reportaise_Command_Failed ("Given file not found: " & Name); end if; Open (File, In_File, Name); while not End_Of_File (File) loop declare Line : constant String := Crunch (To_Lower_Case (Get_Line (File))); begin exit when Contains (Line, "project"); if Contains (Line, "alr depend") then Extract (Line); end if; end; end loop; Close (File); end Check_File; begin for I in 1 .. Num_Arguments loop Check_File (Argument (I)); end loop; Replace_Current (Deps); end From; ---------- -- List -- ---------- procedure List is begin Root.Platform_Dependencies.Print; end List; -------------------------- -- Display_Help_Details -- -------------------------- overriding procedure Display_Help_Details (Cmd : Command) is pragma Unreferenced (Cmd); begin New_Line; Print_Project_Version_Sets; end Display_Help_Details; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Command) is begin Requires_Project; -- No parameters: give current platform dependencies if not (Cmd.Add or else Cmd.Del or else Cmd.From) then List; return; end if; if (Cmd.Add and Cmd.Del) or (Cmd.Add and Cmd.From) or (Cmd.Del and Cmd.From) then Reportaise_Wrong_Arguments ("Exactly one of --add, --del, --from is required"); end if; if Num_Arguments < 1 then if Cmd.Add or Cmd.Del then Reportaise_Wrong_Arguments ("At least one dependency required"); else Reportaise_Wrong_Arguments ("At least one GPR file to process required"); end if; end if; if Cmd.Add then Requires_Full_Index (Even_In_Session => True); Add; elsif Cmd.Del then Del; else Requires_Full_Index (Even_In_Session => True); From; end if; Spawn.Alr (Cmd_Update); end Execute; -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Command; Config : in out GNAT.Command_Line.Command_Line_Configuration) is use GNAT.Command_Line; begin Define_Switch (Config, Cmd.Add'Access, "", "--add", "Add given dependencies"); Define_Switch (Config, Cmd.Del'Access, "", "--del", "Remove given dependencies"); Define_Switch (Config, Cmd.From'Access, "", "--from", "Use dependencies declared within GPR project file"); end Setup_Switches; end Alr.Commands.Depend; alire-1.2.1/src/alr/obsolete/alr-commands-depend.ads000066400000000000000000000015301430264165500223000ustar00rootroot00000000000000package Alr.Commands.Depend is type Command is new Commands.Command with private; overriding procedure Display_Help_Details (Cmd : Command); overriding procedure Execute (Cmd : in out Command); overriding procedure Setup_Switches (Cmd : in out Command; Config : in out GNAT.Command_Line.Command_Line_Configuration); overriding function Short_Description (Cmd : Command) return String is ("Add/remove dependencies to the working project"); overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("{ {--add | --del} [project[versions]]... | --from ... }"); private type Command is new Commands.Command with record Add : aliased Boolean := False; Del : aliased Boolean := False; From : aliased Boolean := False; end record; end Alr.Commands.Depend; alire-1.2.1/src/alr/os_linux/000077500000000000000000000000001430264165500160225ustar00rootroot00000000000000alire-1.2.1/src/alr/os_linux/.retaindir000066400000000000000000000000001430264165500177720ustar00rootroot00000000000000alire-1.2.1/src/alr/os_linux/os.c000066400000000000000000000001031430264165500166010ustar00rootroot00000000000000#include int alr_geteuid(void) { return geteuid(); } alire-1.2.1/src/alr/os_macos/000077500000000000000000000000001430264165500157655ustar00rootroot00000000000000alire-1.2.1/src/alr/os_macos/.retaindir000066400000000000000000000000001430264165500177350ustar00rootroot00000000000000alire-1.2.1/src/alr/os_windows/000077500000000000000000000000001430264165500163555ustar00rootroot00000000000000alire-1.2.1/src/alr/os_windows/.retaindir000066400000000000000000000000001430264165500203250ustar00rootroot00000000000000alire-1.2.1/testsuite/000077500000000000000000000000001430264165500146465ustar00rootroot00000000000000alire-1.2.1/testsuite/README.md000066400000000000000000000015431430264165500161300ustar00rootroot00000000000000Alire/ALR's testsuite ===================== This directory intends to host a comprehensive testsuite for Alire/ALR as a library/tool. The testsuite framework currently requires a Python2 interpreter with the e3-testsuite package (from PyPI) installed. Assuming your environment already has a Python2 interpreter and has `virtualenv` installed, here is a quick cookbook to run the testsuite: ```sh # Create a virtualenv (prefix to install packages) # The exact command varies from one Linux distrib to another: # virtualenv, virtualenv2, virtualenv-2.7, ... $ virtualenv2 my-virtual-env # Update your environment to use it $ source my-virtual-env/bin/activate # Install e3-testsuite and all its dependencies $ pip install e3-testsuite # You should now be able to run the testsuite (make sure you built alr and # made it available with your PATH): $ ./run.py ``` alire-1.2.1/testsuite/disabled/000077500000000000000000000000001430264165500164155ustar00rootroot00000000000000alire-1.2.1/testsuite/disabled/manifest/000077500000000000000000000000001430264165500202235ustar00rootroot00000000000000alire-1.2.1/testsuite/disabled/manifest/version-mismatch/000077500000000000000000000000001430264165500235135ustar00rootroot00000000000000alire-1.2.1/testsuite/disabled/manifest/version-mismatch/test.py000066400000000000000000000015631430264165500250510ustar00rootroot00000000000000""" Check that a local manifest with wrong metadata version is indeed reported """ from drivers.alr import run_alr from drivers.asserts import assert_match from os import chdir import re # Create a regular working release run_alr("init", "--bin", "xxx") chdir("xxx") # Change the version with open("alire/xxx.toml", "r") as file: lines = file.readlines() with open("alire/xxx.toml", "w") as file: for line in lines: if line.startswith("metadata-version"): file.write("metadata-version = '0.0'\n") else: file.write(line) # Verify the error p = run_alr('show', complain_on_error=False) assert p.status != 0, "command should have errored" assert_match(".*" + "Mismatch between manifest version" + " \(.*\) and alr index version \(.*\)" + ".*", p.out, flags=re.S) print("SUCCESS") alire-1.2.1/testsuite/disabled/manifest/version-mismatch/test.yaml000066400000000000000000000000261430264165500253540ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/disabled/manifest/version-missing/000077500000000000000000000000001430264165500233575ustar00rootroot00000000000000alire-1.2.1/testsuite/disabled/manifest/version-missing/test.py000066400000000000000000000014721430264165500247140ustar00rootroot00000000000000""" Check that a local manifest without version is reported as old """ from drivers.alr import run_alr from drivers.asserts import assert_match from os import chdir import re # Create a regular working release run_alr("init", "--bin", "xxx") chdir("xxx") # Remove the version with open("alire/xxx.toml", "r") as file: lines = file.readlines() with open("alire/xxx.toml", "w") as file: for line in lines: if not line.startswith("metadata-version"): file.write(line) # Verify the error p = run_alr('show', complain_on_error=False) assert p.status != 0, "command should have errored" assert_match(".*" + "Local manifest file is for an old alr version" + re.escape(" (lacks metadata-version field)") + ".*", p.out, flags=re.S) print("SUCCESS") alire-1.2.1/testsuite/disabled/manifest/version-missing/test.yaml000066400000000000000000000000261430264165500252200ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/disabled/publish/000077500000000000000000000000001430264165500200635ustar00rootroot00000000000000alire-1.2.1/testsuite/disabled/publish/hash/000077500000000000000000000000001430264165500210065ustar00rootroot00000000000000alire-1.2.1/testsuite/disabled/publish/hash/test.py000066400000000000000000000022741430264165500223440ustar00rootroot00000000000000""" Check the `alr publish --hash` subcommand """ import re from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_eq # Test vectors from https://www.di-mgt.com.au/sha_testvectors.html filenames = ["empty.tgz", "abc.tgz", "bits448.tgz"] contents = ["", "abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"] hashes = [ "sha512:cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47" "d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", "sha512:ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a21" "92992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "sha512:204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596" "fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"] # Generate a test "crate" in the current folder with known contents and hash: for i in range(len(filenames)): with open(filenames[i], "w") as file: file.write(contents[i]) # Hash and check p = run_alr('publish', '--hash', 'file://' + filenames[i], quiet=False) assert_eq(hashes[i] + '\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/disabled/publish/hash/test.yaml000066400000000000000000000000261430264165500226470ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/drivers/000077500000000000000000000000001430264165500163245ustar00rootroot00000000000000alire-1.2.1/testsuite/drivers/__init__.py000066400000000000000000000000001430264165500204230ustar00rootroot00000000000000alire-1.2.1/testsuite/drivers/alr.py000066400000000000000000000376411430264165500174670ustar00rootroot00000000000000""" Helpers to run alr in the testsuite. """ import os import os.path from shutil import copytree from e3.os.process import Run, quote_arg from e3.fs import mkdir from e3.testsuite.driver.classic import ProcessResult import re TESTSUITE_ROOT = os.path.dirname(os.path.dirname( os.path.abspath(__file__))) class CalledProcessError(Exception): pass def distro_is_known(): p = run_alr('version') return not re.match('.*distribution:.*DISTRO_UNKNOWN.*', p.out, flags=re.S) def prepare_env(config_dir, env): """ Prepare the environment to run "alr". This creates the `config_dir` directory and updates `env` (environment variables) to point to it as alr's configuration directory. """ # Disable any user's git configuration to ensure reproducible git behavior. # https://github.com/git/git/commit/4179b4897f2de28858acaebd6382c06c91532e98 env["GIT_CONFIG_GLOBAL"] = "/dev/null" env["GIT_CONFIG_SYSTEM"] = "/dev/null" config_dir = os.path.abspath(config_dir) mkdir(config_dir) env['ALR_CONFIG'] = config_dir # We pass config location explicitly in the following calls since env is # not yet applied. # Disable autoconfig of the community index, to prevent unintended use of # it in tests, besides the overload of fetching it run_alr("-c", config_dir, "config", "--global", "--set", "index.auto_community", "false") # Disable selection of toolchain to preserve older behavior. Tests that # require a configured compiler will have to set it up explicitly. run_alr("-c", config_dir, "toolchain", "--disable-assistant") # Disable warning on old index, to avoid having to update index versions # when they're still compatible. run_alr("-c", config_dir, "config", "--global", "--set", "warning.old_index", "false") # If distro detection is disabled via environment, configure so in alr if "ALIRE_DISABLE_DISTRO" in env: if env["ALIRE_DISABLE_DISTRO"] == "true": run_alr("-c", config_dir, "config", "--global", "--set", "distribution.disable_detection", "true") def run_alr(*args, **kwargs): """ Run "alr" with the given arguments. :param bool complain_on_error: If true and the subprocess exits with a non-zero status code, print information on the standard output (for debugging) and raise a CalledProcessError (to abort the test). :param bool quiet: If true (which is the default), append "-q" to the command line. :param bool debug: If true (which is the default), append "-d" to the command line. This ensures uncaught exceptions are logged instead of presenting a sanitized error intended for final users. :rtype: ProcessResult """ complain_on_error = kwargs.pop('complain_on_error', True) debug = kwargs.pop('debug', True) force = kwargs.pop('force', False) quiet = kwargs.pop('quiet', True) if kwargs: first_unknown_kwarg = sorted(kwargs)[0] raise ValueError('Invalid argument: {}'.format(first_unknown_kwarg)) argv = ['alr'] argv.insert(1, '-n') # always non-interactive if debug: argv.insert(1, '-d') if force: argv.insert(1, '-f') if quiet: argv.insert(1, '-q') argv.extend(args) p = Run(argv) if p.status != 0 and complain_on_error: print('The following command:') print(' {}'.format(' '.join(quote_arg(arg) for arg in argv))) print('Exitted with status code {}'.format(p.status)) print('Output:') print(p.out) raise CalledProcessError('alr returned non-zero status code') # Convert CRLF line endings (Windows-style) to LF (Unix-style). This # canonicalization is necessary to make output comparison work on all # platforms. return ProcessResult(p.status, p.out.replace('\r\n', '\n')) def fixtures_path(*args): """ Return a path under the testsuite `fixtures` directory. """ return os.path.join(TESTSUITE_ROOT, 'fixtures', *args) def prepare_indexes(config_dir, working_dir, index_descriptions): """ Populate alr's config directory with the provided indexes. :param str config_dir: Configuration directory for "alr". :param dict[str, dict] index_description: Mapping from index names to data used to prepare the corresponding indexes. This data dictionary accepts the following keys: * "dir" (str): Name of the directory that contains the index files. It is optional: if not provided, use the name of the index. * "in_fixtures" (bool): Whether the directory that contains the index files is to be found in the "fixtures" directory (by default). Look in the testcase's directory otherwise. * "priority" (int): Priority for this index. 1 by default. """ indexes_dir = os.path.join(config_dir, 'indexes') mkdir(indexes_dir) for name, desc in index_descriptions.items(): # Extract individual fields in `desc` def invalid_desc(reason): raise ValueError('invalid index description for {}: {}' .format(name, reason)) def check_type(what, type_name, value, typ): if not isinstance(value, typ): invalid_desc('{} must be a {}'.format(what, type_name)) check_type('description', 'a dictionary', desc, dict) files_dir = desc.pop('dir', name) check_type('"dir"', 'a string', files_dir, str) in_fixtures = desc.pop('in_fixtures', True) check_type('"in_fixtures"', 'a boolean', in_fixtures, bool) copy_crates_src = desc.pop('copy_crates_src', False) check_type('"copy_crates_src"', 'a boolean', copy_crates_src, bool) priority = desc.pop('priority', 1) check_type('"priority"', 'an integer', priority, int) if desc: first_unknown_key = sorted(desc)[0] invalid_desc('unknown key {}'.format(repr(first_unknown_key))) # Compute the directory that contains index files files_dir = (fixtures_path(files_dir) if in_fixtures else files_dir) if copy_crates_src: crates_dir = fixtures_path('crates') copytree(crates_dir, os.path.join(working_dir, 'crates')) # Crates are adjacent to the index but outside it (otherwise the # index loader detects spurious files). # Finally create the index description in the config directory index_dir = os.path.join(indexes_dir, name) mkdir(index_dir) with open(os.path.join(index_dir, 'index.toml'), 'w') as f: f.write(""" name = '{}' priority = {} url = '{}' """.format(name, priority, os.path.join(working_dir, files_dir))) def index_branch(): """ Identify the expected index branch from `alr version` """ p = run_alr("version", quiet=False) for line in p.out.splitlines(): if line.startswith("community index"): return line.split(':')[1].strip() raise Exception("Unexpected alr output, cannot find index version") def index_version(): """ Identify the expected index version from `alr version` """ return index_branch().split('-')[1] def init_local_crate(name="xxx", binary=True, enter=True, update=True): """ Initialize a local crate and enter its folder for further testing. :param str name: Name of the crate :param bool binary: Initialize as --bin or --lib :param bool enter: Enter the created crate directory """ run_alr("init", name, "--bin" if binary else "--lib") if update: os.chdir(name) run_alr("update") os.chdir("..") if enter: os.chdir(name) def alr_lockfile(): return os.path.join("alire", "alire.lock") def alr_manifest(): return "alire.toml" def alr_touch_manifest(): """ Make the lockfile older than the manifest, to ensure editions to the manifest are detected. """ if os.path.exists(alr_lockfile()): os.utime(alr_lockfile(), (0, 0)) def delete_array_entry_from_manifest(array, crate, fail_if_missing=True, update=True): """ Manual deletion of dependencies/pins. As we emit the additions too, this is simpler than the actual code in alr. """ with open(alr_manifest(), "rt") as manifest: found = False lines = manifest.readlines() orig = lines for i in range(1, len(lines)): if lines[i].startswith(f"{crate} =") \ and lines[i-1] == f"[[{array}]]\n": lines.pop(i) lines.pop(i-1) found = True break # Write the new manifest if found: with open(alr_manifest(), "wt") as manifest: manifest.writelines(lines) if update: run_alr("pin") # Ensure changes don't affect next command output elif fail_if_missing: raise RuntimeError (f"Could not remove crate {crate} in lines:\n" + str(orig)) # Make the lockfile "older" (otherwise timestamp is identical) alr_touch_manifest() def alr_unpin(crate, manual=True, fail_if_missing=True, update=True): """ Unpin a crate, if pinned, or no-op otherwise. Will edit the manifest or use the command-line, according to manual. Must be run in a crate root. If update, run `alr pin` to force computation of new solution """ if manual: # Locate and remove the lines with the pin delete_array_entry_from_manifest("pins", crate, fail_if_missing, update) else: if not update: raise RuntimeError("Update cannot be disabled when using the" " command-line interface") run_alr("pin", "--unpin", crate) def alr_pin(crate, version="", path="", url="", commit="", branch="", manual=True, update=True, force=False): """ Pin a crate, either manually or using the command-line interface. Use only one of version, path, url. Must be run in a crate root. When update, run `alr pin` so the new solution is computed. """ if commit != "" and branch != "": raise RuntimeError("Do not specify both commit and branch") if manual: alr_unpin(crate, fail_if_missing=False) # Just in case if version != "": pin_line = f'{crate} = {{ version = "{version}" }}' elif path != "": pin_line = f"{crate} = {{ path = '{path}' }}" # literal so \ works elif url != "" and commit != "": pin_line = f"{crate} = {{ url = '{url}', commit = '{commit}' }}" elif url != "" and branch != "": pin_line = f"{crate} = {{ url = '{url}', branch = '{branch}' }}" elif url != "": pin_line = f"{crate} = {{ url = '{url}' }}" else: raise ValueError("Specify either version, path or url") with open(alr_manifest(), "at") as manifest: manifest.writelines(["\n[[pins]]\n", pin_line + "\n"]) # Make the lockfile "older" (otherwise timestamp is identical) alr_touch_manifest() if update: return run_alr("pin") # so the changes in the manifest are applied else: if not update: raise RuntimeError("Update cannot be disabled when using the" " command-line interface") args = [] if version != "": args += [f"{crate}={version}"] else: args += [crate] if path != "": args += ["--use", f"{path}"] elif url != "": args += ["--use", f"{url}"] if commit != "": args += ["--commit", f"{commit}"] elif branch != "": args += ["--branch", f"{branch}"] return run_alr("pin", *args, force=force) def alr_with(dep="", path="", url="", commit="", branch="", delete=False, manual=True, update=True, force=False): """ Add/remove dependencies either through command-line or manifest edition """ if commit != "" and branch != "": raise RuntimeError("Do not specify both commit and branch") if path != "" and url != "": raise RuntimeError("Do not specify both path and url") if manual and dep == "": raise RuntimeError("Cannot manually add without explicit dependency") separators = "/=^~<>*" # Fix the dependency if no version subset is in dep if manual and not any([separator in dep for separator in separators]): dep += "*" # Find the separator position pos = len(dep) + 1 for separator in separators: idx = dep.find(separator) pos = idx if 0 < idx < pos else pos if manual and pos > len(dep): raise RuntimeError(f"Should not happen, dep is {dep}") if manual: if delete: delete_array_entry_from_manifest("depends-on", dep, update=update) else: with open(alr_manifest(), "at") as manifest: lines = ["\n[[depends-on]]\n", f'{dep[:pos]} = "{dep[pos:]}"\n'] manifest.writelines(lines) if path != "" or url != "": alr_pin(crate=f'{dep[:pos]}', path=path, url=url, commit=commit, branch=branch, manual=manual, update=False) # Make the lockfile "older" (otherwise timestamp is identical) alr_touch_manifest() if update: return run_alr("with", force=force) else: if delete: run_alr("with", "--del", dep) else: args = ["with"] if dep != "": args += [dep] if path != "": args += ["--use", f"{path}"] elif url != "": args += ["--use", f"{url}"] if commit != "": args += ["--commit", f"{commit}"] elif branch != "": args += ["--branch", f"{branch}"] return run_alr(*args, force=force) def add_action(type, command, name=""): """ Add an action to the manifest in the current directory. :param str type: "pre-build", etc :param list command: array/list of strings that make up the command """ if not os.path.isfile(alr_manifest()): raise RuntimeError("Manifest not found") with open(alr_manifest(), "a") as manifest: manifest.write("[[actions]]\n") manifest.write(f"type = '{type}'\n") manifest.write(f"command = {command}\n") if name != "": manifest.write(f"name = '{name}'\n") def alr_submit(manifest, index_path): """ Move a manifest with origin into its proper location in an index """ assert os.path.isfile(manifest), f"Manifest file not found: {manifest}" # Extract crate name file = os.path.basename(manifest) name = file.split('-')[0] # Prepare destination at index if not os.path.isdir(index_path): raise RuntimeError("Given index path does not exist or " "not a folder: " + index_path) # Create folder hierarchy in the index os.makedirs(os.path.join(index_path, "index", name[:2], name)) # Move published manifest to proper index location os.rename(manifest, os.path.join(index_path, "index", name[:2], name, file)) def alr_publish(name, version="0.0.0", submit=True, index_path=os.path.join("..", "my_index"), quiet=True): """ Run `alr publish` at the current location and optionally move the produced manifest to its intended location in a local index. """ p = run_alr("publish", force=True, quiet=quiet) # Force due to missing optional crate info by `alr init` if submit: alr_submit(os.path.join("alire", "releases", f"{name}-{version}.toml"), index_path) return p alire-1.2.1/testsuite/drivers/asserts.py000066400000000000000000000033451430264165500203670ustar00rootroot00000000000000""" This module provides several helpers to perform user-friendly assertions in testcases based on Python scripts. """ import re import difflib from drivers.alr import run_alr def indent(text, prefix=' '): """ Return `text` indented using `prefix`. """ return '\n'.join(prefix + repr(line) for line in text.splitlines()) def pretty_diff(expected, actual): diff = difflib.unified_diff(expected.splitlines(), actual.splitlines(), fromfile='expected', tofile='actual') return "\n".join(diff) def assert_eq(expected, actual, label=None): if expected != actual: if isinstance(actual, str) and isinstance(expected, str): diff = '\nDiff:\n' + pretty_diff(expected, actual) else: diff = '' text = ['Unexpected {}:'.format(label or 'output'), 'Expecting:', indent(str(expected)), 'But got:', indent(str(actual))] assert False, '\n'.join(text) + diff def assert_match(expected_re, actual, label=None, flags=re.S): if not re.match(expected_re, actual, flags=flags): text = ['Unexpected {}'.format(label or 'output'), 'Expecting a match on:', indent(expected_re), 'But got:', indent(actual)] assert False, '\n'.join(text) def match_solution(regex, escape=False, whole=False): "Check whether a regex matches the current solution" p = run_alr("with", "--solve") wrap = "" if whole else ".*" assert_match(wrap + (regex if not escape else re.escape(regex)) + wrap, p.out) alire-1.2.1/testsuite/drivers/helpers.py000066400000000000000000000135001430264165500203370ustar00rootroot00000000000000""" Assorted helpers that are reused by several tests. """ from subprocess import run from zipfile import ZipFile import hashlib import re import os import platform import shutil import stat # Return the entries (sorted) under a given folder, both folders and files # Optionally, return only those matching regex def contents(dir, regex=""): assert os.path.exists(dir), "Bad path for enumeration: {}".format(dir) if regex != "": matcher = re.compile(regex) return sorted([os.path.join(root, name).replace('\\', '/') for root, dirs, files in os.walk(dir) for name in dirs + files if regex == "" or matcher.search(os.path.join(root, name).replace('\\', '/')) ]) # Return the content of a text file as a single string with embedded newlines def content_of(filename): out = '' with open(filename, 'r') as f: for l in f: out += l return out def lines_of(filename): """ Return the contents of a file as an array of lines (with line breaks) """ with open(filename, 'r') as f: return f.readlines() # Assert two values are equal or format the differences def compare(found, wanted): assert found == wanted, 'Got: {}\nWanted: {}'.format(found, wanted) # Check line appears in file def check_line_in(filename, line): """ Assert that the `filename` text file contains at least one line that contains `line`. """ with open(filename, 'r') as f: for l in f: if l.rstrip() == line: break else: assert False, 'Could not find {} in {}:\n{}'.format( repr(line), filename, content_of(filename)) def on_windows(): return platform.system() == "Windows" def distribution(): if os.environ.get('ALIRE_DISABLE_DISTRO') == 'true': return 'DISTRO_UNKNOWN' known_distro = ["debian", "ubuntu", "msys2", "arch", "rhel", "centos", "fedora"] if os.path.exists("/etc/os-release"): for key in ['id', 'id_like']: with open("/etc/os-release") as f: for line in f: split = line.strip().split('=') if len(split) == 2: val = split[1].lower().strip('"') print("val = '%s'" % val) if split[0].lower() == key and val in known_distro: return val return 'DISTRO_UNKNOWN' elif on_windows(): return 'MSYS2' else: return 'DISTRO_UNKNOWN' def path_separator(): return ':' if os.name != 'nt' else ';' def dir_separator(): return '/' if os.name != 'nt' else '\\' def host_architecture(): host_arch = platform.machine().lower() if host_arch == "amd64": host_arch = "x86_64" elif host_arch == "arm64": host_arch = "aarch64" return host_arch def host_os(): host_os = platform.system().lower() if host_os == "darwin": host_os = 'macos' return host_os # Add a 'with "something";' at the top of a project file def with_project(file, project): with open(file, 'r+') as f: content = f.read() f.seek(0, 0) f.write('with "{}";'.format(project) + '\n' + content) def git_branch(path="."): """ Return the branch name of the checkout """ start_cwd = os.getcwd() os.chdir(path) branch = run(["git", "branch"], capture_output=True).stdout.split()[1] os.chdir(start_cwd) return branch.decode() def git_head(path="."): """ Return the head commit in a git repo """ start_cwd = os.getcwd() os.chdir(path) head_commit = run(["git", "log", "-n1", "--no-abbrev", "--oneline"], capture_output=True).stdout.split()[0] os.chdir(start_cwd) return head_commit.decode() def git_blast(path): """ Change permissions prior to deletion, as otherwise Windows is uncapable of removing git checkouts """ for dirpath, dirnames, filenames in os.walk(path): os.chmod(dirpath, stat.S_IRWXU) for filename in filenames: os.chmod(os.path.join(dirpath, filename), stat.S_IRWXU) shutil.rmtree(path) def init_git_repo(path): """ Initialize and commit everything inside a folder, returning the HEAD commit """ start_cwd = os.getcwd() os.chdir(path) assert run(["git", "init", "."]).returncode == 0 assert run(["git", "config", "user.email", "alr@testing.com"]) \ .returncode == 0 assert run(["git", "config", "user.name", "Alire Testsuite"]) \ .returncode == 0 # Workaround for Windows, where somehow we get undeletable files in temps: with open(".gitignore", "wt") as file: file.write("*.tmp\n") head = commit_all(".") os.chdir(start_cwd) return head def commit_all(path): """ Commit all changes in a repo and return the HEAD commit """ start_cwd = os.getcwd() os.chdir(path) assert run(["git", "add", "."]).returncode == 0 assert run(["git", "commit", "-m", "repo created"]).returncode == 0 head_commit = run(["git", "log", "-n1", "--no-abbrev", "--oneline"], capture_output=True).stdout.split()[0] os.chdir(start_cwd) return head_commit.decode() def zip_dir(path, filename): """ Zip contents of path into filename. Relative paths are preserved. """ with ZipFile(filename, 'w') as zip: for dir, subdirs, files in os.walk(path): for file in files: abs_file = os.path.join(dir, file) zip.write(abs_file, abs_file) def md5sum(file): """Return the hex md5 hash of a file""" with open(file, "rb") as f: file_hash = hashlib.md5() while chunk := f.read(8192): file_hash.update(chunk) return file_hash.hexdigest() alire-1.2.1/testsuite/drivers/python_script.py000066400000000000000000000047631430264165500216150ustar00rootroot00000000000000import os import sys from e3.fs import sync_tree from e3.testsuite.driver.classic import ClassicTestDriver, TestAbortWithFailure from e3.testsuite.result import TestStatus from drivers.alr import prepare_env, prepare_indexes class PythonScriptDriver(ClassicTestDriver): """ Test driver to run a "test.py" Python script. This test driver runs a Python script. For a testcase to succeeds, the script expects it to exit with status code 0, its standard error stream to be empty and its standard output stream to end with a line that contains "SUCCESS". Anything else results in the test failing. """ # This is a workaround for Windows, where attempting to use rlimit by e3-core # causes permission errors. TODO: remove once e3-core has a proper solution. @property def default_process_timeout(self): return None def run(self): env = dict(os.environ) # prepare a private environment for Python scripts to run "alr". config_dir = os.path.join(self.test_env['working_dir'], 'alr-config') prepare_env(config_dir, env) # If requested, prepare indexes to be used by "alr". if 'indexes' in self.test_env: prepare_indexes(config_dir, self.test_env['working_dir'], self.test_env.get('indexes', {})) # Also give it access to our Python helpers python_path = env.get('PYTHONPATH', '') path_for_drivers = os.path.abspath( os.path.dirname(os.path.dirname(__file__))) env['PYTHONPATH'] = '{}{}{}'.format( path_for_drivers, os.path.pathsep, python_path ) if python_path else path_for_drivers # Run the Python script with the current interpreter. check_call aborts # the test if the interpreter exits with non-zero status code. p = self.shell([sys.executable, 'test.py'], env=env, cwd=self.test_env['working_dir']) # Check that stderr is empty if False and p.err: self.result.log += 'non-empty stderr:\n' self.result.log += p.err raise TestAbortWithFailure('non-empty stderr') # Check that the last line in stdout is "SUCCESS" out_lines = p.out.splitlines() if not out_lines or out_lines[-1] != 'SUCCESS': self.result.log += 'missing SUCCESS output line' raise TestAbortWithFailure('missing SUCCESS output line') alire-1.2.1/testsuite/fix-text.sh000077500000000000000000000003271430264165500167570ustar00rootroot00000000000000# Replace $1 by $2 in place, recursively old="$1" new="$2" if [ "$old" == "" ] || [ "$new" == "" ]; then echo use: $0 ' ' exit 1 fi grep -rl . | parallel sed -i "s/${old}/${new}/g" {} alire-1.2.1/testsuite/fix-versions.sh000077500000000000000000000001741430264165500176430ustar00rootroot00000000000000#!/bin/bash oldversion=1.0 newversion=1.1 find . -type f -name index.toml -exec sed -i "s/$oldversion/$newversion/" {} \; alire-1.2.1/testsuite/fixtures/000077500000000000000000000000001430264165500165175ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/basic_index/000077500000000000000000000000001430264165500207675ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/basic_index/he/000077500000000000000000000000001430264165500213635ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/basic_index/he/hello/000077500000000000000000000000001430264165500224665ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/basic_index/he/hello/hello-1.0.0.toml000066400000000000000000000010351430264165500251170ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" long-description = "This is an example of long description in a multi-line string.\n\nMarkdown formating `can` be used to have \"nice\" display on the website.\n" name = "hello" version = "1.0.0" website = "example.com" authors = ["Bob", "Alice"] licenses = "GPL-3.0-only OR MIT" maintainers = ["alejandro@mosteo.com", "bob@example.com"] maintainers-logins = ["mylogin"] tags = ["tag1", "other-tag"] [[depends-on]] libhello = "^1.0" [origin] url = "file:../../../crates/hello_1.0.0" alire-1.2.1/testsuite/fixtures/basic_index/he/hello/hello-1.0.1.toml000066400000000000000000000017021430264165500251210ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" long-description = "This is an example of long description in a multi-line string.\n\nMarkdown formating `can` be used to have \"nice\" display on the website.\n" name = "hello" version = "1.0.1" website = "example.com" authors = ["Bob", "Alice"] licenses = "GPL-3.0-only OR MIT" maintainers = ["alejandro@mosteo.com", "bob@example.com"] maintainers-logins = ["mylogin"] tags = ["tag1", "other-tag"] [[depends-on]] libhello = "^1.0" [configuration.variables] Var1={type="Boolean"} Var2={type="String", default="str"} Var3={type="Enum", values=["A", "B"], default="A"} Var4={type="Integer", default=0} Var5={type="Integer", first=-1, last=1, default=0} Var7={type="Real", default=0.0} Var6={type="Real", first=-1.0, last=1.0, default=0.0} [configuration.values] hello.Var1=true # So far it is possible for a crate to set its own var libhello.Var1=false [origin] url = "file:../../../crates/hello_1.0.1" alire-1.2.1/testsuite/fixtures/basic_index/index.toml000066400000000000000000000000201430264165500227630ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/fixtures/basic_index/li/000077500000000000000000000000001430264165500213735ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/basic_index/li/libhello/000077500000000000000000000000001430264165500231655ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/basic_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000006531430264165500263120ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [configuration.variables] Var1={type="Boolean", default=true} [gpr-externals] TEST_GPR_EXTERNAL = ["gpr_ext_A", "gpr_ext_B", "gpr_ext_C"] [gpr-set-externals] TEST_GPR_EXTERNAL = "gpr_ext_B" [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/fixtures/basic_index/ma/000077500000000000000000000000001430264165500213645ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/basic_index/ma/make/000077500000000000000000000000001430264165500223015ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/basic_index/ma/make/make-external.toml000066400000000000000000000003441430264165500257340ustar00rootroot00000000000000description = "Utility for directing compilation" name = "make" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[external]] kind = "system" origin = [] # Empty on purpose to ensure unavailable in tests alire-1.2.1/testsuite/fixtures/cases_index/000077500000000000000000000000001430264165500210045ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/cases_index/he/000077500000000000000000000000001430264165500214005ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/cases_index/he/hello/000077500000000000000000000000001430264165500225035ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/cases_index/he/hello/hello-0.9.0.toml000066400000000000000000000004501430264165500251440ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "0.9" maintainers = ["alire@developers.com"] maintainers-logins = ["mylogin"] [executables."case(os)"] "linux| windows " = ["hello"] # Without and with whitespace [origin] url = "file:../../../crates/hello_1.0.1" alire-1.2.1/testsuite/fixtures/cases_index/he/hello/hello-1.0.1.toml000066400000000000000000000030051430264165500251340ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "1.0.1" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[depends-on]] libbye = "^1.0" [depends-on."case(os)"."..."] libhello = "^1.1" [depends-on."case(os)".linux] libhello = "^1.0" [[actions."case(os)"."..."]] [[actions."case(os)".linux]] type = "post-fetch" command = ["make"] [[actions."case(os)".linux]] type = "post-build" command = ["hello"] [available."case(os)"] "..." = false linux = true [available."case(os)".windows."case(word-size)"] "..." = false bits-64 = true [executables."case(word-size)"] "..." = "bye" bits-32 = "hello32" bits-64 = "hello" [gpr-set-externals] BUILD = "debug" [gpr-set-externals."case(os)"."..."] OS = "other" [gpr-set-externals."case(os)".linux] OS = "linux" [gpr-set-externals."case(os)".macos] OS = "macos" [gpr-set-externals."case(os)".windows] OS = "windows" [gpr-set-externals."case(host-arch)"."..."] HOST_ARCH = "other" [gpr-set-externals."case(host-arch)".arm] HOST_ARCH = "arm" [gpr-set-externals."case(host-arch)".aarch64] HOST_ARCH = "aarch64" [gpr-set-externals."case(host-arch)".aarch64-be] HOST_ARCH = "aarch64-be" [gpr-set-externals."case(host-arch)".I386] HOST_ARCH = "I386" [gpr-set-externals."case(host-arch)".I686] HOST_ARCH = "I686" [gpr-set-externals."case(host-arch)".x86-64] HOST_ARCH = "x86_64" [project-files."case(word-size)"] "..." = ["bye.gpr"] bits-32 = ["hello.gpr", "hello32.gpr"] bits-64 = ["hello.gpr"] [origin] url = "file:../../../crates/hello_1.0.1" alire-1.2.1/testsuite/fixtures/cases_index/index.toml000066400000000000000000000000201430264165500230000ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/fixtures/cases_index/li/000077500000000000000000000000001430264165500214105ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/cases_index/li/libhello/000077500000000000000000000000001430264165500232025ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/cases_index/li/libhello/libhello-1.0.0-linuxonly.toml000066400000000000000000000005641430264165500303670ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0-linuxonly" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [available."case(os)"] "..." = false linux = true [available."case(os)".windows."case(word-size)"] "..." = false bits_64 = true [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/fixtures/cases_index/li/libhello/libhello-1.0.0-unavail.toml000066400000000000000000000004041430264165500277560ustar00rootroot00000000000000available = false description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0-unavail" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/fixtures/cases_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003521430264165500263230ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/fixtures/cases_index/li/libhello/libhello-external.toml000066400000000000000000000006261430264165500275150ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[external]] kind = "system" [external.origin."case(distribution)"] debian = ["libhello~1"] ubuntu = ["libhello"] [[external]] kind = "hint" [external.available."case(toolchain)"] system = false user = false # Test toolchain case expressions alire-1.2.1/testsuite/fixtures/checked_index/000077500000000000000000000000001430264165500212745ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/checked_index/index.toml000066400000000000000000000000201430264165500232700ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/fixtures/checked_index/li/000077500000000000000000000000001430264165500217005ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/checked_index/li/libhello/000077500000000000000000000000001430264165500234725ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/checked_index/li/libhello/libhello-1.0.0-git.toml000066400000000000000000000007471430264165500274040ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0-git" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "git+file:../../../crates/libhello_git" commit = "ce78e7706c9d3f97605df48d8befca5407f8d328" # hashes = ["sha512:f9d5a85fec4db46d5a2859057658c01ee4fe1ab412dab80bcbb426102b5dcb147ab7e0744e781d045e5d2b50ec3cb4f0990c8ce66e52cda37c88833d0f814500"] # Hashes no longer accepted for git origins alire-1.2.1/testsuite/fixtures/checked_index/li/libhello/libhello-1.0.0-gitbad.toml000066400000000000000000000006101430264165500300400ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0-gitbad" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "git+file:../../../crates/libhello_git" commit = "ce78e7706c9d3f97605df48d8befca5407f8d328" # hashes = ["sha512:deadbeef"] # Bad hash on purpose # Hashes no longer accepted for vcs remotes alire-1.2.1/testsuite/fixtures/checked_index/li/libhello/libhello-1.0.0-tarball.toml000066400000000000000000000006131430264165500302320ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0-tarball" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/crates/000077500000000000000000000000001430264165500200005ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/hello_1.0.0/000077500000000000000000000000001430264165500216175ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/hello_1.0.0/hello.gpr000066400000000000000000000002211430264165500234270ustar00rootroot00000000000000with "libhello.gpr"; project Hello is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Main use ("hello.adb"); end Hello; alire-1.2.1/testsuite/fixtures/crates/hello_1.0.0/src/000077500000000000000000000000001430264165500224065ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/hello_1.0.0/src/hello.adb000066400000000000000000000001161430264165500241570ustar00rootroot00000000000000with Libhello; procedure Hello is begin Libhello.Hello_World; end Hello; alire-1.2.1/testsuite/fixtures/crates/hello_1.0.1/000077500000000000000000000000001430264165500216205ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/hello_1.0.1/hello.gpr000066400000000000000000000002211430264165500234300ustar00rootroot00000000000000with "libhello.gpr"; project Hello is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Main use ("hello.adb"); end Hello; alire-1.2.1/testsuite/fixtures/crates/hello_1.0.1/src/000077500000000000000000000000001430264165500224075ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/hello_1.0.1/src/hello.adb000066400000000000000000000001161430264165500241600ustar00rootroot00000000000000with Libhello; procedure Hello is begin Libhello.Hello_World; end Hello; alire-1.2.1/testsuite/fixtures/crates/libfoo_git/000077500000000000000000000000001430264165500221155ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/HEAD000066400000000000000000000000271430264165500225400ustar00rootroot00000000000000ref: refs/heads/master alire-1.2.1/testsuite/fixtures/crates/libfoo_git/config000066400000000000000000000001021430264165500232760ustar00rootroot00000000000000[core] repositoryformatversion = 0 filemode = true bare = true alire-1.2.1/testsuite/fixtures/crates/libfoo_git/description000066400000000000000000000001111430264165500243540ustar00rootroot00000000000000Unnamed repository; edit this file 'description' to name the repository. alire-1.2.1/testsuite/fixtures/crates/libfoo_git/info/000077500000000000000000000000001430264165500230505ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/info/exclude000066400000000000000000000003601430264165500244230ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~ alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/000077500000000000000000000000001430264165500235465ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/07/000077500000000000000000000000001430264165500237745ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/07/2d593793eda4efbb0af13f3fa422d72f5492d3000066400000000000000000000000221430264165500312600ustar00rootroot00000000000000xKÊÉOR0f8¼ $aalire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/78/000077500000000000000000000000001430264165500240045ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/78/981922613b2afb6025042ff6bd878ac1994e85000066400000000000000000000000211430264165500307240ustar00rootroot00000000000000xKÊÉOR0bHäd]alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/9a/000077500000000000000000000000001430264165500240575ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/9a/6aa1471db1a0c821570db875b12f08653f623c000066400000000000000000000002111430264165500310210ustar00rootroot00000000000000x¥Í½ @agžâî& Z.Icttpñ ø¹DL„Òŧ7©àv¦ïøšsê Œ<õFQÅà̈!JÇɈfv)ƒÚ“–#·“bvï¯Úà¶ÒÛ–Ð*<xÔ­S…Åæ#®{IÛÚ. &Í*=#œùÈ9óǸÓ»—Ô“]ág±/žÔ?µalire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/9a/f665c489b9079ead6193d01db502f1a074e36a000066400000000000000000000000631430264165500311330ustar00rootroot00000000000000x+)JMU0µ`040031Q(`x6÷ÑìM¯9{wk®+ºqèIOðD¨d!VI€Íalire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/9d/000077500000000000000000000000001430264165500240625ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/9d/dda32bbbf117dcf2314cb8c23f127c735e5863000066400000000000000000000002171430264165500313400ustar00rootroot00000000000000x•Í=Â0 @aæœÂ;Reò'!# 7°j#‚ÚFJÓ…ÓS•°½é{}ÇÜ€’ݵª Ï䂈DDQOÄè¼ø”„­Å#KTKlCO†—ö*®ƒ¾y’ZàÑÁ½ÌM œxÜâ²LùõÓù äR<aDÓoã¦~e¬w+A+anSn™øYæ Dé?5alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/cb/000077500000000000000000000000001430264165500241325ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/cb/514eabb745aff2b9a515cce4c4daaaac56edaf000066400000000000000000000001171430264165500321210ustar00rootroot00000000000000x+)JMU°0c040031Q¨`x6÷ÑìM¯9{wk®+ºqèIOðD P¨d˜õ-õHçNöyk'_ÝÊôqAÉã,¨Æ*¬Tß*£alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/e6/000077500000000000000000000000001430264165500240605ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391000066400000000000000000000000171430264165500313050ustar00rootroot00000000000000xKÊÉOR0` °ðalire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/f4/000077500000000000000000000000001430264165500240575ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/f4/fdb928df3b0be3f896b18be4987ce7338f0a54000066400000000000000000000001771430264165500314060ustar00rootroot00000000000000x+)JMU044c040031QHd¨˜!©”h­õ;A•EÿÛÞö®ƒ3ýZM €@!‰át ßêí®ë?í\*zæÉ‘[«Ö„½]Õ˜Ìðlî£Ù›.^söîÖ\WuãГžà‰PÉà Øu#Í'¿]ò~7×G{û%J×õC&]£4üalire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/f9/000077500000000000000000000000001430264165500240645ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/objects/f9/57ddd800de611a056d699da3304ad8e31a37c1000066400000000000000000000001431430264165500312010ustar00rootroot00000000000000x+)JMU°0c040031QHd¨˜!©”h­õ;A•EÿÛÞö®ƒ3ýZM €@!‰át ßêí®ë?í\*zæÉ‘[«Ö„½]Õ˜Ìðlî£Ù›.^söîÖ\WuãГžà‰‰9(alire-1.2.1/testsuite/fixtures/crates/libfoo_git/packed-refs000066400000000000000000000001511430264165500242210ustar00rootroot00000000000000# pack-refs with: peeled fully-peeled sorted 9a6aa1471db1a0c821570db875b12f08653f623c refs/heads/master alire-1.2.1/testsuite/fixtures/crates/libfoo_git/refs/000077500000000000000000000000001430264165500230545ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/refs/heads/000077500000000000000000000000001430264165500241405ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/refs/heads/.emptydir000066400000000000000000000000001430264165500257640ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libfoo_git/refs/heads/master000066400000000000000000000000511430264165500253520ustar00rootroot000000000000009ddda32bbbf117dcf2314cb8c23f127c735e5863 alire-1.2.1/testsuite/fixtures/crates/libhello_1.0.0.tgz000066400000000000000000000006631430264165500230410ustar00rootroot00000000000000‹kW ]í•MOƒ@†9÷WŒœ4Q\>–z2ñ IcM4ñHøX[*B³@jÿ½»H»Ö61ôC绳³»áeæMâ`Â’$óLƒäZÛDЧT>Í>%«ÏÍ´©i;¶íXŽFL‹X®t/·Q(óÂçÚÔO³mëvÅ)ɺþÍÐÏxggH]ÇùV˱ýŠрtvƒ-üsýg<›²°€a-<Äy¯¯‡§¬ä!óncžC™38×sêƒ&> dªŒWa= ¦ú Í;rŸ/¼ÿ-ãÕú@]Ðæ‹ŸOæ³4j¯#†ÇþB¥þ…ÀÝ{Àú¿kRìÿ‡`ƒþ­øQÐÉ»ú¿M]EJ\ûÿ!˜ÇÅn"ßxf…w? wæ‡oþ˜AE H_¸RYNÂ]õ½d<‰ ™TWÊYá7!‹JÎÖ2ÄæP!}`í6b.`ã8­ãeá ãTzQ• s¹ÁYíJÒ:Vö­Í$iÍäØ_ûôØ^ÿy'gìªÒÿRÿ&Áú?M±«u¾±N±žAAAAAANžOxïU@(alire-1.2.1/testsuite/fixtures/crates/libhello_1.0.0/000077500000000000000000000000001430264165500223065ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libhello_1.0.0/libhello.gpr000066400000000000000000000002421430264165500246100ustar00rootroot00000000000000project Libhello is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Library_Name use "hello"; for Library_Dir use "lib"; end Libhello; alire-1.2.1/testsuite/fixtures/crates/libhello_1.0.0/src/000077500000000000000000000000001430264165500230755ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libhello_1.0.0/src/libhello.adb000066400000000000000000000003561430264165500253430ustar00rootroot00000000000000with Ada.Text_IO; package body libhello is ----------------- -- Hello_World -- ----------------- procedure Hello_World is use Ada.Text_IO; begin Put_Line ("Hello, world!"); end Hello_World; end libhello; alire-1.2.1/testsuite/fixtures/crates/libhello_1.0.0/src/libhello.ads000066400000000000000000000000761430264165500253630ustar00rootroot00000000000000package libhello is procedure Hello_World; end libhello; alire-1.2.1/testsuite/fixtures/crates/libhello_git/000077500000000000000000000000001430264165500224355ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/noop_1.0-default.tgz000066400000000000000000000006641430264165500235070ustar00rootroot00000000000000‹û¡Ý]í•Ënƒ0EYç+F¬)´<,²k›e›E¥n+cê„ÚÈ€ÒϯM ¯>’TI¤ªs`tÇã±. ) 'eSRçÕu\M†æíÅ¡»ùî°¼ ŒâÀwã@Çy¾çG„gªg‹º¬ˆ°fDÈŸâöé±é¿ù¸Î uâ5ŒÁÑpø­ÿ±¬ü†Æÿ òB Ü×ñ%ÿÜÿBÉ£ÇpLÿ_ž?6çûÿùùäw2O¸Æ¾þýöÿK û?ei­ØêHXÆ…i/¢ÎóÑoû ‚ ‚ ‚ ‚ ‚ ‚ ‚ rY>~‚h(alire-1.2.1/testsuite/fixtures/crates/noop_1.0-multi.tgz000066400000000000000000000007301430264165500232070ustar00rootroot00000000000000‹y¢Ý]í–MOÃ0 †{Þ¯°z‰A“~vã㸢4 %[—Ti+øù$¥ÛÊ ¤mæç°f²ã8r^'JëjÐ?Ývجÿx­ÿG„†¨ÿ}ð^ÿô‹@±üCúïîþ¢2[_c“þÓhðþ‹ˆÕŠúßVÿSÁ›åíouÿ¨ ÜéÖpñp)M m-àÈ··ƒ<éÍ·™›äÌÕ×ÙÔ_Ø®^_Y2©––k&UmñÎôOÀ_Þ9.¾ë;ã3V8oe™ ãÒ‚Ž.³gÙð'QÛ ,gþqp< \¬qñ–$¸®ÕÏôBÏ+Y~'jo½P¬¹go+Øás?ì~o©²ôíV®º=ÚSÆgc»Ÿ 2\$³¶o©¾½í«z¸án¢ †6AAAAA9d^éi†¡(alire-1.2.1/testsuite/fixtures/crates/noop_1.0-nondef.tgz000066400000000000000000000006701430264165500233310ustar00rootroot00000000000000‹@¢Ý]í•=oÂ0†3çWœ2©¡ù$[[Æ–¡R×ÊqLjHíÈID~í E¢P ¨*î°ÑkŸÏz}!eé )26»³Î„§IâØŒ~{ýqå‡ñ( ß‹G–ç·2ÄçJ¨OSÕDXs"äOëéÿÑó¿Rô,oàWþ‰ö?ˆÃý¿»þ›ÿÁdé Ï0¢h¿ÿúmlý7õ‘owÂöråþ—JR–5ŠÁ³qxe§,çÂÑÅØf"[icû¯“ENN¿þÍ|˜—êÔgªÿ$ˆ¶õšþFzÀú¿ºþçŒÖm…›â×u?“ ^d£({{䪂¦bpãèƒ3wò45›ŒÜªŽLçÎZ›|2ºUR.6Êᢋ¶ù̘˜¦×”„.HÎà¾áEÆ”IZÚl–¼¦ï¬ÒIFœAÄ{Î-8n¾J L§êöú ?J^µ“ÁDÏ©_Éê=]vÓöw8·›µÝ‚íRÙÎfúeÑ…« ‹^†ëdvîÍÅÑמTý ·u°uŸÆ6 ‚ ‚ ‚ ‚ ‚ ‚ ×ʇO´³(alire-1.2.1/testsuite/fixtures/git_index/000077500000000000000000000000001430264165500204715ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/git_index/index.toml000066400000000000000000000000201430264165500224650ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/fixtures/git_index/li/000077500000000000000000000000001430264165500210755ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/git_index/li/libfoo/000077500000000000000000000000001430264165500223475ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/git_index/li/libfoo/libfoo-1.0.0-git.toml000066400000000000000000000004321430264165500257300ustar00rootroot00000000000000description = "Custom repo to check proper retrieval of local git crates" name = "libfoo" version = "1.0.0-git" maintainers = ["some@one.com"] maintainers-logins = ["mylogin"] [origin] url = "git+file:../../../crates/libfoo_git" commit = "9ddda32bbbf117dcf2314cb8c23f127c735e5863" alire-1.2.1/testsuite/fixtures/native_index/000077500000000000000000000000001430264165500211745ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/native_index/index.toml000066400000000000000000000000201430264165500231700ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/fixtures/native_index/li/000077500000000000000000000000001430264165500216005ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/native_index/li/libhello/000077500000000000000000000000001430264165500233725ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/native_index/li/libhello/libhello-0.9.0-test-unav-native.toml000066400000000000000000000004261430264165500317350ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "0.9.0-test-unav-native" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[depends-on]] make = "*" [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/fixtures/native_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003521430264165500265130ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/fixtures/native_index/ma/000077500000000000000000000000001430264165500215715ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/native_index/ma/make/000077500000000000000000000000001430264165500225065ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/native_index/ma/make/make-external.toml000066400000000000000000000003551430264165500261430ustar00rootroot00000000000000description = "Utility for directing compilation" name = "make" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[external]] kind = "system" origin = [] # No package name since we require it unavailable in tests alire-1.2.1/testsuite/fixtures/run_index/000077500000000000000000000000001430264165500205125ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/run_index/index.toml000066400000000000000000000000201430264165500225060ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/fixtures/run_index/no/000077500000000000000000000000001430264165500211265ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/run_index/no/noop/000077500000000000000000000000001430264165500221015ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/run_index/no/noop/noop-1.0.0-default.toml000066400000000000000000000005221430264165500260240ustar00rootroot00000000000000description = "Do nothing" name = "noop" version = "1.0.0-default" maintainers = ["mr@lazy.com"] maintainers-logins = ["mrlazy"] [origin] url = "file:../../../crates/noop_1.0-default.tgz" hashes = ["sha512:de676fbda9f16ba98fe1adc80e20dbd9b98a86352267825b55f1d719570adc0f92f1be2e96fd3df06aac4f6b5fee8686695e315be370cabe482edefc5a0570c5"] alire-1.2.1/testsuite/fixtures/run_index/no/noop/noop-1.0.0-multi.toml000066400000000000000000000005561430264165500255410ustar00rootroot00000000000000description = "Do nothing" name = "noop" version = "1.0.0-multi" executables = ["noop", "noop2"] maintainers = ["mr@lazy.com"] maintainers-logins = ["mrlazy"] [origin] url = "file:../../../crates/noop_1.0-multi.tgz" hashes = ["sha512:ce2fc754c166ead10e1fcc7bbd483cff0f95bf527ee78b443510f692b5f1cb95b21b48d65ee1dc6555dcc6bfd04e607e3a7cf510ac056cc209308aa4ec0be7cc"] alire-1.2.1/testsuite/fixtures/run_index/no/noop/noop-1.0.0-nondef.toml000066400000000000000000000005501430264165500256520ustar00rootroot00000000000000description = "Do nothing" name = "noop" version = "1.0.0-nondef" executables = ["noop2"] maintainers = ["mr@lazy.com"] maintainers-logins = ["mrlazy"] [origin] url = "file:../../../crates/noop_1.0-nondef.tgz" hashes = ["sha512:a5807a3f7ea5bb9bc99f37e0ff23e13526fc6c928c7d90a75c0aa6f3ba9cc964978beedd4d5f890b8c82d969ec159315b4bb66dba18e1c559b2fa0bd71c66f2b"] alire-1.2.1/testsuite/fixtures/solver_index/000077500000000000000000000000001430264165500212205ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/he/000077500000000000000000000000001430264165500216145ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/he/hello/000077500000000000000000000000001430264165500227175ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/he/hello/hello-1.0.0.toml000066400000000000000000000004531430264165500253530ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "1.0.0" website = "example.com" authors = ["Bob", "Alice"] licenses = "GPL-3.0-only OR MIT" maintainers = ["bob@example.com"] maintainers-logins = ["mylogin"] [[depends-on]] libhello = "^1.0" [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/he/hello/hello-1.0.1.toml000066400000000000000000000005051430264165500253520ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "1.0.1" website = "example.com" authors = ["Bob", "Alice"] licenses = "GPL-3.0-only OR MIT" maintainers = ["bob@example.com"] maintainers-logins = ["mylogin"] # With plain dependencies [[depends-on]] libhello = "^1.0" [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/he/hello/hello-2.0.0.toml000066400000000000000000000005451430264165500253560ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "2.0.0" website = "example.com" authors = ["Bob", "Alice"] licenses = "GPL-3.0-only OR MIT" maintainers = ["bob@example.com"] maintainers-logins = ["mylogin"] # With regular and unavailable external (hint) [[depends-on]] libhello = "^2.0" make = "*" [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/he/hello/hello-3.0.0.toml000066400000000000000000000005071430264165500253550ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "3.0.0" website = "example.com" authors = ["Bob", "Alice"] licenses = "GPL-3.0-only OR MIT" maintainers = ["bob@example.com"] maintainers-logins = ["mylogin"] # With missing dependencies [[depends-on]] libhello = "^3.0" [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/he/hello/hello-4.0.0.toml000066400000000000000000000005451430264165500253600ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "4.0.0" website = "example.com" authors = ["Bob", "Alice"] licenses = "GPL-3.0-only OR MIT" maintainers = ["bob@example.com"] maintainers-logins = ["mylogin"] # With missing dependencies + missing external [[depends-on]] libhello = "^4.0" make = "*" [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/index.toml000066400000000000000000000000201430264165500232140ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/fixtures/solver_index/li/000077500000000000000000000000001430264165500216245ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/li/libhello/000077500000000000000000000000001430264165500234165ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003051430264165500265350ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.0" maintainers = ["john@doe.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/li/libhello/libhello-1.0.1.toml000066400000000000000000000003051430264165500265360ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.0.1" maintainers = ["john@doe.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/li/libhello/libhello-1.1.0.toml000066400000000000000000000003051430264165500265360ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "1.1.0" maintainers = ["john@doe.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/li/libhello/libhello-2.0.0.toml000066400000000000000000000003051430264165500265360ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project support library" name = "libhello" version = "2.0.0" maintainers = ["john@doe.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/fixtures/solver_index/ma/000077500000000000000000000000001430264165500216155ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/ma/make/000077500000000000000000000000001430264165500225325ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/ma/make/make-external.toml000066400000000000000000000003551430264165500261670ustar00rootroot00000000000000description = "Utility for directing compilation" name = "make" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[external]] kind = "system" origin = [] # No package name since we require it unavailable in tests alire-1.2.1/testsuite/fixtures/solver_index/su/000077500000000000000000000000001430264165500216475ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/su/superhello/000077500000000000000000000000001430264165500240315ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/solver_index/su/superhello/superhello-1.0.0.toml000066400000000000000000000004271430264165500275450ustar00rootroot00000000000000description = "A better hello" name = "superhello" version = "1.0.0" website = "example.com" authors = ["Bob", "Alice"] licenses = "GPL-3.0-only OR MIT" maintainers = ["bob@example.com"] maintainers-logins = ["mylogin"] [[depends-on]] libhello = "~1.0" [origin] url = "file:." alire-1.2.1/testsuite/fixtures/toolchain_index/000077500000000000000000000000001430264165500216665ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/000077500000000000000000000000001430264165500222725ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_conflict/000077500000000000000000000000001430264165500252515ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_conflict/crate_conflict-1.2.3.toml000066400000000000000000000006541430264165500315710ustar00rootroot00000000000000description = "A crate that conflicts with other crates" name = "crate_conflict" version = "1.2.3" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[forbids]] crate_virtual = "*" crate_lone = "*" [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_equiv/000077500000000000000000000000001430264165500246015ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_equiv/crate_equiv-2.0.0.toml000066400000000000000000000006451430264165500304450ustar00rootroot00000000000000description = "A crate that supplies another crate" name = "crate_equiv" version = "2.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["crate_virtual=1.0", "crate_lone=1.0"] [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_lone/000077500000000000000000000000001430264165500244055ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_lone/crate_lone-1.0.0.toml000066400000000000000000000006111430264165500300450ustar00rootroot00000000000000description = "A crate" name = "crate_lone" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["crate_virtual=1.0"] available = false [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_lone/crate_lone-2.0.0.toml000066400000000000000000000005661430264165500300570ustar00rootroot00000000000000description = "A crate" name = "crate_lone" version = "2.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["crate_virtual=1.0"] [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_real/000077500000000000000000000000001430264165500243735ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_real/crate_real-1.0.0.toml000066400000000000000000000005251430264165500300250ustar00rootroot00000000000000description = "A crate" name = "crate_real" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_subst/000077500000000000000000000000001430264165500246105ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_subst/crate_subst-1.0.0.toml000066400000000000000000000010771430264165500304620ustar00rootroot00000000000000description = "A crate that replaces another, forbidding other implementations" name = "crate_subst" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = [ "crate_real=1.0.0" ] [[forbids]] crate_real = "*" # This forbids means that no other crate should solve for crate_lone, as # crate_subst is providing it already. [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_virt_1/000077500000000000000000000000001430264165500246545ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_virt_1/crate_virt_1-2.0.0.toml000066400000000000000000000006461430264165500305740ustar00rootroot00000000000000description = "A crate that supplies another crate" name = "crate_virt_1" version = "2.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["crate_virtual=1.0", "crate_lone=1.0"] [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_virt_2/000077500000000000000000000000001430264165500246555ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/cr/crate_virt_2/crate_virt_2-1.0.0.toml000066400000000000000000000006241430264165500305710ustar00rootroot00000000000000description = "A crate that supplies another crate" name = "crate_virt_2" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["crate_virtual=1.0"] [origin] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/gn/000077500000000000000000000000001430264165500222725ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_cross_1/000077500000000000000000000000001430264165500246545ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_cross_1/gnat_cross_1-1.0.0.toml000066400000000000000000000007051430264165500305670ustar00rootroot00000000000000description = "Fake GNAT cross-target crate (1)" name = "gnat_cross_1" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["gnat=1.0"] # Test dynamic expression, but for all OSes [origin."case(os)"."..."] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_cross_1/gnat_cross_1-9999.0.0.toml000066400000000000000000000007131430264165500310510ustar00rootroot00000000000000description = "Fake GNAT cross-target crate (1)" name = "gnat_cross_1" version = "9999.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["gnat=9999.0"] # Test dynamic expression, but for all OSes [origin."case(os)"."..."] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_cross_2/000077500000000000000000000000001430264165500246555ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_cross_2/gnat_cross_2-1.0.0.toml000066400000000000000000000006761430264165500306000ustar00rootroot00000000000000description = "Fake GNAT cross crate (2)" name = "gnat_cross_2" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["gnat=1.0"] # Test dynamic expression, but for all OSes [origin."case(os)"."..."] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_external/000077500000000000000000000000001430264165500251255ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_external/gnat_external-external.toml000066400000000000000000000005471430264165500325030ustar00rootroot00000000000000description = "GNAT is a compiler for the Ada programming language" name = "gnat_external" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mosteo"] [[external]] kind = "version-output" # We look for make instead that should be always installed. version-command = ["make", "--version"] version-regexp = ".*Make ([\\d\\.]+).*" provides = "gnat" alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_native/000077500000000000000000000000001430264165500245715ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_native/gnat_native-7777.0.0.toml000066400000000000000000000007001430264165500306670ustar00rootroot00000000000000description = "Fake GNAT native crate" name = "gnat_native" version = "7777.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["gnat=7777.0"] # Test dynamic expression, but for all OSes [origin."case(os)"."..."] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/gn/gnat_native/gnat_native-8888.0.0.toml000066400000000000000000000012151430264165500306750ustar00rootroot00000000000000description = "Fake GNAT native crate" name = "gnat_native" version = "8888.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] provides = ["gnat=8888.0"] # Although the compiler is fake, we use this path in some tests environment.'case(os)'.'windows'.TEST_PATH.append = '${CRATE_ROOT}\bin' environment.'case(os)'.'...'.TEST_PATH.append = '${CRATE_ROOT}/bin' # Test dynamic expression, but for all OSes [origin."case(os)"."..."] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/gp/000077500000000000000000000000001430264165500222745ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/gp/gprbuild/000077500000000000000000000000001430264165500241045ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/toolchain_index/gp/gprbuild/gprbuild-8888.0.0.toml000066400000000000000000000006461430264165500275300ustar00rootroot00000000000000description = "Fake gprbuild crate" name = "gprbuild" version = "8888.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] # Using this conditional origin marks it as binary [origin."case(os)"."..."] url = "file:../../../crates/libhello_1.0.0.tgz" hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] alire-1.2.1/testsuite/fixtures/toolchain_index/gp/gprbuild/gprbuild-external.toml000066400000000000000000000004641430264165500304350ustar00rootroot00000000000000description = "Fake gprbuild external" name = "gprbuild" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mosteo"] [[external]] kind = "version-output" # We look for make instead, that should be always installed. version-command = ["make", "--version"] version-regexp = ".*Make ([\\d\\.]+).*" alire-1.2.1/testsuite/fixtures/toolchain_index/index.toml000066400000000000000000000000201430264165500236620ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/run.py000077500000000000000000000015651430264165500160360ustar00rootroot00000000000000#! /usr/bin/env python """ e3.testsuite-based testsuite for Alire/ALR. Just execute this script to run the testsuite. It requires a Python2 interpreter with the e3-core and e3-testsuite packages (from PyPI) installed. """ from __future__ import absolute_import, print_function import sys import os.path import e3.testsuite import e3.testsuite.driver from e3.testsuite.result import TestStatus from drivers.python_script import PythonScriptDriver class Testsuite(e3.testsuite.Testsuite): tests_subdir = 'tests' test_driver_map = {'python-script': PythonScriptDriver} def set_up(self): super().set_up() # Some tests rely on an initially empty GPR_PROJECT_PATH variable os.environ.pop('GPR_PROJECT_PATH', None) if __name__ == '__main__': suite = Testsuite() sys.exit(suite.testsuite_main(sys.argv[1:] + ["--failure-exit-code=1"])) alire-1.2.1/testsuite/skels/000077500000000000000000000000001430264165500157675ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/global-index/000077500000000000000000000000001430264165500203345ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/global-index/test.py000066400000000000000000000002711430264165500216650ustar00rootroot00000000000000""" A test that uses an index in testsuite/fixtures """ from drivers.alr import run_alr # from drivers.asserts import assert_eq, assert_match p = run_alr('clean') print('SUCCESS') alire-1.2.1/testsuite/skels/global-index/test.yaml000066400000000000000000000000631430264165500221760ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/skels/local-index/000077500000000000000000000000001430264165500201665ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/local-index/my_index/000077500000000000000000000000001430264165500220025ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/local-index/my_index/crates/000077500000000000000000000000001430264165500232635ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/local-index/my_index/crates/crate/000077500000000000000000000000001430264165500243615ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/local-index/my_index/crates/crate/.emptydir000066400000000000000000000000001430264165500262050ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/local-index/my_index/index/000077500000000000000000000000001430264165500231115ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/local-index/my_index/index/cr/000077500000000000000000000000001430264165500235155ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/local-index/my_index/index/cr/crate/000077500000000000000000000000001430264165500246135ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/local-index/my_index/index/cr/crate/crate-1.0.0.toml000066400000000000000000000002661430264165500272440ustar00rootroot00000000000000description = "Sample crate" name = "crate" version = "1.0.0" licenses = [] maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] url = "file:../../../crates/crate" alire-1.2.1/testsuite/skels/local-index/my_index/index/index.toml000066400000000000000000000000201430264165500251050ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/skels/local-index/test.py000066400000000000000000000002431430264165500215160ustar00rootroot00000000000000""" A test that uses its own local index """ from drivers.alr import run_alr # from drivers.asserts import assert_eq, assert_match run_alr() print('SUCCESS') alire-1.2.1/testsuite/skels/local-index/test.yaml000066400000000000000000000001101430264165500220210ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/skels/no-index/000077500000000000000000000000001430264165500175105ustar00rootroot00000000000000alire-1.2.1/testsuite/skels/no-index/test.py000066400000000000000000000002361430264165500210420ustar00rootroot00000000000000""" A test that requires no indexes """ from drivers.alr import run_alr # from drivers.asserts import assert_eq, assert_match run_alr() print('SUCCESS') alire-1.2.1/testsuite/skels/no-index/test.yaml000066400000000000000000000000261430264165500213510ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/000077500000000000000000000000001430264165500160105ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/000077500000000000000000000000001430264165500172655ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/list/000077500000000000000000000000001430264165500202405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/list/my_index/000077500000000000000000000000001430264165500220545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/list/my_index/index.toml000066400000000000000000000000201430264165500240500ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/action/list/my_index/ma/000077500000000000000000000000001430264165500224515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/list/my_index/ma/main/000077500000000000000000000000001430264165500233755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/list/my_index/ma/main/main-1.0.0.toml000066400000000000000000000003771430264165500256570ustar00rootroot00000000000000description = "Main program" name = "main" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[actions]] type = "post-fetch" command = ["echo", "POST-FETCH MAIN"] [origin] url = "file:." alire-1.2.1/testsuite/tests/action/list/test.py000066400000000000000000000015241430264165500215730ustar00rootroot00000000000000""" Test listing of actions with `alr action` """ import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match from glob import glob expected_output = """main=1.0.0: Post_Fetch run: ${CRATE_DIR}/./echo POST-FETCH MAIN """ # First test, list action in a root crate run_alr("get", "main") os.chdir(glob("main*")[0]) p = run_alr("action") assert_eq(expected_output, p.out) # Second test, check that action in dependency is not listed by default os.chdir("..") init_local_crate() alr_with("main") p = run_alr("action") assert_eq("No actions.\n", p.out) # Third test, check that action in dependency is listed with --recursive, -r p1 = run_alr("action", "--recursive") p2 = run_alr("action", "-r") assert_eq(expected_output, p1.out) assert_eq(expected_output, p2.out) print('SUCCESS') alire-1.2.1/testsuite/tests/action/list/test.yaml000066400000000000000000000001101430264165500220730ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/action/post-fetch-once/000077500000000000000000000000001430264165500222635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/post-fetch-once/my_index/000077500000000000000000000000001430264165500240775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/post-fetch-once/my_index/index.toml000066400000000000000000000000201430264165500260730ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/action/post-fetch-once/my_index/ma/000077500000000000000000000000001430264165500244745ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/post-fetch-once/my_index/ma/main/000077500000000000000000000000001430264165500254205ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/post-fetch-once/my_index/ma/main/main-1.0.0.toml000066400000000000000000000004041430264165500276710ustar00rootroot00000000000000description = "Main program" name = "main" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[actions]] type = "post-fetch" command = ["echo", "POST-FETCH TRIGGERED"] [origin] url = "file:." alire-1.2.1/testsuite/tests/action/post-fetch-once/test.py000066400000000000000000000006301430264165500236130ustar00rootroot00000000000000""" Test that post-fetch actions are invoked only once for the root crate during an `alr get` """ from drivers.alr import run_alr # Should silently retrieve everything p = run_alr('get', 'main') checks = 0 for line in p.out.splitlines(): if "POST-FETCH TRIGGERED" in line: checks += 1 assert checks == 1, \ f"Expected matching once but got: {checks} in output: {p.out}" print('SUCCESS') alire-1.2.1/testsuite/tests/action/post-fetch-once/test.yaml000066400000000000000000000001101430264165500241160ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/action/trigger/000077500000000000000000000000001430264165500207305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/trigger/my_index/000077500000000000000000000000001430264165500225445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/trigger/my_index/index.toml000066400000000000000000000000201430264165500245400ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/action/trigger/my_index/ma/000077500000000000000000000000001430264165500231415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/trigger/my_index/ma/main/000077500000000000000000000000001430264165500240655ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/action/trigger/my_index/ma/main/main-1.0.0.toml000066400000000000000000000003771430264165500263470ustar00rootroot00000000000000description = "Main program" name = "main" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[actions]] type = "post-fetch" command = ["echo", "POST-FETCH MAIN"] [origin] url = "file:." alire-1.2.1/testsuite/tests/action/trigger/test.py000066400000000000000000000020071430264165500222600ustar00rootroot00000000000000""" Test triggering of actions with `alr action` """ import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match from glob import glob expected_output = "POST-FETCH MAIN\n" # Test trigger action in a root crate run_alr("get", "main") os.chdir(glob("main*")[0]) p = run_alr("action", "post-fetch") assert_eq(expected_output, p.out) # Test trigger of undefined action p = run_alr("action", "post-build") assert_eq("No actions to run.\n", p.out) # Test trigger of non-existent action p = run_alr("action", "made-up", complain_on_error=False) assert_eq("ERROR: Invalid action: made-up\n", p.out) # Test that action in dependency is not triggered by default os.chdir("..") init_local_crate() alr_with("main") p = run_alr("action", "post-fetch") assert_eq("No actions to run.\n", p.out) # Third test, check that action in dependency is listed with --recursive, -r p = run_alr("action", "post-fetch", "--recursive") assert_eq(expected_output, p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/action/trigger/test.yaml000066400000000000000000000001101430264165500225630ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/alias/000077500000000000000000000000001430264165500171015ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/alias/basic/000077500000000000000000000000001430264165500201625ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/alias/basic/test.py000066400000000000000000000010601430264165500215100ustar00rootroot00000000000000""" Basic check of alias definition in configuration """ from glob import glob import os from drivers.alr import run_alr from drivers.asserts import assert_match import re # Get the "hello" project and enter its directory run_alr('get', 'hello') os.chdir(glob('hello*')[0]) # Define an alias locally run_alr('config', '--set', 'alias.my_alias', 'exec -- echo Test an alias') # Use the alias p = run_alr('my_alias', quiet=False) # -q will hide the output of the exec command assert_match('Test an alias', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/alias/basic/test.yaml000066400000000000000000000000631430264165500220240ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/build/000077500000000000000000000000001430264165500171075ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/build/incremental/000077500000000000000000000000001430264165500214105ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/build/incremental/test.py000066400000000000000000000034361430264165500227470ustar00rootroot00000000000000""" Test that a tool built by a dependency is available to a dependent crate """ from drivers.alr import run_alr, init_local_crate, alr_with, alr_manifest from drivers.alr import add_action from os import chdir from os.path import join from shutil import rmtree, which # We test with a locally pinned dependency, which should make no difference as # it is a regular release in the eyes of the build process init_local_crate("root") init_local_crate("depended", binary=True, enter=False) alr_with("depended", path="depended") # Add a pre-build action to the root crate that attempts to run bin/depended add_action("pre-build", ["depended/bin/depended"]) run_alr("build") # Now, add the executable to the path in the depended crate, and an action that # uses only the executable name # First, ensure that a same-name executable isn't in the environment by some # bizarre chance assert which("depended") is None, "Unexpected 'depended' command in PATH" chdir("depended") with open(alr_manifest(), "a") as manifest: manifest.writelines(["[environment]\n", "PATH.append = '${CRATE_ROOT}/bin'\n"]) chdir("..") # Clean up a bit just in case rmtree("alire") rmtree("depended/alire") add_action("pre-build", ["depended"]) # Finally verify that a non-existant executable is actually failing. We do this # using "root" as an intermediate crate, to ensure that "pre-build" is also # being run for all dependencies and not only the root one. add_action("pre-build", ["fake_alr_test_exec"]) init_local_crate("root_test") alr_with("root", path="..") p = run_alr("build", complain_on_error=False) assert p.status != 0, "Command should have failed" assert 'Command ["fake_alr_test_exec"] exited with code' in p.out, \ "Output does not contain expected error, but: " + p.out print('SUCCESS') alire-1.2.1/testsuite/tests/build/incremental/test.yaml000066400000000000000000000001121430264165500232450ustar00rootroot00000000000000driver: python-script indexes: basic_index: in_fixtures: true alire-1.2.1/testsuite/tests/build_profile/000077500000000000000000000000001430264165500206275ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/build_profile/alr_build_switches/000077500000000000000000000000001430264165500244755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/build_profile/alr_build_switches/test.py000066400000000000000000000033621430264165500260320ustar00rootroot00000000000000""" Check `alr build` switches to control root profile """ import os from drivers.alr import run_alr, init_local_crate, alr_with, alr_manifest from drivers.helpers import content_of from drivers.asserts import assert_match init_local_crate('lib_1', binary=False, enter=False) init_local_crate('bin_1', binary=True, enter=True) run_alr('update') def check_config(path, profile): conf = content_of(path) assert_match('.*Build_Profile : Build_Profile_Kind := "%s"' % profile, conf) lib1_config = "../lib_1/config/lib_1_config.gpr" bin_config = "config/bin_1_config.gpr" mtime = os.path.getmtime(bin_config) def check_config_changed(): global mtime last_mtime = mtime mtime = os.path.getmtime(bin_config) assert last_mtime != mtime, "config file did not change" def check_config_not_changed(): global mtime last_mtime = mtime mtime = os.path.getmtime(bin_config) assert last_mtime == mtime, "config file did not change" # Check default profiles for root and dependency check_config(bin_config, 'development') # Check that the project builds run_alr('build') # Build in validation mode run_alr('build', '--validation') check_config_changed() check_config(bin_config, 'validation') # Build in validation mode run_alr('build', '--development') check_config_changed() check_config(bin_config, 'development') # Build in release mode run_alr('build', '--release') check_config_changed() check_config(bin_config, 'release') # Alr with will re-generate the crate config and default to DEVELOPMENT alr_with('lib_1', path='../lib_1') check_config_changed() check_config(bin_config, 'development') # Build with default profile, the config should not change run_alr('build') check_config_not_changed() print('SUCCESS') alire-1.2.1/testsuite/tests/build_profile/alr_build_switches/test.yaml000066400000000000000000000000261430264165500263360ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/build_profile/custom_profiles/000077500000000000000000000000001430264165500240445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/build_profile/custom_profiles/test.py000066400000000000000000000041321430264165500253750ustar00rootroot00000000000000""" Check customization of profiles """ from drivers.alr import run_alr, init_local_crate, alr_with, alr_manifest from drivers.helpers import content_of from drivers.asserts import assert_match init_local_crate('lib_1', binary=False, enter=False) init_local_crate('lib_2', binary=False, enter=False) init_local_crate('bin_1', binary=True, enter=True) alr_with('lib_1', path='../lib_1') alr_with('lib_2', path='../lib_2') run_alr('update') def check_config(path, profile, expected_switches=[]): conf = content_of(path) assert_match('.*Build_Profile : Build_Profile_Kind := "%s"' % profile, conf) for sw in expected_switches: assert_match('.*"%s"' % sw,conf) lib1_config = '../lib_1/config/lib_1_config.gpr' lib2_config = '../lib_2/config/lib_2_config.gpr' bin_config = 'config/bin_1_config.gpr' # Check default profiles for root and dependency check_config(lib1_config, 'release', ['-O3', '-gnatn']) check_config(lib2_config, 'release', ['-O3', '-gnatn']) check_config(bin_config, 'development', ['-Og', '-g', '-gnatwa', '-gnaty3']) # Create custom Release profile for lib_1 with open('../lib_1/alire.toml', "a") as manifest: manifest.write('[build-switches]\n') manifest.write('release.optimization = "size"\n') manifest.write('release.contracts = "yes"\n') manifest.write('release.ada_version = "ada12"\n') # Create custom wildcard profile for lib_2 with open('../lib_2/alire.toml', "a") as manifest: manifest.write('[build-switches]\n') manifest.write('"*".optimization = "debug"\n') manifest.write('"*".contracts = "no"\n') manifest.write('"*".ada_version = "gnat_extensions"\n') # Check if we can change the profile of a dependency with open(alr_manifest(), "a") as manifest: manifest.write('[build-profiles]\n') manifest.write('lib_2 = "validation"\n') run_alr('update') check_config(lib1_config, 'release', ['-Os', '-gnata', '-gnat12']) check_config(lib2_config, 'validation', ['-Og', '-gnatX']) check_config(bin_config, 'development', ['-Og', '-g', '-gnatwa', '-gnaty3']) # Check that the project builds run_alr('build') print('SUCCESS') alire-1.2.1/testsuite/tests/build_profile/custom_profiles/test.yaml000066400000000000000000000000261430264165500257050ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/build_profile/custom_switches/000077500000000000000000000000001430264165500240525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/build_profile/custom_switches/test.py000066400000000000000000000041761430264165500254130ustar00rootroot00000000000000""" Check that crates can define custom switches """ from drivers.alr import run_alr, init_local_crate, alr_with, alr_manifest from drivers.helpers import content_of from drivers.asserts import assert_match init_local_crate('lib_1', binary=False, enter=False) init_local_crate('lib_2', binary=False, enter=False) init_local_crate('bin_1', binary=True, enter=True) alr_with('lib_1', path='../lib_1') alr_with('lib_2', path='../lib_2') run_alr('update') def check_config(path, profile, expected_switches=[]): conf = content_of(path) assert_match('.*Build_Profile : Build_Profile_Kind := "%s"' % profile, conf) for sw in expected_switches: assert_match('.*"%s"' % sw,conf) lib1_config = "../lib_1/config/lib_1_config.gpr" lib2_config = "../lib_2/config/lib_2_config.gpr" bin_config = "config/bin_1_config.gpr" # Check if we can change the profile of a dependency manifests = [alr_manifest(), '../lib_1/alire.toml', '../lib_2/alire.toml'] for path in manifests: with open(path, "a") as manifest: manifest.write('[build-switches]\n') manifest.write('"*".optimization = ["-opt-switch", "-opt-switch2"]\n') manifest.write('"*".debug_info = ["-debug-info-switch"]\n') manifest.write('"*".runtime_checks = ["-runtime-checks-switch"]\n') manifest.write('"*".compile_checks = ["-compile-checks-switch"]\n') manifest.write('"*".contracts = ["-contracts-switch"]\n') manifest.write('"*".style_checks = ["-style-switch", "-style-switch2"]\n') manifest.write('"*".ada_version = ["-ada-version"]\n') run_alr('update') expected_switches = ['-opt-switch', '-opt-switch2', '-debug-info-switch', '-runtime-checks-switch', '-compile-checks-switch', '-contracts-switch', '-style-switch', '-style-switch2', '-ada-version'] check_config(lib1_config, 'release', expected_switches) check_config(lib2_config, 'release', expected_switches) check_config(bin_config, 'development', expected_switches) print('SUCCESS') alire-1.2.1/testsuite/tests/build_profile/custom_switches/test.yaml000066400000000000000000000000261430264165500257130ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/build_profile/default/000077500000000000000000000000001430264165500222535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/build_profile/default/test.py000066400000000000000000000032401430264165500236030ustar00rootroot00000000000000""" Check switches for default profiles """ from drivers.alr import run_alr, init_local_crate, alr_with, alr_manifest from drivers.helpers import content_of from drivers.asserts import assert_match init_local_crate('lib_1', binary=False, enter=False) init_local_crate('lib_2', binary=False, enter=False) init_local_crate('bin_1', binary=True, enter=True) alr_with('lib_1', path='../lib_1') alr_with('lib_2', path='../lib_2') run_alr('update') def check_config(path, profile, expected_switches=[]): conf = content_of(path) assert_match('.*Build_Profile : Build_Profile_Kind := "%s"' % profile, conf) for sw in expected_switches: assert_match('.*"%s"' % sw,conf) lib1_config = "../lib_1/config/lib_1_config.gpr" lib2_config = "../lib_2/config/lib_2_config.gpr" bin_config = "config/bin_1_config.gpr" # Check default profiles for root and dependency check_config(lib1_config, 'release', ['-O3', '-gnatn']) check_config(lib2_config, 'release', ['-O3', '-gnatn']) check_config(bin_config, 'development', ['-Og', '-g', '-gnatwa', '-gnaty3']) # Check if we can change the profile of a dependency with open(alr_manifest(), "a") as manifest: manifest.write('[build-profiles]\n') manifest.write('lib_1 = "development"\n') run_alr('update') check_config(lib1_config, 'development', ['-Og']) # Check wildcard profile setting with open(alr_manifest(), "a") as manifest: manifest.write('"*" = "validation"\n') run_alr('update') check_config(lib1_config, 'development', ['-Og']) check_config(lib2_config, 'validation', ['-gnatwe']) check_config(bin_config, 'validation', ['-gnatwe']) # Check that the project builds run_alr('build') print('SUCCESS') alire-1.2.1/testsuite/tests/build_profile/default/test.yaml000066400000000000000000000000261430264165500241140ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/clean/000077500000000000000000000000001430264165500170725ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/clean/temp-files/000077500000000000000000000000001430264165500211375ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/clean/temp-files/test.py000066400000000000000000000017541430264165500224770ustar00rootroot00000000000000""" Verify that `alr clean --temp` works properly """ from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match import e3 import os os.mkdir("test") os.chdir("test") # We create a temp file above us, one at the current dir, and one below. # The one above us should not be cleaned. Also, a file not conforming to # "alr-????.tmp" should not be cleaned either. e3.os.fs.touch("../alr-0001.tmp") e3.os.fs.touch("alr-0002.tmp") os.mkdir("nested") e3.os.fs.touch("nested/alr-0003.tmp") e3.os.fs.touch("alien.tmp") p = run_alr("clean", "--temp") assert os.path.exists("../alr-0001.tmp"), "unexpected deletion" assert os.path.exists("alien.tmp"), "unexpected deletion" assert not os.path.exists("alr-0002.tmp"), "unexpected file" assert not os.path.exists("nested/alr-0003.tmp"), "unexpected file" # Finally verify that running again in a clean environment does nothing p = run_alr("clean", "--temp", quiet=False) assert_eq("No temporaries found.\n", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/clean/temp-files/test.yaml000066400000000000000000000000631430264165500230010ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/config/000077500000000000000000000000001430264165500172555ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/config/basics/000077500000000000000000000000001430264165500205215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/config/basics/test.py000066400000000000000000000071661430264165500220640ustar00rootroot00000000000000""" Check basic features of the alr config command """ import os from glob import glob from drivers.alr import run_alr def invalid_key(*args): print("Running: alr config %s" % " ".join([item for item in args])) p = run_alr('config', *args, complain_on_error=False, quiet=False) assert p.status != 0, "command should fail" assert "Invalid configuration key" in p.out, \ "Missing error message in: '%s" % p.out def invalid_builtin(*args): print("Running: alr config %s" % " ".join([item for item in args])) p = run_alr('config', *args, complain_on_error=False, quiet=False) assert p.status != 0, "command should fail" assert "Invalid value " in p.out, \ "Missing error message in: '%s" % p.out def check_value(key, expected_value, local=True): if local: get = run_alr('config', '--get', key) else: get = run_alr('config', '--global', '--get', key) assert get.out == expected_value + "\n", "Got '%s'" % get.out def set_get_unset(key, value, image=None): if image is None: image = value # The key should not be defined get1 = run_alr('config', '--global', '--get', key, complain_on_error=False) assert get1.status != 0, 'Should not be defined' # Define it run_alr('config', '--global', '--set', key, value) # Check that it is defined check_value(key, image, local=False) # Unset it run_alr('config', '--global', '--unset', key) # Check that is it not defined anymore get3 = run_alr('config', '--global', '--get', key, complain_on_error=False) assert get3.status != 0, 'Should not be defined' ####################### # invalid config keys # ####################### invalid_key('--get', '--global', '.test') invalid_key('--get', '--global', '_test.') invalid_key('--get', '--global', '_test') invalid_key('--get', '--global', 'test_') invalid_key('--get', '--global', 'test..test') invalid_key('--get', '--global', '@') invalid_key('--get', '--global', '%') invalid_key('--get', '--global', '&') invalid_key('--get', '--global', '#') invalid_key('--get', '--global', '^') #################### # invalid builtins # #################### invalid_builtin('--set', '--global', 'user.github_login', 'This is not a valid login') invalid_builtin('--set', '--global', 'user.email', '@ This is not @ valid email address@') ############################### # Global Set, Get, Unset, Get # ############################### set_get_unset('test.explicit.string', '"str"', image='str') set_get_unset('test.implicit.string', 'str') set_get_unset('test.int', '42') set_get_unset('test.bool', 'true') set_get_unset('test.float', '0.2', image='2.00000000000000E-01') ################ # Local config # ################ # Check that local operations (default) fail if not in a crate context p = run_alr('config', '--set', 'test.local', '42', complain_on_error=False) assert p.status != 0, 'Should fail' # Get a create to have local context run_alr('get', 'hello') os.chdir(glob('hello*')[0]) # Local operation should now work run_alr('config', '--set', 'test.local', '42') # Set a local and check its value run_alr('config', '--set', 'test.override', '"is_local"') check_value('test.override', 'is_local') # Set a global and check that the local value is still returned run_alr('config', '--set', '--global', 'test.override', '"is_global"') check_value('test.override', 'is_local') # Leave the crate context (local keys are not available anymore) os.chdir('..') # Check that we now see the global value check_value('test.override', 'is_global', local=False) # Remove the global key run_alr('config', '--unset', '--global', 'test.override') print('SUCCESS') alire-1.2.1/testsuite/tests/config/basics/test.yaml000066400000000000000000000000631430264165500223630ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/config/community-disable/000077500000000000000000000000001430264165500227025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/config/community-disable/test.py000066400000000000000000000007701430264165500242370ustar00rootroot00000000000000""" Verify that catalog.autoconfig works as intended (no autoadd community index) """ from glob import glob import os import re from drivers.alr import run_alr from drivers.asserts import assert_match # Since no index is configured, looking for crates will attempt to add the # community index p = run_alr("search", "hello", quiet=False) assert \ "Not configuring the community index, " + \ "disabled via index.auto_community" \ in p.out, "unexpected output: " + p.out print('SUCCESS') alire-1.2.1/testsuite/tests/config/community-disable/test.yaml000066400000000000000000000000651430264165500245460ustar00rootroot00000000000000driver: python-script # No index defined, on purpose alire-1.2.1/testsuite/tests/config/distro-disable/000077500000000000000000000000001430264165500221625ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/config/distro-disable/test.py000066400000000000000000000004761430264165500235220ustar00rootroot00000000000000""" Verify that disabling distro detection works as intended """ import os from glob import glob from drivers.alr import run_alr, distro_is_known run_alr("config", "--global", "--set", "distribution.disable_detection", "true") assert not distro_is_known(), "Unexpected distro detection" print('SUCCESS') alire-1.2.1/testsuite/tests/config/distro-disable/test.yaml000066400000000000000000000000631430264165500240240ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/config/relative_config_path/000077500000000000000000000000001430264165500234315ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/config/relative_config_path/test.py000066400000000000000000000006071430264165500247650ustar00rootroot00000000000000""" Verify that using a relative path for Alire config dir is ok """ import os from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_eq from drivers.helpers import lines_of run_alr("--config", ".", "config", "--global", "--set", "some_config_key", "true") assert_eq("some_config_key = true\n", lines_of ("config.toml")[0]) print('SUCCESS') alire-1.2.1/testsuite/tests/config/relative_config_path/test.yaml000066400000000000000000000000631430264165500252730ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/crate_config/000077500000000000000000000000001430264165500204335ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/000077500000000000000000000000001430264165500215145ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/000077500000000000000000000000001430264165500233305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/hello_src/000077500000000000000000000000001430264165500253025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/hello_src/hello_world.gpr000066400000000000000000000002111430264165500303200ustar00rootroot00000000000000with "config/hello_world_config"; project Hello_World is for Source_Dirs use ("src"); for Main use ("main.adb"); end Hello_World; alire-1.2.1/testsuite/tests/crate_config/basic/my_index/hello_src/src/000077500000000000000000000000001430264165500260715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/hello_src/src/main.adb000066400000000000000000000000751430264165500274670ustar00rootroot00000000000000with Plop; procedure Main is begin Plop.Print; end Main; alire-1.2.1/testsuite/tests/crate_config/basic/my_index/index/000077500000000000000000000000001430264165500244375ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/index/he/000077500000000000000000000000001430264165500250335ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/index/he/hello_world/000077500000000000000000000000001430264165500273455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/index/he/hello_world/hello_world-0.1.0.toml000066400000000000000000000004451430264165500332110ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] executables=['main'] [origin] url = "file:../../../hello_src" [[depends-on]] libcrate_config = "*" alire-1.2.1/testsuite/tests/crate_config/basic/my_index/index/index.toml000066400000000000000000000000201430264165500264330ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/crate_config/basic/my_index/index/li/000077500000000000000000000000001430264165500250435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/index/li/libcrate_config/000077500000000000000000000000001430264165500301555ustar00rootroot00000000000000libcrate_config-1.0.0.toml000066400000000000000000000010451430264165500345370ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/index/li/libcrate_configdescription = "crate config demonstration project" name = "libcrate_config" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../libcrate_config_src" [configuration.variables] Var_Bool = {type="Boolean", default=true} Var_String = {type="String", default="Test string."} Var_Int = {type="Integer", first=-42, last=42, default=-1} Var_Real = {type="Real", first=-42.0, last=42.0, default=-1.0} Var_Enum = {type="Enum", values=["A", "B", "C"], default="B"} alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/000077500000000000000000000000001430264165500273115ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/libcrate_config.gpr000066400000000000000000000023301430264165500331330ustar00rootroot00000000000000with "config/libcrate_config_config"; project Libcrate_Config is for Source_Dirs use ("src", "config"); for Languages use ("Ada", "C"); for Library_Name use "crate_config"; for Library_Kind use "static"; Src_Dirs := ("src", "config"); case Libcrate_Config_Config.Var_Bool is when "True" => null; when others => Src_Dirs := Src_Dirs & ("invalid value for Var_Bool"); end case; case Libcrate_Config_Config.Var_String is when "Test string." => null; when others => Src_Dirs := Src_Dirs & ("invalid value for Var_String"); end case; case Libcrate_Config_Config.Var_Enum is when "B" => null; when others => Src_Dirs := Src_Dirs & ("invalid value for Var_Enum"); end case; case Libcrate_Config_Config.Var_Int is when "-1" => null; when others => Src_Dirs := Src_Dirs & ("invalid value for Var_Int"); end case; case Libcrate_Config_Config.Var_Int_Last is when "42" => null; when others => Src_Dirs := Src_Dirs & ("invalid value for Var_Int_Last"); end case; Src_Dirs := Src_Dirs & ("src/" & Libcrate_Config_Config.Alire_Host_OS); for Source_Dirs use Src_Dirs; end Libcrate_Config; alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/000077500000000000000000000000001430264165500301005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/host_specific.ads000066400000000000000000000000461430264165500334130ustar00rootroot00000000000000function Host_Specific return String; alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/linux/000077500000000000000000000000001430264165500312375ustar00rootroot00000000000000host_specific.adb000066400000000000000000000001351430264165500344510ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/linuxfunction Host_Specific return String is begin return "linux specific"; end Host_Specific; alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/macos/000077500000000000000000000000001430264165500312025ustar00rootroot00000000000000host_specific.adb000066400000000000000000000001351430264165500344140ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/macosfunction Host_Specific return String is begin return "macos specific"; end Host_Specific; alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/plop.adb000066400000000000000000000034051430264165500315240ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; with Libcrate_Config_Config; use Libcrate_Config_Config; with Host_Specific; package body Plop is type My_Int_Type is range Var_Int_First .. Var_Int_Last; My_Int : constant My_Int_Type := Var_Int; type My_Real_Type is digits 10 range Var_Real_First .. Var_Real_Last; My_Real : constant My_Real_Type := Var_Real; procedure Print is procedure Test_C_Print; pragma Import(C, Test_C_Print, "test_c_print"); begin Put_Line ("Ada -> Crate_Version: " & Libcrate_Config_Config.Crate_Version); Put_Line ("Ada -> Crate_Name: " & Libcrate_Config_Config.Crate_Name); Put_Line ("Ada -> Alire_Host_OS: " & Libcrate_Config_Config.Alire_Host_OS); Put_Line ("Ada -> Alire_Host_Arch: " & Libcrate_Config_Config.Alire_Host_Arch); Put_Line ("Ada -> Alire_Host_Distro: " & Libcrate_Config_Config.Alire_Host_Distro); Put_Line ("Ada -> Var_Bool: " & Libcrate_Config_Config.Var_Bool'Img); Put_Line ("Ada -> Var_String: '" & Libcrate_Config_Config.Var_String & "'"); Put_Line ("Ada -> Var_Int'First: " & My_Int_Type'First'Img); Put_Line ("Ada -> Var_Int'Last: " & My_Int_Type'Last'Img); Put_Line ("Ada -> Var_Int: " & My_Int'Img); Put_Line ("Ada -> Var_Real'First: " & My_Real_Type'First'Img); Put_Line ("Ada -> Var_Real'Last: " & My_Real_Type'Last'Img); Put_Line ("Ada -> Var_Real: " & My_Real'Img); Put_Line ("Ada -> Var_Enum_Kind'First: " & Libcrate_Config_Config.Var_Enum_Kind'First'Img); Put_Line ("Ada -> Var_Enum_Kind'Last: " & Libcrate_Config_Config.Var_Enum_Kind'Last'Img); Put_Line ("Ada -> Var_Enum: " & Libcrate_Config_Config.Var_Enum'Img); Put_Line ("Host_Specific -> " & Host_Specific); Test_C_Print; end Print; end Plop; alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/plop.ads000066400000000000000000000000561430264165500315440ustar00rootroot00000000000000package Plop is procedure Print; end Plop; alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/test.c000066400000000000000000000017011430264165500312220ustar00rootroot00000000000000#include #include "libcrate_config_config.h" void test_c_print(void) { printf("C -> Crate_Version: %s\n", CRATE_VERSION); printf("C -> Crate_Name: %s\n", CRATE_NAME); printf("C -> Alire_Host_OS: %s\n", ALIRE_HOST_OS); printf("C -> Alire_Host_Arch: %s\n", ALIRE_HOST_ARCH); printf("C -> Alire_Host_Distro: %s\n", ALIRE_HOST_DISTRO); printf("C -> VAR_BOOL: %d\n", VAR_BOOL); printf("C -> VAR_STRING: '%s'\n", VAR_STRING); printf("C -> VAR_INT_FIRST: %d\n", VAR_INT_FIRST); printf("C -> VAR_INT_LAST: %d\n", VAR_INT_LAST); printf("C -> VAR_INT: %d\n", VAR_INT); printf("C -> VAR_REAL_FIRST: %f\n", VAR_REAL_FIRST); printf("C -> VAR_REAL_LAST: %f\n", VAR_REAL_LAST); printf("C -> VAR_REAL: %f\n", VAR_REAL); printf("C -> VAR_ENUM_A: %d\n", VAR_ENUM_A); printf("C -> VAR_ENUM_B: %d\n", VAR_ENUM_B); printf("C -> VAR_ENUM_C: %d\n", VAR_ENUM_C); printf("C -> VAR_ENUM: %d\n", VAR_ENUM); } alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/windows/000077500000000000000000000000001430264165500315725ustar00rootroot00000000000000host_specific.adb000066400000000000000000000001371430264165500350060ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/basic/my_index/libcrate_config_src/src/windowsfunction Host_Specific return String is begin return "windows specific"; end Host_Specific; alire-1.2.1/testsuite/tests/crate_config/basic/test.py000066400000000000000000000037521430264165500230540ustar00rootroot00000000000000""" Test basic crate configuration """ from drivers.alr import run_alr from drivers.asserts import assert_eq from drivers.helpers import distribution, host_architecture, host_os import os import platform # Get and check post fetch action run_alr('get', 'hello_world') os.chdir("hello_world_0.1.0_filesystem/") expected_host_arch = host_architecture() expected_host_os = host_os() expected_host_distro = distribution().lower() run_alr('build') p = run_alr('run') assert_eq("Ada -> Crate_Version: 1.0.0\n" "Ada -> Crate_Name: libcrate_config\n" f"Ada -> Alire_Host_OS: {expected_host_os}\n" f"Ada -> Alire_Host_Arch: {expected_host_arch}\n" f"Ada -> Alire_Host_Distro: {expected_host_distro}\n" "Ada -> Var_Bool: TRUE\n" "Ada -> Var_String: 'Test string.'\n" "Ada -> Var_Int'First: -42\n" "Ada -> Var_Int'Last: 42\n" "Ada -> Var_Int: -1\n" "Ada -> Var_Real'First: -4.20000000000000E+01\n" "Ada -> Var_Real'Last: 4.20000000000000E+01\n" "Ada -> Var_Real: -1.000000000E+00\n" "Ada -> Var_Enum_Kind'First: A\n" "Ada -> Var_Enum_Kind'Last: C\n" "Ada -> Var_Enum: B\n" f"Host_Specific -> {expected_host_os} specific\n" "C -> Crate_Version: 1.0.0\n" "C -> Crate_Name: libcrate_config\n" f"C -> Alire_Host_OS: {expected_host_os}\n" f"C -> Alire_Host_Arch: {expected_host_arch}\n" f"C -> Alire_Host_Distro: {expected_host_distro}\n" "C -> VAR_BOOL: 1\n" "C -> VAR_STRING: 'Test string.'\n" "C -> VAR_INT_FIRST: -42\n" "C -> VAR_INT_LAST: 42\n" "C -> VAR_INT: -1\n" "C -> VAR_REAL_FIRST: -42.000000\n" "C -> VAR_REAL_LAST: 42.000000\n" "C -> VAR_REAL: -1.000000\n" "C -> VAR_ENUM_A: 1\n" "C -> VAR_ENUM_B: 2\n" "C -> VAR_ENUM_C: 3\n" "C -> VAR_ENUM: 2\n", p.out) print(p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/crate_config/basic/test.yaml000066400000000000000000000001101430264165500233470ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/crate_config/gen_control/000077500000000000000000000000001430264165500227445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/000077500000000000000000000000001430264165500245605ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/hello_src/000077500000000000000000000000001430264165500265325ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/hello_src/hello_world.gpr000066400000000000000000000002031430264165500315510ustar00rootroot00000000000000with "libcrate_config.gpr"; project Hello_World is for Source_Dirs use ("src"); for Main use ("main.adb"); end Hello_World; alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/hello_src/src/000077500000000000000000000000001430264165500273215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/hello_src/src/main.adb000066400000000000000000000000751430264165500307170ustar00rootroot00000000000000with Plop; procedure Main is begin Plop.Print; end Main; alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/index/000077500000000000000000000000001430264165500256675ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/index/he/000077500000000000000000000000001430264165500262635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/index/he/hello_world/000077500000000000000000000000001430264165500305755ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000005061430264165500343600ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] executables=['main'] [origin] url = "file:../../../hello_src" [[depends-on]] libcrate_config = "*" [configuration] disabled = true alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/index/index.toml000066400000000000000000000000201430264165500276630ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/index/li/000077500000000000000000000000001430264165500262735ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/index/li/libcrate_config/000077500000000000000000000000001430264165500314055ustar00rootroot00000000000000libcrate_config-1.0.0.toml000066400000000000000000000011721430264165500357700ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/index/li/libcrate_configdescription = "crate config demonstration project" name = "libcrate_config" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../libcrate_config_src" [configuration] output_dir = "plop_config" generate_c = false generate_gpr = false [configuration.variables] Var_Bool = {type="Boolean", default=true} Var_String = {type="String", default="Test string."} Var_Int = {type="Integer", first=-42, last=42, default=-1} Var_Real = {type="Real", first=-42.0, last=42.0, default=-1.0} Var_Enum = {type="Enum", values=["A", "B", "C"], default="B"} alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/libcrate_config_src/000077500000000000000000000000001430264165500305415ustar00rootroot00000000000000libcrate_config.gpr000066400000000000000000000003621430264165500343070ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/libcrate_config_srcproject Libcrate_Config is for Source_Dirs use ("src", "config"); for Languages use ("Ada"); for Library_Name use "crate_config"; for Library_Kind use "static"; for Source_Dirs use ("src", "plop_config"); end Libcrate_Config; alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/libcrate_config_src/src/000077500000000000000000000000001430264165500313305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/libcrate_config_src/src/plop.adb000066400000000000000000000013411430264165500327510ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; with Libcrate_Config_Config; use Libcrate_Config_Config; package body Plop is type My_Int_Type is range Var_Int_First .. Var_Int_Last; My_Int : constant My_Int_Type := Var_Int; type My_Real_Type is digits 10 range Var_Real_First .. Var_Real_Last; My_Real : constant My_Real_Type := Var_Real; procedure Print is begin Put_Line ("Ada -> Var_Bool: " & Libcrate_Config_Config.Var_Bool'Img); Put_Line ("Ada -> Var_String: '" & Libcrate_Config_Config.Var_String & "'"); Put_Line ("Ada -> Var_Int: " & My_Int'Img); Put_Line ("Ada -> Var_Real: " & My_Real'Img); Put_Line ("Ada -> Var_Enum: " & Libcrate_Config_Config.Var_Enum'Img); end Print; end Plop; alire-1.2.1/testsuite/tests/crate_config/gen_control/my_index/libcrate_config_src/src/plop.ads000066400000000000000000000000561430264165500327740ustar00rootroot00000000000000package Plop is procedure Print; end Plop; alire-1.2.1/testsuite/tests/crate_config/gen_control/test.py000066400000000000000000000017141430264165500243000ustar00rootroot00000000000000""" Test basic crate configuration """ from drivers.alr import run_alr from drivers.asserts import assert_eq from drivers.helpers import contents import os # Get and check post fetch action run_alr('get', 'hello_world', quiet=False, debug=True) os.chdir("hello_world_0.1.0_filesystem/") run_alr('build', quiet=False, debug=True) p = run_alr('run') assert_eq("Ada -> Var_Bool: TRUE\n" "Ada -> Var_String: 'Test string.'\n" "Ada -> Var_Int: -1\n" "Ada -> Var_Real: -1.000000000E+00\n" "Ada -> Var_Enum: B\n", p.out) assert not os.path.isdir('config'), "config should not be created for root project" for top, dirs, files in os.walk('./'): for nm in files: path = os.path.join(top, nm) if 'plop_config' in path: assert not path.endswith('.h'), "C header should not be generated" assert not path.endswith('.gpr'), "GPR should not be generated" print(p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/crate_config/gen_control/test.yaml000066400000000000000000000001101430264165500245770ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/crate_config/reserved_names/000077500000000000000000000000001430264165500234355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/reserved_names/test.py000066400000000000000000000020301430264165500247610ustar00rootroot00000000000000""" Test that reserved configuration variable names are rejected """ import os.path from drivers.alr import run_alr, init_local_crate, alr_manifest from drivers.asserts import assert_match from drivers.helpers import content_of test_dir = os.getcwd() crate_name = "xxx" for name in ["crate_version", "Crate_VERsion", "crate_name", "alire_", "ada_compiler_switches", "c_compiler_switches"]: init_local_crate(name=crate_name) with open(alr_manifest(), "at") as manifest: manifest.write("[configuration.variables]\n") manifest.write('%s = {type = "Boolean", default = false}\n' % name) p = run_alr("update", complain_on_error=False) assert p.status != 0, "alr should have errored" assert_match(".*\n" "ERROR: Configuration variable name '%s.%s' " "is reserved for Alire internal use\n.*" % (crate_name, name.lower()), p.out) os.chdir("..") # Create a different crate name for the next iteration crate_name += "x" print('SUCCESS') alire-1.2.1/testsuite/tests/crate_config/reserved_names/test.yaml000066400000000000000000000001701430264165500252760ustar00rootroot00000000000000driver: python-script indexes: basic_index: # needed to avoid cloning the community index in_fixtures: true alire-1.2.1/testsuite/tests/crate_config/style_checks_off/000077500000000000000000000000001430264165500237455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/000077500000000000000000000000001430264165500255615ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/hello_src/000077500000000000000000000000001430264165500275335ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/hello_src/hello_world.gpr000066400000000000000000000011221430264165500325530ustar00rootroot00000000000000with "config/hello_world_config.gpr"; project Hello_World is for Source_Dirs use ("src/", "config/"); for Object_Dir use "obj/" & Hello_World_Config.Build_Profile; for Create_Missing_Dirs use "True"; for Exec_Dir use "bin"; for Main use ("hello_world.adb"); package Compiler is for Default_Switches ("Ada") use Hello_World_Config.Ada_Compiler_Switches; end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; package Install is for Artifacts (".") use ("share"); end Install; end Hello_World; alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/hello_src/src/000077500000000000000000000000001430264165500303225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/hello_src/src/hello_world.adb000066400000000000000000000002311430264165500333000ustar00rootroot00000000000000with Ada.Text_IO; with Hello_World_Config; procedure Hello_World is begin Ada.Text_IO.Put_Line (Hello_World_Config.Crate_Version); end Hello_World; alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/index/000077500000000000000000000000001430264165500266705ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/index/he/000077500000000000000000000000001430264165500272645ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/index/he/hello_world/000077500000000000000000000000001430264165500315765ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000007121430264165500353600ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] executables=['main'] [origin] url = "file:../../../hello_src" [configuration.variables] test = { type = "Enum", values = ["This_Is_Too_Long", "And_Might_Trigger", "A_Style_Check_Error", "But_We_Disable_Them", "In_The_Generate_Code"], default = "This_Is_Too_Long"} alire-1.2.1/testsuite/tests/crate_config/style_checks_off/my_index/index/index.toml000066400000000000000000000000201430264165500306640ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/crate_config/style_checks_off/test.py000066400000000000000000000004101430264165500252710ustar00rootroot00000000000000""" Test that style checks are disabled in generated code """ from drivers.alr import run_alr import os # Get and check post fetch action run_alr('get', 'hello_world') os.chdir("hello_world_0.1.0_filesystem/") run_alr('build', '--validation') print('SUCCESS') alire-1.2.1/testsuite/tests/crate_config/style_checks_off/test.yaml000066400000000000000000000001101430264165500256000ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/debug/000077500000000000000000000000001430264165500170765ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/debug/enabled-dump-exception/000077500000000000000000000000001430264165500234275ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/debug/enabled-dump-exception/test.py000066400000000000000000000016321430264165500247620ustar00rootroot00000000000000""" Test that -d/--debug enable dumping of unexpected exceptions """ import os from drivers.alr import prepare_env, prepare_indexes, run_alr from drivers.asserts import assert_eq, assert_match def check_output(dump): assert_match( '''stderr: PROGRAM_ERROR stderr: Raising forcibly stderr: raised PROGRAM_ERROR : Raising forcibly.* ''', dump) # Check debug dump (we intentionally disable debug flag in run_alr) check_output(run_alr('-d', 'dev', '--raise', debug=False, complain_on_error=False).out) # Long flag version check_output(run_alr('--debug', 'dev', '--raise', debug=False, complain_on_error=False).out) # Check ordinary non-debug output: assert_eq(run_alr('dev', '--raise', debug=False, complain_on_error=False).out, "ERROR: Raising forcibly\n" "ERROR: alr encountered an unexpected error, re-run with -d for details.\n") print('SUCCESS') alire-1.2.1/testsuite/tests/debug/enabled-dump-exception/test.yaml000066400000000000000000000000261430264165500252700ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/debug/logging-scopes/000077500000000000000000000000001430264165500220165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/debug/logging-scopes/test.py000066400000000000000000000031451430264165500233520ustar00rootroot00000000000000""" Test the fidelity of various logging scopes """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_eq from drivers.asserts import assert_match # Check invalid syntax detection p = run_alr('-d--', complain_on_error=False, quiet=False) assert p.status == 1, "alr should have error code 1" assert_eq('Filtering mode: BLACKLIST\n' 'Invalid logging scope separator: --\n' 'ERROR: Invalid logging filters.', p.out.strip()) # Check empty whitelist lets nothing through p = run_alr('-vv', '-d+', 'dev', quiet=False) assert_eq('Filtering mode: WHITELIST', p.out.strip()) # Check whitelisting p = run_alr('-vv', '-d+dev', 'dev', '--filter', quiet=False) assert_match('Filtering mode: WHITELIST\n' 'Filtering substring: dev\n' '\[Alr.Commands.Dev.Execute\] \(alr-commands-dev.adb:[0-9]* \)' ' -->> In dev --filter', p.out.strip()) # Check whitelisting with exception p = run_alr('-vv', '-d+dev-exec', 'dev', '--filter', quiet=False) assert_eq('Filtering mode: WHITELIST\n' 'Filtering substring: dev\n' 'Filtering exception: exec', p.out.strip()) # Check blacklisting with exception p = run_alr('-vv', '-d-a+main', 'dev', quiet=False) assert_match('Filtering mode: BLACKLIST\n' 'Filtering substring: a\n' 'Filtering exception: main\n' '\[Alr.Main \] \(alr-main.adb:.*', # Remaining output is likely to change in the future so lets just # stop here the matching. p.out.strip()) print('SUCCESS') alire-1.2.1/testsuite/tests/debug/logging-scopes/test.yaml000066400000000000000000000000261430264165500236570ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/debug/outcome-stack-trace/000077500000000000000000000000001430264165500227505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/debug/outcome-stack-trace/test.py000066400000000000000000000010641430264165500243020ustar00rootroot00000000000000""" Verify that creating a Outcome_Failure also dumps the stack trace to log output """ from drivers.alr import run_alr from drivers.asserts import assert_match import re p = run_alr('index', '--name', 'xx', '--add', '.', complain_on_error=False, debug=True, quiet=True) # Failed call because name is too short. That causes a Outcome_Failure to be # returned. # Since stack traces wildly differ across platforms, a minimal check is done: assert_match( '.*Generating Outcome_Failure with call stack:.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/debug/outcome-stack-trace/test.yaml000066400000000000000000000000261430264165500246110ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/debug/self-tests/000077500000000000000000000000001430264165500211675ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/debug/self-tests/test.py000066400000000000000000000004521430264165500225210ustar00rootroot00000000000000""" Do internal self-tests that are simpler to do in Ada code than with a fully- fledged test case. """ from glob import glob from drivers.alr import run_alr p = run_alr('dev', '--test', complain_on_error=True, quiet=True) assert p.status == 0, "alr should have error code 0" print('SUCCESS') alire-1.2.1/testsuite/tests/debug/self-tests/test.yaml000066400000000000000000000000261430264165500230300ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/exec/000077500000000000000000000000001430264165500167345ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/exec/basic/000077500000000000000000000000001430264165500200155ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/exec/basic/test.py000066400000000000000000000016551430264165500213550ustar00rootroot00000000000000""" Check that alr exec runs commands within Alire environment/context """ from glob import glob import os from drivers.alr import run_alr from drivers.asserts import assert_match import re # Get the "hello" project and enter its directory run_alr('get', 'hello') os.chdir(glob('hello*')[0]) p = run_alr('exec', 'echo', 'test string', quiet=False) # -q will hide the output of the exec command assert_match('test string', p.out, flags=re.S) # exec using -- to separate arguments to the spawned command p = run_alr('exec', '--', 'sh', '-c', 'echo "print GPR_PROJECT_PATH from' ' alire context:" ${GPR_PROJECT_PATH}', quiet=False) # -q will hide the output of the exec command assert_match('.* GPR_PROJECT_PATH from alire context.*' 'hello_[0-9\.]*_filesystem.*' 'libhello_[0-9\.]*_filesystem.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/exec/basic/test.yaml000066400000000000000000000000631430264165500216570ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/exec/with_project/000077500000000000000000000000001430264165500214355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/exec/with_project/test.py000066400000000000000000000025051430264165500227700ustar00rootroot00000000000000""" Check alr exec -P switch support """ from glob import glob import os from drivers.alr import run_alr from drivers.asserts import assert_match import re # Get the "hello" project and enter its directory run_alr('get', 'hello') os.chdir(glob('hello*')[0]) def check(p_switch, expected_out, complain_on_error=True): p = run_alr('exec', p_switch, '--', 'echo', '1', '2', '3', '4', '5', quiet=False, # -q will hide the output of the exec command complain_on_error=complain_on_error) assert_match(expected_out, p.out, flags=re.S) check('-P', '-P hello.gpr 1 2 3 4 5') check('-P1', '-P hello.gpr 1 2 3 4 5') check('-P2', '1 -P hello.gpr 2 3 4 5') check('-P5', '1 2 3 4 -P hello.gpr 5') check('-P6', '1 2 3 4 5 -P hello.gpr') check('-P7', '1 2 3 4 5 -P hello.gpr') check('-P42000', '1 2 3 4 5 -P hello.gpr') check('-P-1', '1 2 3 4 5 -P hello.gpr') check('-P-2', '1 2 3 4 -P hello.gpr 5') check('-P-3', '1 2 3 -P hello.gpr 4 5') check('-P-5', '-P hello.gpr 1 2 3 4 5') check('-P-6', '-P hello.gpr 1 2 3 4 5') check('-P-7', '-P hello.gpr 1 2 3 4 5') check('-P-42000', '-P hello.gpr 1 2 3 4 5') check('-P0', '.*Invalid position argument.*', complain_on_error=False) check('-Ptest', '.*Invalid position argument.*', complain_on_error=False) print('SUCCESS') alire-1.2.1/testsuite/tests/exec/with_project/test.yaml000066400000000000000000000000631430264165500232770ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/get/000077500000000000000000000000001430264165500165675ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/000077500000000000000000000000001430264165500226145ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/000077500000000000000000000000001430264165500244305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/crates/000077500000000000000000000000001430264165500257115ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/crates/crate/000077500000000000000000000000001430264165500270075ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/crates/crate/.emptydir000066400000000000000000000000001430264165500306330ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/crates/crate/alire.lock000066400000000000000000000001501430264165500307510ustar00rootroot00000000000000# THIS IS A MACHINE-GENERATED FILE. DO NOT EDIT MANUALLY. [solution] [solution.context] solved = true alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/crates/crate/alire.toml000066400000000000000000000005701430264165500310020ustar00rootroot00000000000000description = "Shiny new project" maintainers = ["your@email.here"] maintainers-logins = ["github-username"] metadata-version = "0.2.0" name = "crate" version = "1.0.0" # We check the following property is absent after `alr get` completes in the # regular manifest, but present in the *.upstream backup badproperty = "a malicious property that is not in the index metadata" alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/crates/crate/crate.gpr000066400000000000000000000007321430264165500306210ustar00rootroot00000000000000project Crate is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Exec_Dir use "bin"; for Main use ("crate.adb"); package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end Crate; alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/crates/crate/src/000077500000000000000000000000001430264165500275765ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/crates/crate/src/crate.adb000066400000000000000000000000551430264165500313440ustar00rootroot00000000000000procedure Crate is begin null; end Crate; alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/index/000077500000000000000000000000001430264165500255375ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/index/cr/000077500000000000000000000000001430264165500261435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/index/cr/crate/000077500000000000000000000000001430264165500272415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/index/cr/crate/crate-1.0.0.toml000066400000000000000000000003021430264165500316610ustar00rootroot00000000000000description = "Sample crate" name = "crate" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] url = "file:../../../crates/crate" alire-1.2.1/testsuite/tests/get/backup-user-manifest/my_index/index/index.toml000066400000000000000000000000201430264165500275330ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/get/backup-user-manifest/test.py000066400000000000000000000014101430264165500241410ustar00rootroot00000000000000""" Check that an upstream manifest is backed up and not used upon `alr get` """ from drivers.alr import run_alr from drivers.helpers import content_of from os import chdir, path # Retrieve a crate that bundles a manifest file run_alr('get', 'crate') chdir('crate_1.0.0_filesystem') upstream = path.join('alire', 'alire.toml.upstream') # Verify that the manifest has been properly renamed assert path.isfile(upstream), "Expected backup file missing" # Verify that contents are as expected in the generated and backed up manifests assert "badproperty" not in content_of("alire.toml"), \ "Unexpected contents present in manifest file" assert "badproperty" in content_of(upstream), \ "Unexpected contents missing in upstream manifest file" print('SUCCESS') alire-1.2.1/testsuite/tests/get/backup-user-manifest/test.yaml000066400000000000000000000001101430264165500244470ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/get/build/000077500000000000000000000000001430264165500176665ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/000077500000000000000000000000001430264165500215025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/crates/000077500000000000000000000000001430264165500227635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/crates/bad/000077500000000000000000000000001430264165500235115ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/crates/bad/bad.gpr000066400000000000000000000007241430264165500247540ustar00rootroot00000000000000project Bad is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Exec_Dir use "bin"; for Main use ("bad.adb"); package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end Bad; alire-1.2.1/testsuite/tests/get/build/my_index/crates/bad/src/000077500000000000000000000000001430264165500243005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/crates/bad/src/bad.adb000066400000000000000000000000571430264165500255000ustar00rootroot00000000000000procedure Bad is begin Won't build end Bad; alire-1.2.1/testsuite/tests/get/build/my_index/crates/good/000077500000000000000000000000001430264165500237135ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/crates/good/good.gpr000066400000000000000000000007271430264165500253630ustar00rootroot00000000000000project Good is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Exec_Dir use "bin"; for Main use ("good.adb"); package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end Good; alire-1.2.1/testsuite/tests/get/build/my_index/crates/good/src/000077500000000000000000000000001430264165500245025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/crates/good/src/good.adb000066400000000000000000000000531430264165500261000ustar00rootroot00000000000000procedure Good is begin null; end Good; alire-1.2.1/testsuite/tests/get/build/my_index/index/000077500000000000000000000000001430264165500226115ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/index/ba/000077500000000000000000000000001430264165500231735ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/index/ba/bad/000077500000000000000000000000001430264165500237215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/index/ba/bad/bad-1.0.0.toml000066400000000000000000000003001430264165500257670ustar00rootroot00000000000000description = "Bad crate" name = "bad" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["jane@doe.com"] maintainers-logins = ["mylogin"] [origin] url = "file:./../../../crates/bad" alire-1.2.1/testsuite/tests/get/build/my_index/index/go/000077500000000000000000000000001430264165500232165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/index/go/good/000077500000000000000000000000001430264165500241465ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/build/my_index/index/go/good/good-1.0.0.toml000066400000000000000000000003031430264165500264210ustar00rootroot00000000000000description = "Good crate" name = "good" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["john@doe.com"] maintainers-logins = ["mylogin"] [origin] url = "file:./../../../crates/good" alire-1.2.1/testsuite/tests/get/build/my_index/index/index.toml000066400000000000000000000000201430264165500246050ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/get/build/test.py000066400000000000000000000005151430264165500212200ustar00rootroot00000000000000""" Check the `alr get --build` combo for crates that [don't] build """ from drivers.alr import run_alr # Should succeed p = run_alr('get', '--build', 'good') # Should err out p = run_alr('get', '--build', 'bad', complain_on_error=False) assert p.status == 1, "Expected command to exit with code 1" print('SUCCESS') alire-1.2.1/testsuite/tests/get/build/test.yaml000066400000000000000000000001101430264165500215210ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/get/dirname/000077500000000000000000000000001430264165500202065ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/dirname/test.py000066400000000000000000000003651430264165500215430ustar00rootroot00000000000000""" Verify output of `alr get --dirname` """ from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match assert_eq("libhello_1.0.0_filesystem\n", run_alr("get", "libhello", "--dirname").out) print('SUCCESS') alire-1.2.1/testsuite/tests/get/dirname/test.yaml000066400000000000000000000000631430264165500220500ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/get/external-tool-dependency/000077500000000000000000000000001430264165500235005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/external-tool-dependency/my_index/000077500000000000000000000000001430264165500253145ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/external-tool-dependency/my_index/index.toml000066400000000000000000000000201430264165500273100ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/get/external-tool-dependency/my_index/ma/000077500000000000000000000000001430264165500257115ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/external-tool-dependency/my_index/ma/main/000077500000000000000000000000001430264165500266355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/external-tool-dependency/my_index/ma/main/main-1.0.0.toml000066400000000000000000000006151430264165500311120ustar00rootroot00000000000000description = "Main program" name = "main" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[depends-on]] make = "*" [origin] url = "file:./../../../crates/noop_1.0-default.tgz" hashes = ["sha512:de676fbda9f16ba98fe1adc80e20dbd9b98a86352267825b55f1d719570adc0f92f1be2e96fd3df06aac4f6b5fee8686695e315be370cabe482edefc5a0570c5"] alire-1.2.1/testsuite/tests/get/external-tool-dependency/my_index/ma/make/000077500000000000000000000000001430264165500266265ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/external-tool-dependency/my_index/ma/make/make-external.toml000066400000000000000000000004301430264165500322550ustar00rootroot00000000000000description = "Utility for directing compilation" name = "make" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[external]] kind = "version-output" version-regexp = ".*Make ([\\d\\.]+).*" version-command = ["make", "--version"] alire-1.2.1/testsuite/tests/get/external-tool-dependency/test.py000066400000000000000000000030241430264165500250300ustar00rootroot00000000000000""" Test that external tool dependencies work as expected. """ import re from drivers.alr import run_alr from drivers.asserts import assert_eq from drivers.helpers import compare, contents from subprocess import check_output # Should silently retrieve everything p = run_alr('get', 'main') assert_eq('', p.out) dir_content = contents('main_1.0.0_filesystem/') # The directrory for the external dependencies 'make' contains a version number # that can be different depending on the platform or version of the # distribution. We search through the content to find that directory and use it # in the expected output. make_dep_dir = "__MAKE_DEPENDENCY_DIR_NOT_FOUND_" for elt in dir_content: if re.match('^.*/alire/cache/dependencies/make_.*_external$', elt): make_dep_dir = elt # Check folder contents compare(dir_content, ['main_1.0.0_filesystem/alire', 'main_1.0.0_filesystem/alire.toml', 'main_1.0.0_filesystem/alire/alire.lock', 'main_1.0.0_filesystem/alire/cache', 'main_1.0.0_filesystem/alire/cache/dependencies', make_dep_dir, make_dep_dir + "/alire", 'main_1.0.0_filesystem/alire/config.toml', 'main_1.0.0_filesystem/config', 'main_1.0.0_filesystem/config/main_config.ads', 'main_1.0.0_filesystem/config/main_config.gpr', 'main_1.0.0_filesystem/config/main_config.h', 'main_1.0.0_filesystem/noop.gpr', 'main_1.0.0_filesystem/src', 'main_1.0.0_filesystem/src/noop.adb' ]) print('SUCCESS') alire-1.2.1/testsuite/tests/get/external-tool-dependency/test.yaml000066400000000000000000000001461430264165500253440ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/get/get-not-found/000077500000000000000000000000001430264165500212555ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/get-not-found/test.py000066400000000000000000000006501430264165500226070ustar00rootroot00000000000000""" Test the behavior of "alr get" to get a crate that does not exist. """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match p = run_alr('get', 'does_not_exist', complain_on_error=False) assert_eq(1, p.status) assert_match('.*Crate \[does_not_exist\] does not exist in the catalog\.\n', p.out) assert_eq([], glob('does_not_exist*')) print('SUCCESS') alire-1.2.1/testsuite/tests/get/get-not-found/test.yaml000066400000000000000000000000631430264165500231170ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/get/git-local/000077500000000000000000000000001430264165500204425ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/git-local/test.py000066400000000000000000000021771430264165500220020ustar00rootroot00000000000000""" Retrieve a release from a local git repository """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import compare, contents # Get the release p = run_alr('get', 'libfoo') # Check expected contents (excepting .git contents) compare(list(filter (lambda str: ".git" not in str, contents('libfoo_1.0.0_9ddda32b'))), ['libfoo_1.0.0_9ddda32b/a', 'libfoo_1.0.0_9ddda32b/alire', 'libfoo_1.0.0_9ddda32b/alire.toml', 'libfoo_1.0.0_9ddda32b/alire/alire.lock', 'libfoo_1.0.0_9ddda32b/alire/config.toml', 'libfoo_1.0.0_9ddda32b/b', 'libfoo_1.0.0_9ddda32b/b/x', 'libfoo_1.0.0_9ddda32b/b/y', 'libfoo_1.0.0_9ddda32b/b/y/p', 'libfoo_1.0.0_9ddda32b/b/y/q', 'libfoo_1.0.0_9ddda32b/b/z', 'libfoo_1.0.0_9ddda32b/c', 'libfoo_1.0.0_9ddda32b/config', 'libfoo_1.0.0_9ddda32b/config/libfoo_config.ads', 'libfoo_1.0.0_9ddda32b/config/libfoo_config.gpr', 'libfoo_1.0.0_9ddda32b/config/libfoo_config.h' ]) print('SUCCESS') alire-1.2.1/testsuite/tests/get/git-local/test.yaml000066400000000000000000000001101430264165500222750ustar00rootroot00000000000000driver: python-script indexes: git_index: in_fixtures: true alire-1.2.1/testsuite/tests/get/indirect-link/000077500000000000000000000000001430264165500213235ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/indirect-link/my_index/000077500000000000000000000000001430264165500231375ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/000077500000000000000000000000001430264165500242465ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/index.toml000066400000000000000000000000201430264165500262420ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/ti/000077500000000000000000000000001430264165500246625ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/ti/tier1/000077500000000000000000000000001430264165500257065ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/ti/tier1/tier1-1.0.0.toml000066400000000000000000000003201430264165500302540ustar00rootroot00000000000000description = "top-level crate" name = "tier1" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["john@doe.com"] maintainers-logins = ["mylogin"] [[depends-on]] tier2 = "*" [origin] url = "file:." alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/ti/tier2/000077500000000000000000000000001430264165500257075ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/ti/tier2/tier2-1.0.0.toml000066400000000000000000000003201430264165500302560ustar00rootroot00000000000000description = "2nd-level crate" name = "tier2" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["john@doe.com"] maintainers-logins = ["mylogin"] [[depends-on]] tier3 = "*" [origin] url = "file:." alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/ti/tier3/000077500000000000000000000000001430264165500257105ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/indirect-link/my_index/index/ti/tier3/tier3-1.0.0.toml000066400000000000000000000003201430264165500302600ustar00rootroot00000000000000description = "2nd-level crate" name = "tier3" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["john@doe.com"] maintainers-logins = ["mylogin"] [[depends-on]] tier3 = "*" [origin] url = "file:." alire-1.2.1/testsuite/tests/get/indirect-link/test.py000066400000000000000000000023501430264165500226540ustar00rootroot00000000000000""" Check that an indirect dependency on a linked dir is deployed correctly """ import re import os from drivers.alr import run_alr from drivers.asserts import assert_match # The crux of this test is to have a dependency that in turn depends on a # linked dir: root -> tier1 -> tier2, where tier2 is linked or missing. # For the bug to manifest, root must already depend on tier2 when tier1 is # added. So the test adds root -> tier2, and later root -> tier1, causing: # root -> tier1 -> tier2 # â””----------------^ # This indeed does not work with alr versions pre- this PR. # Initialize root workspace run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Depend on tier2, as a linked idr os.mkdir('tier2') run_alr('with', 'tier2', '--use', 'tier2') # Add tier1 (this is where the bug manifests pre- fix) run_alr('with', 'tier1') # Verify the solution graph looks as expected p = run_alr('with', '--solve') assert_match('.*' + re.escape('Dependencies (graph):\n' ' tier1=1.0.0 --> tier2* \n' ' xxx=0.1.0-dev --> tier1=1.0.0 (^1.0.0)\n' ' xxx=0.1.0-dev --> tier2^1.0.0 ') + '.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/get/indirect-link/test.yaml000066400000000000000000000001101430264165500231560ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/get/integrity-tarballs/000077500000000000000000000000001430264165500224075ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/integrity-tarballs/test.py000066400000000000000000000007411430264165500237420ustar00rootroot00000000000000""" Test proper integrity check of a git origin """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_match import re # Get the release and check that verification took place. This, coupled # with not getting an error, means that the release verified properly: p = run_alr('-v', 'get', 'libhello=1.0.0-tarball', complain_on_error=True, quiet=False) assert_match('.*Verifying integrity.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/get/integrity-tarballs/test.yaml000066400000000000000000000000651430264165500242530ustar00rootroot00000000000000driver: python-script indexes: checked_index: {} alire-1.2.1/testsuite/tests/get/missing-deps/000077500000000000000000000000001430264165500211715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/missing-deps/test.py000066400000000000000000000012221430264165500225170ustar00rootroot00000000000000""" Retrieve a crate with a partial solution available """ import re import os from drivers.alr import run_alr from drivers.asserts import assert_match from glob import glob # Get the "hello" crate with version 3, which has missing libhello=3 dep run_alr('get', 'hello=3', force=True) os.chdir(glob('hello*')[0]) # Check missing dependency is shown as external p = run_alr('with', '--solve') assert_match('.*Dependencies \(external\):\n' ' libhello\^3\.0.*', p.out, flags=re.S) # Double-check that build fails p = run_alr('build', complain_on_error=False) assert p.status != 0, "Build should have failed" print('SUCCESS') alire-1.2.1/testsuite/tests/get/missing-deps/test.yaml000066400000000000000000000000641430264165500230340ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/get/only/000077500000000000000000000000001430264165500175505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/only/test.py000066400000000000000000000017511430264165500211050ustar00rootroot00000000000000""" Test proper working of alr get --only and other follow-up commands in such an invalid solution state """ from glob import glob import os import re from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match # Get the "hello" project and enter its directory, without solving dependencies run_alr('get', 'hello', '--only') os.chdir(glob('hello*')[0]) # Verify that it has no solution p = run_alr('with', '--solve') assert_eq('Dependencies (direct):\n' ' libhello^1.0\n' 'Dependencies (solution):\n' ' No solving attempted\n', p.out) # Verify that it has no pins p = run_alr('pin') assert_eq('There are no pins\n', p.out) # Verify that updating it fixes the solution run_alr('update') p = run_alr('with', '--solve') assert_match('.*\n' # Skip dependencies 'Dependencies \(solution\):\n' ' libhello=1\.0\.0.*\n' '.*', # Skip graph p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/get/only/test.yaml000066400000000000000000000000631430264165500214120ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/get/system-hint/000077500000000000000000000000001430264165500210535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/system-hint/test.py000066400000000000000000000013231430264165500224030ustar00rootroot00000000000000""" Test that an unavailable system is reported during get as an installation hint """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_match import re p = run_alr('get', 'libhello=0.9-test-unav-native', force=True, complain_on_error=True, quiet=False) assert_match('.*' # Skip user interaction and solution changes 'Warning: The following external dependencies' ' are unavailable within Alire:\n' 'Warning: make\*\n' 'Warning: They should be made available in the' ' environment by the user.\n' '.*', # Skip final solution summary p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/get/system-hint/test.yaml000066400000000000000000000000641430264165500227160ustar00rootroot00000000000000driver: python-script indexes: native_index: {} alire-1.2.1/testsuite/tests/get/system-unsupported/000077500000000000000000000000001430264165500225015ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/system-unsupported/test.py000066400000000000000000000014361430264165500240360ustar00rootroot00000000000000""" Test two outcomes of requesting an unavailable native package: 1) In unknown distros, say that there is no support 2) In known distros, say the package is unavailable """ from glob import glob from drivers.alr import distro_is_known, run_alr from drivers.asserts import assert_match import re # Run get on a native package and see what happens depending on platform p = run_alr('--non-interactive', 'get', '--only', 'make', complain_on_error=False, quiet=False) if distro_is_known(): assert_match(".*No source release or system package available for the " "requested crate*", p.out, flags=re.S) else: assert_match(".*cannot use system packages in unknown distribution.*", p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/get/system-unsupported/test.yaml000066400000000000000000000000631430264165500243430ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/get/unpack-in-place/000077500000000000000000000000001430264165500215365ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/get/unpack-in-place/test.py000066400000000000000000000017261430264165500230750ustar00rootroot00000000000000""" Test init command produced artifacts and options """ from drivers.alr import run_alr from drivers.asserts import assert_eq from drivers.helpers import compare, contents # Get crate from tarball and check contents run_alr('get', 'libhello=1.0.0-tarball') compare(contents('libhello_1.0.0_filesystem'), ['libhello_1.0.0_filesystem/alire', 'libhello_1.0.0_filesystem/alire.toml', 'libhello_1.0.0_filesystem/alire/alire.lock', 'libhello_1.0.0_filesystem/alire/config.toml', 'libhello_1.0.0_filesystem/config', 'libhello_1.0.0_filesystem/config/libhello_config.ads', 'libhello_1.0.0_filesystem/config/libhello_config.gpr', 'libhello_1.0.0_filesystem/config/libhello_config.h', 'libhello_1.0.0_filesystem/libhello.gpr', 'libhello_1.0.0_filesystem/src', 'libhello_1.0.0_filesystem/src/libhello.adb', 'libhello_1.0.0_filesystem/src/libhello.ads', ]) print('SUCCESS') alire-1.2.1/testsuite/tests/get/unpack-in-place/test.yaml000066400000000000000000000000651430264165500234020ustar00rootroot00000000000000driver: python-script indexes: checked_index: {} alire-1.2.1/testsuite/tests/help/000077500000000000000000000000001430264165500167405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/help/equivalent_help/000077500000000000000000000000001430264165500221255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/help/equivalent_help/test.py000066400000000000000000000017611430264165500234630ustar00rootroot00000000000000""" Check that 'alr -h ' produces same output as 'alr help command' """ import re from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_match #################################### # First check, with valid help topic p1 = run_alr('-h', 'get', quiet=False) p2 = run_alr('help', 'get', quiet=False) # Verify we got the expected help assert_match("SUMMARY\n Fetches a crate release.*", p1.out, flags=re.S) # Verify equality assert p1.out == p2.out, "Mismatch in outputs: {} != {}".format(p1.out, p2.out) ####################################### # Second check, with invalid help topic p1 = run_alr('-h', 'non_existing_command', complain_on_error=False, quiet=False) p2 = run_alr('help', 'non_existing_command', complain_on_error=False, quiet=False) # Verify we got the expected error message assert_match(".*o help found for:.*", p1.out) # Verify equality assert p1.out == p2.out, "Mismatch in outputs: {} != {}".format(p1.out, p2.out) print('SUCCESS') alire-1.2.1/testsuite/tests/help/equivalent_help/test.yaml000066400000000000000000000000261430264165500237660ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/index/000077500000000000000000000000001430264165500171175ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-action-command/000077500000000000000000000000001430264165500225345ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-action-command/my_index/000077500000000000000000000000001430264165500243505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-action-command/my_index/index/000077500000000000000000000000001430264165500254575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-action-command/my_index/index/he/000077500000000000000000000000001430264165500260535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-action-command/my_index/index/he/hello_world/000077500000000000000000000000001430264165500303655ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000004641430264165500341530ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-action-command/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[actions."case(os)".linux]] command = "should be an array of strings" type = "post-fetch" [origin] url = "file:." alire-1.2.1/testsuite/tests/index/bad-action-command/my_index/index/index.toml000066400000000000000000000000201430264165500274530ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/bad-action-command/test.py000066400000000000000000000005341430264165500240670ustar00rootroot00000000000000""" Test invalid action command """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match('ERROR:.*Loading .* actions command must' ' be an array of string\(s\)\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-action-command/test.yaml000066400000000000000000000001101430264165500243670ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/bad-config-vars/000077500000000000000000000000001430264165500220615ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-config-vars/manifest.toml000066400000000000000000000005461430264165500245710ustar00rootroot00000000000000# This manifest is a base modified and copied by the test to introduce # different invalid variable definitions. description = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." [configuration.variables] alire-1.2.1/testsuite/tests/index/bad-config-vars/my_index/000077500000000000000000000000001430264165500236755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-config-vars/my_index/index/000077500000000000000000000000001430264165500250045ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-config-vars/my_index/index/he/000077500000000000000000000000001430264165500254005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-config-vars/my_index/index/he/hello_world/000077500000000000000000000000001430264165500277125ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-config-vars/my_index/index/he/hello_world/.gitignore000066400000000000000000000000141430264165500316750ustar00rootroot00000000000000!.gitignore alire-1.2.1/testsuite/tests/index/bad-config-vars/my_index/index/index.toml000066400000000000000000000000201430264165500270000ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/bad-config-vars/test.py000066400000000000000000000160361430264165500234200ustar00rootroot00000000000000""" Test invalid crate configuration variable definitions """ import os from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import content_of def make_manifest(var_def): """ Make an hello_world manifest that include the variable definitions passed as argument. """ dst = os.path.join("my_index", "index", "he", "hello_world", "hello_world-0.1.0.toml") src = "manifest.toml" # Remove existing manifest, if any if os.path.exists(dst): os.remove(dst) with open(dst, 'w') as f: f.write(content_of(src)) f.write(var_def) def check_error(var_def, expected): make_manifest(var_def) p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match('ERROR:.*' + expected + '\n', p.out) def check_ok(var_def): make_manifest(var_def) p = run_alr('show', 'hello_world', complain_on_error=True, debug=False, quiet=True) os.remove(os.path.join("my_index", "index", "he", "hello_world", ".gitignore")) check_error('var1=["plop"]', 'variable definition must be a table') check_error('var1={}', "configuration.variables.var1:") check_error('var1={}', "'type' missing") check_error('var1={type=42}', "'type' must be string") check_error('var1={type=""}', "Invalid configuration type ''," " must be \(real, integer, string," " enum or boolean\)") check_error('var1={type="test"}', "Invalid configuration type 'test'.*") check_error('var1={type="String", plop="test"}', "forbidden extra entries: plop") # String check_ok('var1={type="String"}') check_ok('var1={type="String", default="test"}') check_error('var1={type="String", first="test"}', "forbidden extra entries: first") check_error('var1={type="String", last="test"}', "forbidden extra entries: last") check_error('var1={type="String", values="test"}', "forbidden extra entries: values") expected = "invalid default value for String" check_error('var1={type="String", default=42}', expected) check_error('var1={type="String", default=42.0}', expected) check_error('var1={type="String", default=false}', expected) check_error('var1={type="String", default=["test"]}', expected) check_error('var1={type="String", default={plop="test"}}', expected) # Boolean check_ok('var1={type="Boolean"}') check_ok('var1={type="Boolean", default=true}') check_ok('var1={type="Boolean", default=false}') check_error('var1={type="Boolean", first=true}', "forbidden extra entries: first") check_error('var1={type="Boolean", last=true}', "forbidden extra entries: last") check_error('var1={type="Boolean", values=true}', "forbidden extra entries: values") expected = "invalid default value for Boolean" check_error('var1={type="Boolean", default=42}', expected) check_error('var1={type="Boolean", default=42.0}', expected) check_error('var1={type="Boolean", default="false"}', expected) check_error('var1={type="Boolean", default=["test"]}', expected) check_error('var1={type="Boolean", default={plop="test"}}', expected) # Integer check_ok('var1={type="Integer"}') check_ok('var1={type="Integer", default=42}') check_ok('var1={type="Integer", default=9223372036854775807}') check_ok('var1={type="Integer", default=-9223372036854775808}') check_ok('var1={type="Integer", first=0}') check_ok('var1={type="Integer", last=10}') check_ok('var1={type="Integer", first=0, last=10}') check_ok('var1={type="Integer", first=0, last=10, default=5}') check_error('var1={type="Integer", values=0}', "forbidden extra entries: values") expected = "invalid default value for Integer range .* \.\. .*" check_error('var1={type="Integer", first=0, default=-1}', expected) check_error('var1={type="Integer", last=0, default=1}', expected) check_error('var1={type="Integer", first=0, last=10, default=20}', expected) check_error('var1={type="Integer", default="42"}', expected) check_error('var1={type="Integer", default=42.0}', expected) check_error('var1={type="Integer", default=false}', expected) check_error('var1={type="Integer", default=["test"]}', expected) check_error('var1={type="Integer", default={plop="test"}}', expected) # Real check_ok('var1={type="Real"}') check_ok('var1={type="Real", default=42.0}') check_ok('var1={type="Real", default=4.9406564584124654e-324}') check_ok('var1={type="Real", default=1.7976931348623157e+308}') check_ok('var1={type="Real", first=0.0}') check_ok('var1={type="Real", last=10.0}') check_ok('var1={type="Real", first=0.0, last=10.0}') check_ok('var1={type="Real", first=0.0, last=10.0, default=5.0}') expected = "'first' cannot be NaN" check_error('var1={type="Real", first=nan}', expected) check_error('var1={type="Real", first=+nan}', expected) check_error('var1={type="Real", first=-nan}', expected) expected = "'last' cannot be NaN" check_error('var1={type="Real", last=nan}', expected) check_error('var1={type="Real", last=+nan}', expected) check_error('var1={type="Real", last=-nan}', expected) check_error('var1={type="Real", values=0}', "forbidden extra entries: values") expected = "invalid default value for Real range .* \.\. .*" check_error('var1={type="Real", first=0.0, default=-1.0}', expected) check_error('var1={type="Real", last=0.0, default=1.0}', expected) check_error('var1={type="Real", first=0.0, last=10.0, default=20.0}', expected) check_error('var1={type="Real", default=nan}', expected) check_error('var1={type="Real", default=+nan}', expected) check_error('var1={type="Real", default=-nan}', expected) check_error('var1={type="Real", default=inf}', expected) check_error('var1={type="Real", default=+inf}', expected) check_error('var1={type="Real", default=-inf}', expected) check_error('var1={type="Real", default=42}', expected) check_error('var1={type="Real", default="42.0"}', expected) check_error('var1={type="Real", default=false}', expected) check_error('var1={type="Real", default=["test"]}', expected) check_error('var1={type="Real", default={plop="test"}}', expected) # Enum check_ok('var1={type="Enum", values=["A"]}') check_ok('var1={type="Enum", values=["A"], default="A"}') check_ok('var1={type="Enum", values=["A", "B"]}') check_ok('var1={type="Enum", values=["A", "B"], default="B"}') check_error('var1={type="Enum", values=["A"], first="test"}', "forbidden extra entries: first") check_error('var1={type="Enum", values=["A"], last="test"}', "forbidden extra entries: last") check_error('var1={type="Enum", values=[]}', "'values' must be a not empty array of strings") check_error('var1={type="Enum"}', "missing 'values' for enumeration type") expected = "invalid default value for Enum \(A, B\)" check_error('var1={type="Enum", values=["A", "B"], default="C"}', expected) check_error('var1={type="Enum", values=["A", "B"], default=42}', expected) check_error('var1={type="Enum", values=["A", "B"], default=42.0}', expected) check_error('var1={type="Enum", values=["A", "B"], default=false}', expected) check_error('var1={type="Enum", values=["A", "B"], default=["test"]}', expected) check_error('var1={type="Enum", values=["A", "B"], default={plop="test"}}', expected) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-config-vars/test.yaml000066400000000000000000000001101430264165500237140ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/bad-external-regex/000077500000000000000000000000001430264165500225755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-external-regex/my_index/000077500000000000000000000000001430264165500244115ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-external-regex/my_index/index/000077500000000000000000000000001430264165500255205ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-external-regex/my_index/index/ba/000077500000000000000000000000001430264165500261025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-external-regex/my_index/index/ba/bad_regex/000077500000000000000000000000001430264165500300225ustar00rootroot00000000000000bad_regex-external.toml000066400000000000000000000004441430264165500344020ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-external-regex/my_index/index/ba/bad_regexdescription = "An external with bad switches" name = "bad_regex" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[external]] kind = "version-output" version-regexp = "*" # No char before * is improper version-command = ["make", "--version"] alire-1.2.1/testsuite/tests/index/bad-external-regex/my_index/index/index.toml000066400000000000000000000000201430264165500275140ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/bad-external-regex/test.py000066400000000000000000000004751430264165500241340ustar00rootroot00000000000000""" Check regex validation on index loading """ from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match import re p = run_alr("index", "--check", complain_on_error=False) assert p.status != 0, "unexpected success" assert_match(".*invalid regular expression.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-external-regex/test.yaml000066400000000000000000000001101430264165500244300ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/bad-index-metadata/000077500000000000000000000000001430264165500225305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-index-metadata/my_index/000077500000000000000000000000001430264165500243445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-index-metadata/my_index/index/000077500000000000000000000000001430264165500254535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-index-metadata/my_index/index/index.toml000066400000000000000000000000531430264165500274550ustar00rootroot00000000000000version = "1.1" badkey = "sneaking around" alire-1.2.1/testsuite/tests/index/bad-index-metadata/test.py000066400000000000000000000004421430264165500240610ustar00rootroot00000000000000""" Test that no alien fields appear in index metadata """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr("search", "--crates", complain_on_error=False) assert_match( '.*index metadata contains unexpected fields.*', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-index-metadata/test.yaml000066400000000000000000000001101430264165500243630ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/bad-index-version/000077500000000000000000000000001430264165500224355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-index-version/my_index/000077500000000000000000000000001430264165500242515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-index-version/my_index/index/000077500000000000000000000000001430264165500253605ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-index-version/my_index/index/index.toml000066400000000000000000000000201430264165500273540ustar00rootroot00000000000000version = "0.0" alire-1.2.1/testsuite/tests/index/bad-index-version/test.py000066400000000000000000000004311430264165500237640ustar00rootroot00000000000000""" Test that mismatched index version is detected """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr("search", "--crates", complain_on_error=False) assert_match( '.*index version \(0\.0\.0\) is too old.*', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-index-version/test.yaml000066400000000000000000000001101430264165500242700ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/bad-license-too-long/000077500000000000000000000000001430264165500230215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license-too-long/my_index/000077500000000000000000000000001430264165500246355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license-too-long/my_index/index/000077500000000000000000000000001430264165500257445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license-too-long/my_index/index/he/000077500000000000000000000000001430264165500263405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license-too-long/my_index/index/he/hello_world/000077500000000000000000000000001430264165500306525ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000005541430264165500344400ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license-too-long/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((MIT))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))" maintainers = ["Mr. User "] maintainers-logins = ["user"] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/bad-license-too-long/my_index/index/index.toml000066400000000000000000000000201430264165500277400ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/bad-license-too-long/test.py000066400000000000000000000006241430264165500243540ustar00rootroot00000000000000""" Test that long licenses are rejected """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match('.*Loading .*hello_world-0.1.0.toml:' '.*licenses:.*License expression too long \(must be no more than [0-9]* chars\)\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-license-too-long/test.yaml000066400000000000000000000001101430264165500246540ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/bad-license/000077500000000000000000000000001430264165500212655ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license/my_index/000077500000000000000000000000001430264165500231015ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license/my_index/index/000077500000000000000000000000001430264165500242105ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license/my_index/index/he/000077500000000000000000000000001430264165500246045ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license/my_index/index/he/hello_world/000077500000000000000000000000001430264165500271165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-license/my_index/index/he/hello_world/hello_world-0.1.0.toml000066400000000000000000000003501430264165500327550ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "MIT OR (MIT AND MIT" maintainers = ["Mr. User "] maintainers-logins = ["user"] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/bad-license/my_index/index/index.toml000066400000000000000000000000201430264165500262040ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/bad-license/test.py000066400000000000000000000006211430264165500226150ustar00rootroot00000000000000""" Test that invalid licenses are rejected """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match('.*Loading .*hello_world-0.1.0.toml:' '.*licenses:.*Invalid license expression .* Missing closing parentheses.*\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-license/test.yaml000066400000000000000000000001101430264165500231200ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/bad-name/000077500000000000000000000000001430264165500205635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-name/test.py000066400000000000000000000004761430264165500221230ustar00rootroot00000000000000""" Check that specifying a malformed index name is properly reported """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('index', '--add', 'xx', '--name', 'xx', complain_on_error=False, debug=False) assert_match('.*Identifier too short.*', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-name/test.yaml000066400000000000000000000000261430264165500224240ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/index/bad-tag/000077500000000000000000000000001430264165500204165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-tag/my_index/000077500000000000000000000000001430264165500222325ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-tag/my_index/index/000077500000000000000000000000001430264165500233415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-tag/my_index/index/he/000077500000000000000000000000001430264165500237355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-tag/my_index/index/he/hello_world/000077500000000000000000000000001430264165500262475ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-tag/my_index/index/he/hello_world/hello_world-0.1.0.toml000066400000000000000000000003601430264165500321070ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] tags = ["invalid_tag"] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/bad-tag/my_index/index/index.toml000066400000000000000000000000201430264165500253350ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/bad-tag/test.py000066400000000000000000000005461430264165500217540ustar00rootroot00000000000000""" Test invalid characters in a tag are rejected """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match( '.*Loading .*hello_world-0.1.0.toml:.*tags:' '.*Tag string is not valid: .*\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-tag/test.yaml000066400000000000000000000001101430264165500222510ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/bad-underscore/000077500000000000000000000000001430264165500220145ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-underscore/my_index/000077500000000000000000000000001430264165500236305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-underscore/my_index/index/000077500000000000000000000000001430264165500247375ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-underscore/my_index/index/he/000077500000000000000000000000001430264165500253335ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-underscore/my_index/index/he/hello_world/000077500000000000000000000000001430264165500276455ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000004561430264165500334340ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/bad-underscore/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[depends_on]] # This is wrong, as it should be depends-on (notice dash/underscore) [origin] url = "file:." alire-1.2.1/testsuite/tests/index/bad-underscore/my_index/index/index.toml000066400000000000000000000000201430264165500267330ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/bad-underscore/test.py000066400000000000000000000006241430264165500233470ustar00rootroot00000000000000""" Test underscores are properly rejected in property keys """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match( ".*TOML keys should use hyphens instead of underscores," " but found key: depends_on.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/bad-underscore/test.yaml000066400000000000000000000001101430264165500236470ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/branch-mismatch/000077500000000000000000000000001430264165500221575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/branch-mismatch/community/000077500000000000000000000000001430264165500242035ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/branch-mismatch/community/index/000077500000000000000000000000001430264165500253125ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/branch-mismatch/community/index/index.toml000066400000000000000000000000201430264165500273060ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/branch-mismatch/test.py000066400000000000000000000023561430264165500235160ustar00rootroot00000000000000""" Test that a mismatched branch in the community index is detected """ from drivers.alr import run_alr from drivers.asserts import assert_match import os # Initialize a git repo in the index location, so it returns a 'master' branch # To do so, first retrieve the index location in the test config p = run_alr('index', '--list') location = p.out.split()[7] # To avoid git complaints about missing info gitconfig = '-c user.name="Fubar Snafu" -c user.email="fubar@snafu.org"' # Create master branch by adding the files in the index start = os.getcwd() os.chdir(location) os.system('git ' + gitconfig + ' init -q .') os.system('git ' + gitconfig + ' add .') os.system('git ' + gitconfig + ' commit -q -m initialize') os.chdir(start) # Enable the warning we are trying to test run_alr("config", "--global", "--set", "warning.old_index", "true") # Run the test. No alr version should use 'master' for the community index. # This produces a warning only, because the index version is valid. p = run_alr("search", "--crates", # Causes loading of the index quiet=False) assert_match(".*This alr build expects an index branch with prefix '.*'" " but your community index branch is 'master'.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/branch-mismatch/test.yaml000066400000000000000000000001111430264165500240130ustar00rootroot00000000000000driver: python-script indexes: community: in_fixtures: false alire-1.2.1/testsuite/tests/index/case-expressions/000077500000000000000000000000001430264165500224125ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/case-expressions/test.py000066400000000000000000000036261430264165500237520ustar00rootroot00000000000000""" Test the loading of case expressions without resolving them. """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import host_architecture import re import platform p = run_alr('show', 'hello') # If the index loads without complaints we are already in promising territory. # Check a few substrings for more certainty: # Available assert_match(".*Available when: .case OS is Linux => True, " "Windows => \(case Word_Size is Bits_64 => True, others => False\)" ", others => False.*", p.out, flags=re.S) # Properties assert_match(".*case Word_Size is .* when Bits_32 => Executable: hello32.*", p.out, flags=re.S) assert_match(".*case OS is .* when Linux => GPR External: OS := linux.*", p.out, flags=re.S) # Dependencies assert_match(".*Dependencies .direct.:.*case OS is.*when Linux => libhello\^1.*", p.out, flags=re.S) # Check that evaluation for the current platform does work p = run_alr('show', 'hello', '--system') # And that, once resolved, the expected property is there: if platform.system() == 'Windows': assert_match(".*GPR External: OS := windows.*", p.out, flags=re.S) elif platform.system() == 'Darwin': assert_match(".*GPR External: OS := macos.*", p.out, flags=re.S) else: assert_match(".*GPR External: OS := linux.*", p.out, flags=re.S) assert_match(".*GPR External: HOST_ARCH := " + host_architecture() + ".*", p.out, flags=re.S) # Check that a case given as "x|y" is properly loaded and shown p = run_alr("show", "hello=0.9") assert_match( '.*' 'Properties:\n' ' Description: "Hello, world!" demonstration project\n' ' case OS is\n' ' when Linux => Executable: hello\n' ' when Windows => Executable: hello\n' '.*', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/case-expressions/test.yaml000066400000000000000000000002231430264165500242520ustar00rootroot00000000000000driver: python-script indexes: cases_index: {} # CAVEAT: for some funny Python reason, a folder named 'case_*' breaks # the testsuite. alire-1.2.1/testsuite/tests/index/check-enums/000077500000000000000000000000001430264165500213215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/check-enums/my_index/000077500000000000000000000000001430264165500231355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/check-enums/my_index/crates/000077500000000000000000000000001430264165500244165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/check-enums/my_index/crates/crate/000077500000000000000000000000001430264165500255145ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/check-enums/my_index/crates/crate/.emptydir000066400000000000000000000000001430264165500273400ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/check-enums/my_index/index/000077500000000000000000000000001430264165500242445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/check-enums/my_index/index/cr/000077500000000000000000000000001430264165500246505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/check-enums/my_index/index/cr/crate/000077500000000000000000000000001430264165500257465ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/check-enums/my_index/index/cr/crate/crate-1.0.0.toml000066400000000000000000000004011430264165500303660ustar00rootroot00000000000000description = "Sample crate" name = "crate" version = "1.0.0" licenses = [] maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] url = "file:../../../crates/crate" [available.'case(distribution)'] ubuntu = true nonexistent-distro = false alire-1.2.1/testsuite/tests/index/check-enums/my_index/index/index.toml000066400000000000000000000000201430264165500262400ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/check-enums/test.py000066400000000000000000000016051430264165500226540ustar00rootroot00000000000000""" Check behavior of unknown enum values in manifests """ from drivers.alr import run_alr from drivers.asserts import assert_match import glob import os # Verify that we can list the index, despite containing an unknown distro value run_alr("search", "--crates") # Verify that checking the index strictly does fail p = run_alr("index", "--check", complain_on_error=False) assert_match(".*invalid enumeration value:.*", p.out) # Verify that we can retrieve and load such a crate's manifest run_alr("get", "crate") os.chdir(glob.glob("crate_*")[0]) run_alr("show") # Verify that adding bad values to our local manifest won't slip by with open("alire.toml", "at") as manifest: manifest.write(""" [available.'case(distribution)'] ubuntu = true nonexistent-distro = false\n""") p = run_alr("show", complain_on_error=False) assert_match(".*invalid enumeration value:.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/check-enums/test.yaml000066400000000000000000000001101430264165500231540ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/custom-action/000077500000000000000000000000001430264165500217045ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/custom-action/test.py000066400000000000000000000035441430264165500232430ustar00rootroot00000000000000""" Check loading of custom actions and related changes """ from drivers.alr import run_alr, init_local_crate, alr_manifest, add_action from drivers.asserts import assert_eq, assert_match from os import chdir from shutil import rmtree import re def bad_action_check(type, command, name, error_re): # Test in new crate as the manifest is going to be broken init_local_crate("abc") add_action(type=type, command=command, name=name) p = run_alr("show", complain_on_error=False) assert p.status != 0, "Unexpected success" assert_match(error_re, p.out) chdir("..") rmtree("abc") init_local_crate() # Add a proper custom action and verify its loading add_action(type="on-demand", name="my-action", command=["ls"]) p = run_alr("show") assert_match(".*" + re.escape("On_Demand (my-action) run: ${CRATE_DIR}/./ls"), p.out) # Verify that regular action can also have a name add_action(type="post-fetch", name="action-2", command=["ls"]) p = run_alr("show") assert_match(".*" + re.escape("Post_Fetch (action-2) run: ${CRATE_DIR}/./ls"), p.out) # Add an on-demand action without name and see it fails bad_action_check(type="on-demand", command=["ls"], name="", error_re=".*on-demand actions require a name") # Bad names bad_action_check(type="on-demand", command=["ls"], name="2nd-action", error_re=".*Offending name is") bad_action_check(type="on-demand", command=["ls"], name="bad--action", error_re=".*Offending name is") bad_action_check(type="on-demand", command=["ls"], name="-action", error_re=".*Offending name is") bad_action_check(type="on-demand", command=["ls"], name="action-", error_re=".*Offending name is") bad_action_check(type="on-demand", command=["ls"], name="x", error_re=".*Offending name is") print('SUCCESS') alire-1.2.1/testsuite/tests/index/custom-action/test.yaml000066400000000000000000000000631430264165500235460ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/index/empty-dependency-case/000077500000000000000000000000001430264165500233025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/empty-dependency-case/test.py000066400000000000000000000011371430264165500246350ustar00rootroot00000000000000""" Test that an empty nested table in dependencies does not cause an error. Bugfix #906: https://github.com/alire-project/alire/pull/906 """ from drivers.alr import run_alr, init_local_crate, alr_manifest from drivers.asserts import assert_match init_local_crate() # Create the problematic table with open(alr_manifest(), "at") as manifest: manifest.write("[[depends-on]]\n") manifest.write("[depends-on.'case(os)'.linux." "'case(distribution)'.ubuntu]\n") # The following command failed pre-bugfix, all is OK if it does not complain p = run_alr("update") print('SUCCESS') alire-1.2.1/testsuite/tests/index/empty-dependency-case/test.yaml000066400000000000000000000000631430264165500251440ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/index/empty-tag/000077500000000000000000000000001430264165500210265ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/empty-tag/my_index/000077500000000000000000000000001430264165500226425ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/empty-tag/my_index/index/000077500000000000000000000000001430264165500237515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/empty-tag/my_index/index/he/000077500000000000000000000000001430264165500243455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/empty-tag/my_index/index/he/hello_world/000077500000000000000000000000001430264165500266575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/empty-tag/my_index/index/he/hello_world/hello_world-0.1.0.toml000066400000000000000000000003451430264165500325220ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] tags = [""] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/empty-tag/my_index/index/index.toml000066400000000000000000000000201430264165500257450ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/empty-tag/test.py000066400000000000000000000005131430264165500223560ustar00rootroot00000000000000""" Test that empty tags are rejected """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match( '.*Loading .*hello_world-0.1.0.toml:.*tags:.*Tag string is empty\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/empty-tag/test.yaml000066400000000000000000000001101430264165500226610ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/environment/000077500000000000000000000000001430264165500214635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/environment/my_index/000077500000000000000000000000001430264165500232775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/environment/my_index/index/000077500000000000000000000000001430264165500244065ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/environment/my_index/index/he/000077500000000000000000000000001430264165500250025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/environment/my_index/index/he/hello/000077500000000000000000000000001430264165500261055ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/environment/my_index/index/he/hello/hello-1.0.0.toml000066400000000000000000000012411430264165500305350ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [environment.VAR1] append = "abc" [environment.VAR2] prepend = "xyz" [environment.VAR3] set = "pqr" [environment.VAR4] set = "${_ALIRE_TEST_}" [environment.VAR5] set = "${_ALIRE_TEST_" [environment.VAR6] set = "\\${_ALIRE_TEST_}" [environment.VAR7] set = "abc${_ALIRE_TEST_}abc" [environment.VAR8] set = "abc\\${_ALIRE_TEST_}abc" [environment.VAR9] set = "${_ALIRE_TEST_}${_ALIRE_TEST_}${_ALIRE_TEST_}" [environment."case(os)"."...".CONDVAR] set = "uvw" [origin] url = "file:." alire-1.2.1/testsuite/tests/index/environment/my_index/index/index.toml000066400000000000000000000000201430264165500264020ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/environment/test.py000066400000000000000000000032211430264165500230120ustar00rootroot00000000000000""" Test proper loading of environment properties """ from drivers.alr import run_alr from drivers.asserts import assert_match from glob import glob import re import os # With conditionals p = run_alr('show', 'hello') assert_match('.*' ' when others => Environment: CONDVAR=uvw\n' '.*' ' Environment: VAR1=\${VAR1}:abc\n' ' Environment: VAR2=xyz:\${VAR2}\n' ' Environment: VAR3=pqr\n' ' Environment: VAR4=\${_ALIRE_TEST_}\n' ' Environment: VAR5=\${_ALIRE_TEST_\n' ' Environment: VAR6=\\\\\${_ALIRE_TEST_}\n' ' Environment: VAR7=abc\${_ALIRE_TEST_}abc\n' ' Environment: VAR8=abc\\\\\${_ALIRE_TEST_}abc\n' ' Environment: VAR9=\${_ALIRE_TEST_}\${_ALIRE_TEST_}\${_ALIRE_TEST_}\n' '.*', p.out, flags=re.S) # Check resolved conditional p = run_alr('show', 'hello', '--system') assert_match('.*' ' Environment: CONDVAR=uvw\n' '.*', p.out, flags=re.S) # Check environment variable formatting run_alr('get', 'hello') os.chdir(glob('hello*')[0]) p = run_alr('printenv', '--unix') assert_match('.*' 'export VAR1="abc"\n' 'export VAR2="xyz"\n' 'export VAR3="pqr"\n' 'export VAR4="TEST"\n' 'export VAR5="\${_ALIRE_TEST_"\n' 'export VAR6="\\\\\${_ALIRE_TEST_}"\n' 'export VAR7="abcTESTabc"\n' 'export VAR8="abc\\\\\${_ALIRE_TEST_}abc"\n' 'export VAR9="TESTTESTTEST"\n' '.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/environment/test.yaml000066400000000000000000000001101430264165500233160ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/external-available/000077500000000000000000000000001430264165500226575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-available/my_index/000077500000000000000000000000001430264165500244735ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-available/my_index/cr/000077500000000000000000000000001430264165500250775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-available/my_index/cr/crate/000077500000000000000000000000001430264165500261755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-available/my_index/cr/crate/crate-external.toml000066400000000000000000000004661430264165500320160ustar00rootroot00000000000000description = "A crate" name = "crate" licenses = "GPL-3.0-only" maintainers = ["somebody@somewhere.com"] maintainers-logins = ["mylogin"] [[external]] kind = "version-output" version-regexp = ".*Make ([\\d\\.]+).*" version-command = ["make", "--version"] [external.available."case(toolchain)"] "..." = false alire-1.2.1/testsuite/tests/index/external-available/my_index/index.toml000066400000000000000000000000201430264165500264670ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/external-available/test.py000066400000000000000000000016321430264165500242120ustar00rootroot00000000000000""" Test use of the available field in externals """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_match import re import platform # 1st test: showing available information on all platforms p = run_alr('show', 'crate', '--external') assert_match(".*Executable make --version .*" "(case Toolchain is others => False).*", p.out, flags=re.S) # 2nd test: showing available information on current platform p = run_alr('show', 'crate', '--external', '--system') assert_match(".*Executable make --version .* False.*", p.out, flags=re.S) # 3rd test: crate is not detected because it is unavailable. It would be # detectable otherwise (make is installed in all test images) p = run_alr('--no-tty', 'show', 'crate', '--external-detect', quiet=False) assert_match("Not found: crate\*.*", p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/external-available/test.yaml000066400000000000000000000001101430264165500245120ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/external-from-output/000077500000000000000000000000001430264165500232405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-from-output/my_index/000077500000000000000000000000001430264165500250545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-from-output/my_index/index/000077500000000000000000000000001430264165500261635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-from-output/my_index/index/ba/000077500000000000000000000000001430264165500265455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-from-output/my_index/index/ba/bad_switch/000077500000000000000000000000001430264165500306545ustar00rootroot00000000000000bad_switch-external.toml000066400000000000000000000004501430264165500354200ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-from-output/my_index/index/ba/bad_switchdescription = "An external with bad switches" name = "bad_switch" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[external]] kind = "version-output" version-regexp = ".*Make ([\\d\\.]+).*" version-command = ["make", "--bad-nonexistent-switch"] alire-1.2.1/testsuite/tests/index/external-from-output/my_index/index/index.toml000066400000000000000000000000201430264165500301570ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/external-from-output/my_index/index/ma/000077500000000000000000000000001430264165500265605ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-from-output/my_index/index/ma/make/000077500000000000000000000000001430264165500274755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-from-output/my_index/index/ma/make/make-external.toml000066400000000000000000000004271430264165500331320ustar00rootroot00000000000000description = "Utility for directing compilation" name = "make" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[external]] kind = "version-output" version-regexp = ".*Make ([\\d\\.]+).*" version-command = ["make", "--version"] alire-1.2.1/testsuite/tests/index/external-from-output/test.py000066400000000000000000000033471430264165500246000ustar00rootroot00000000000000""" Test detection of tools in path via external """ from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match import re # Hint that an external exists p = run_alr('show', 'make', complain_on_error=False, quiet=False) assert_eq('Not found: make*\n' 'There are external definitions for the crate. ' 'Use --external to show them.\n', p.out) # External definition p = run_alr('show', 'make', '--external') assert_eq('Kind Description Details Available\n' 'Executable make --version .*Make ([\\d\\.]+).* True \n', p.out) # External detection p = run_alr('show', 'make', '--external-detect') assert_match('make=.*: Utility for directing compilation\n' 'Notes: Detected at .*make(\.exe)?\n' 'Origin: external path .*make(\.exe)?\n', p.out, flags=re.S) # Verify that an invalid command does not crash Alire. We don't want different # behaviors in different platforms to unsuspectedly break users on an index # update. p = run_alr("show", "bad_switch", quiet=False) assert p.status == 0, "unexpected exit with error" assert_match(".*There are external definitions for the crate.", p.out) # External definition check (crate is actually there) p = run_alr('show', 'bad_switch', '--external') assert_eq('Kind Description ' 'Details Available\n' 'Executable make --bad-nonexistent-switch ' '.*Make ([\\d\\.]+).* True \n', p.out) # External detection fails (no release found, but without error) p = run_alr('show', 'bad_switch', '--external-detect', quiet=False) assert_match('.*Not found: bad_switch', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/external-from-output/test.yaml000066400000000000000000000001101430264165500250730ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/external-hint/000077500000000000000000000000001430264165500217015ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-hint/my_index/000077500000000000000000000000001430264165500235155ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-hint/my_index/cr/000077500000000000000000000000001430264165500241215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-hint/my_index/cr/crate/000077500000000000000000000000001430264165500252175ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-hint/my_index/cr/crate/crate-external.toml000066400000000000000000000004111430264165500310260ustar00rootroot00000000000000description = "A crate" name = "crate" licenses = "GPL-3.0-only" maintainers = ["somebody@somewhere.com"] maintainers-logins = ["mylogin"] [[external]] kind = "hint" [external.hint."case(toolchain)"] system = "This is a custom hint" user = "This is a custom hint" alire-1.2.1/testsuite/tests/index/external-hint/my_index/cr/crate_master/000077500000000000000000000000001430264165500265725ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-hint/my_index/cr/crate_master/crate_master-1.0.0.toml000066400000000000000000000006471430264165500326010ustar00rootroot00000000000000description = "A crate with a dependency" name = "crate_master" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["somebody@somewhere.com"] maintainers-logins = ["mylogin"] [[depends-on]] crate = "any" [origin] url = "file://../../../crates/noop_1.0-default.tgz" hashes = ["sha512:de676fbda9f16ba98fe1adc80e20dbd9b98a86352267825b55f1d719570adc0f92f1be2e96fd3df06aac4f6b5fee8686695e315be370cabe482edefc5a0570c5"] alire-1.2.1/testsuite/tests/index/external-hint/my_index/index.toml000066400000000000000000000000201430264165500255110ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/external-hint/test.py000066400000000000000000000032511430264165500232330ustar00rootroot00000000000000""" Test the hinting with custom text in external definitions """ from glob import glob from drivers.alr import distro_is_known, run_alr from drivers.asserts import assert_eq, assert_match import re import platform # 1st test: directly attempting to retrieve an external (this is doable for # system externals in supported platforms -- never in this test). Depending on # whether the distro has a supported package manager we get two outcomes: p = run_alr('get', 'crate', quiet=False, complain_on_error=False) if distro_is_known(): assert_match(".*Hint: This is a custom hint.*", p.out, flags=re.S) else: assert_eq('ERROR: No source release indexed for the requested crate, and ' 'cannot use system packages in unknown distribution\n', p.out) # 2nd test: hint is displayed when the hint belongs to a dependency, on get p = run_alr('get', 'crate_master', force=True, quiet=False) assert_match (".*" # Skip previous user interaction and warning about incomplete solution "Warning: The following native dependencies are unavailable within Alire:\n" "Warning: crate\*\n" "Warning: Hint: This is a custom hint\n" "Warning: They should be made available in the environment by the user.\n", p.out) # 3rd test: hint is displayed when showing the crate info p = run_alr('show', 'crate_master', '--solve', '--system', quiet=False) assert_match(".*" # Skip previous crate info "Dependencies \(external\):\n" " crate\* \(direct,hinted\)\n" " Hint: This is a custom hint\n" "Dependencies \(graph\):\n" ".*", # Skip solution graph p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/external-hint/test.yaml000066400000000000000000000001461430264165500235450ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/index/external-msys2/000077500000000000000000000000001430264165500220145ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-msys2/my_index/000077500000000000000000000000001430264165500236305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-msys2/my_index/di/000077500000000000000000000000001430264165500242245ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-msys2/my_index/di/dialog/000077500000000000000000000000001430264165500254635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-msys2/my_index/di/dialog/dialog-external.toml000066400000000000000000000003531430264165500314400ustar00rootroot00000000000000description = "Just for the test" name = "dialog" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mosteo"] [[external]] kind = "system" [external.origin."case(distribution)"] msys2 = ["dialog"] alire-1.2.1/testsuite/tests/index/external-msys2/my_index/index.toml000066400000000000000000000000201430264165500256240ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/external-msys2/my_index/ma/000077500000000000000000000000001430264165500242255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-msys2/my_index/ma/main/000077500000000000000000000000001430264165500251515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-msys2/my_index/ma/main/main-1.0.0.toml000066400000000000000000000007671430264165500274360ustar00rootroot00000000000000description = "Main program" name = "main" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [[depends-on]] dialog = "*" [[actions."case(os)".windows]] type = "post-fetch" command = ["bash", "-c", "uname && dialog --help"] [origin] url = "file://./../../../crates/noop_1.0-default.tgz" hashes = ["sha512:de676fbda9f16ba98fe1adc80e20dbd9b98a86352267825b55f1d719570adc0f92f1be2e96fd3df06aac4f6b5fee8686695e315be370cabe482edefc5a0570c5"] alire-1.2.1/testsuite/tests/index/external-msys2/test.py000066400000000000000000000010751430264165500233500ustar00rootroot00000000000000""" Test that installing msys2 dependency work as expected. """ from drivers.alr import run_alr import platform if platform.system() == 'Windows': # Should silently retrieve everything p = run_alr('--non-interactive', '-v', 'get', 'main', quiet=False, debug=True) checks = 0 for line in p.out.splitlines(): if line.startswith("cdialog (ComeOn Dialog!) version "): print("dialog output matched") checks += 1 assert checks == 1, 'Only %d match in the output : "%s"' % (checks, p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/external-msys2/test.yaml000066400000000000000000000001461430264165500236600ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/index/external-unindexed/000077500000000000000000000000001430264165500227225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-unindexed/my_index/000077500000000000000000000000001430264165500245365ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-unindexed/my_index/index/000077500000000000000000000000001430264165500256455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-unindexed/my_index/index/he/000077500000000000000000000000001430264165500262415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-unindexed/my_index/index/he/hello_world/000077500000000000000000000000001430264165500305535ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000006671430264165500343460ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-unindexed/my_index/index/he/hello_worlddescription = "This is the regular short description" long-description = "This is the long crate description.\n\nThis can be a multiline string, and TOML parsers are free to use the platform end-of-line character during loading.\n" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "http://blah.com/pkg.zip" hashes = ["sha512:deadbeef"] hello_world-external.toml000066400000000000000000000005721430264165500355270ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/external-unindexed/my_index/index/he/hello_worlddescription = "This is the regular short description" long-description = "This is the long crate description.\n\nThis can be a multiline string, and TOML parsers are free to use the platform end-of-line character during loading.\n" name = "hello_world" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[external]] kind = "hint" alire-1.2.1/testsuite/tests/index/external-unindexed/my_index/index/index.toml000066400000000000000000000000201430264165500276410ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/external-unindexed/test.py000066400000000000000000000017011430264165500242520ustar00rootroot00000000000000""" Test unindexed external output with show/search """ from drivers.alr import run_alr from drivers.asserts import assert_match import re p = run_alr('show', 'hello_world', '--external') assert_match('.*Hint.*' 'Externally provided.*' 'Must be provided by the user.*', p.out, flags=re.S) p = run_alr('search', 'hello_world', '--external') assert_match('.*hello_world.*' 'E\ .*' # single E means external, no detection attempted 'external.*' 'This is the regular short description.*' 'Externally provided.*', p.out, flags=re.S) p = run_alr('search', 'hello_world', '--external-detect') assert_match('.*hello_world.*' 'EU.*' # EU means external, detection failed 'external.*' 'This is the regular short description.*' 'Externally provided.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/external-unindexed/test.yaml000066400000000000000000000001101430264165500245550ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/ignore-unknown-property/000077500000000000000000000000001430264165500237615ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/ignore-unknown-property/test.py000066400000000000000000000015171430264165500253160ustar00rootroot00000000000000""" Check that unknown properties can be force-ignored """ from drivers.alr import run_alr from drivers.asserts import assert_match from os import chdir import re # Create a regular working release run_alr("init", "--bin", "xxx") chdir("xxx") # Add spurious metadata with open("alire.toml", "r") as file: lines = file.readlines() with open("alire.toml", "w") as file: file.write("fancy-new-feat = false\n") file.writelines(lines) # Verify the regular error p = run_alr('show', complain_on_error=False) assert p.status != 0, "command should have errored" assert_match(".*invalid property:.*", p.out, flags=re.S) # Verify the force-ignore p = run_alr('show', quiet=False, force=True) # Should not complain assert_match(".*Warning:.*invalid property:.*", # Should be a warning p.out, flags=re.S) print("SUCCESS") alire-1.2.1/testsuite/tests/index/ignore-unknown-property/test.yaml000066400000000000000000000001651430264165500256260ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} # Needed to prevent going online to fetch the community index alire-1.2.1/testsuite/tests/index/local-index-not-found/000077500000000000000000000000001430264165500232255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/local-index-not-found/test.py000066400000000000000000000014731430264165500245630ustar00rootroot00000000000000""" Test that Alire properly reports an invalid index URL. """ import os import re from e3.fs import rm from drivers.alr import prepare_indexes, run_alr from drivers.asserts import assert_match for d in ('no-such-directory', 'file://no-such-directory', ): rm('alr-config', recursive=True) prepare_indexes('alr-config', '.', {'bad_index': {'dir': d, 'in_fixtures': False}}) p = run_alr("search", "--crates", complain_on_error=False, debug=False) path_excerpt = os.path.join('alr-config', 'indexes', 'bad_index', 'index.toml') assert_match('ERROR: Cannot load metadata from .*{}:' ' Not a readable directory' '\n' .format(re.escape(path_excerpt)), p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/local-index-not-found/test.yaml000066400000000000000000000001571430264165500250730ustar00rootroot00000000000000driver: python-script indexes: bad_index: dir: file://no-such-directory in_fixtures: false alire-1.2.1/testsuite/tests/index/long-description/000077500000000000000000000000001430264165500223775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-description/my_index/000077500000000000000000000000001430264165500242135ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-description/my_index/index/000077500000000000000000000000001430264165500253225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-description/my_index/index/he/000077500000000000000000000000001430264165500257165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-description/my_index/index/he/hello_world/000077500000000000000000000000001430264165500302305ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000006671430264165500340230ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-description/my_index/index/he/hello_worlddescription = "This is the regular short description" long-description = "This is the long crate description.\n\nThis can be a multiline string, and TOML parsers are free to use the platform end-of-line character during loading.\n" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "http://blah.com/pkg.zip" hashes = ["sha512:deadbeef"] alire-1.2.1/testsuite/tests/index/long-description/my_index/index/index.toml000066400000000000000000000000201430264165500273160ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/long-description/test.py000066400000000000000000000007141430264165500237320ustar00rootroot00000000000000""" Test that long descriptions are accepted """ from drivers.alr import run_alr from drivers.asserts import assert_match import re p = run_alr('show', 'hello_world') assert_match('.*Long_Description: This is the long crate description.\n' '\n' 'This can be a multiline string, and TOML parsers are free to use' ' the platform end-of-line character during loading.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/long-description/test.yaml000066400000000000000000000001101430264165500242320ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/long-tag/000077500000000000000000000000001430264165500206275ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-tag/my_index/000077500000000000000000000000001430264165500224435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-tag/my_index/index/000077500000000000000000000000001430264165500235525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-tag/my_index/index/he/000077500000000000000000000000001430264165500241465ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-tag/my_index/index/he/hello_world/000077500000000000000000000000001430264165500264605ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/long-tag/my_index/index/he/hello_world/hello_world-0.1.0.toml000066400000000000000000000003671430264165500323270ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] tags = ["very-very-long-tag"] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/long-tag/my_index/index/index.toml000066400000000000000000000000201430264165500255460ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/long-tag/test.py000066400000000000000000000006211430264165500221570ustar00rootroot00000000000000""" Test that long tags are rejected """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match('.*Loading .*hello_world-0.1.0.toml:' '.*tags:.*Tag string is too long ' '\(must be no more than [0-9]+\)\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/long-tag/test.yaml000066400000000000000000000001101430264165500224620ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/maint-bad-email/000077500000000000000000000000001430264165500220405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-email/my_index/000077500000000000000000000000001430264165500236545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-email/my_index/index/000077500000000000000000000000001430264165500247635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-email/my_index/index/he/000077500000000000000000000000001430264165500253575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-email/my_index/index/he/hello_world/000077500000000000000000000000001430264165500276715ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000003161430264165500334530ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-email/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["Mr. User"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/maint-bad-email/my_index/index/index.toml000066400000000000000000000000201430264165500267570ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/maint-bad-email/test.py000066400000000000000000000006121430264165500233700ustar00rootroot00000000000000""" Test that maintainers provide a plausible email """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match( '.*Loading .*hello_world-0.1.0.toml:.*maintainers:.*' 'Maintainers must have a valid email, but got: Mr. User\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/maint-bad-email/test.yaml000066400000000000000000000001101430264165500236730ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/maint-bad-login/000077500000000000000000000000001430264165500220615ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-login/my_index/000077500000000000000000000000001430264165500236755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-login/my_index/index/000077500000000000000000000000001430264165500250045ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-login/my_index/index/he/000077500000000000000000000000001430264165500254005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-login/my_index/index/he/hello_world/000077500000000000000000000000001430264165500277125ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000003441430264165500334750ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/maint-bad-login/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["Mr. User "] maintainers-logins = ["mr.user"] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/maint-bad-login/my_index/index/index.toml000066400000000000000000000000201430264165500270000ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/maint-bad-login/test.py000066400000000000000000000006431430264165500234150ustar00rootroot00000000000000""" Test that maintainers provide a plausible GitHub login """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match( '.*Loading .*hello_world-0.1.0.toml:.*maintainers-logins:.*' 'maintainers-logins must be a valid GitHub login, but got: mr.user\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/maint-bad-login/test.yaml000066400000000000000000000001101430264165500237140ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/mismatched-crate/000077500000000000000000000000001430264165500223315ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-crate/my_index/000077500000000000000000000000001430264165500241455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-crate/my_index/index/000077500000000000000000000000001430264165500252545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-crate/my_index/index/cr/000077500000000000000000000000001430264165500256605ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-crate/my_index/index/cr/crate/000077500000000000000000000000001430264165500267565ustar00rootroot00000000000000misplaced_crate-1.0.0.toml000066400000000000000000000003021430264165500333400ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-crate/my_index/index/cr/cratedescription = "Sample crate" name = "crate" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] url = "file:../../../crates/crate" alire-1.2.1/testsuite/tests/index/mismatched-crate/my_index/index/index.toml000066400000000000000000000000201430264165500272500ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/mismatched-crate/test.py000066400000000000000000000004661430264165500236700ustar00rootroot00000000000000""" Check detection of manifest in wrong shelf """ import re from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr("search", "--crates", complain_on_error=False) assert_match('.*ERROR: Mismatch between manifest and shelf:.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/mismatched-crate/test.yaml000066400000000000000000000001101430264165500241640ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/mismatched-parent/000077500000000000000000000000001430264165500225245ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-parent/my_index/000077500000000000000000000000001430264165500243405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-parent/my_index/index/000077500000000000000000000000001430264165500254475ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-parent/my_index/index/cr/000077500000000000000000000000001430264165500260535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-parent/my_index/index/cr/bad_parent/000077500000000000000000000000001430264165500301525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/mismatched-parent/my_index/index/cr/bad_parent/crate-1.0.0.toml000066400000000000000000000003021430264165500325720ustar00rootroot00000000000000description = "Sample crate" name = "crate" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] url = "file:../../../crates/crate" alire-1.2.1/testsuite/tests/index/mismatched-parent/my_index/index/index.toml000066400000000000000000000000201430264165500274430ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/mismatched-parent/test.py000066400000000000000000000004701430264165500240560ustar00rootroot00000000000000""" Check detection of manifest in wrong parent """ import re from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr("search", "--crates", complain_on_error=False) assert_match('.*ERROR: Mismatch between manifest and parent:.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/mismatched-parent/test.yaml000066400000000000000000000001101430264165500243570ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/old-compat-version/000077500000000000000000000000001430264165500226415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/old-compat-version/community/000077500000000000000000000000001430264165500246655ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/old-compat-version/community/index/000077500000000000000000000000001430264165500257745ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/old-compat-version/community/index/index.toml000066400000000000000000000000201430264165500277700ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/old-compat-version/test.py000066400000000000000000000011771430264165500242000ustar00rootroot00000000000000""" Test that an old compatible index can be loaded, but a warning is given """ from drivers.alr import run_alr from drivers.asserts import assert_match import re import os # Enable the warning we are trying to test run_alr("config", "--global", "--set", "warning.old_index", "true") # Run a command that loads the index. This produces a warning only, because the # index version is old but valid. p = run_alr("search", "--crates", # Causes loading of the index quiet=False) assert_match(".*Index 'community' version .* is older" " than the newest supported by alr.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/old-compat-version/test.yaml000066400000000000000000000001111430264165500244750ustar00rootroot00000000000000driver: python-script indexes: community: in_fixtures: false alire-1.2.1/testsuite/tests/index/old-incompat-version/000077500000000000000000000000001430264165500231705ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/old-incompat-version/community/000077500000000000000000000000001430264165500252145ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/old-incompat-version/community/index/000077500000000000000000000000001430264165500263235ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/old-incompat-version/community/index/index.toml000066400000000000000000000000471430264165500303300ustar00rootroot00000000000000version = "0.0" # Deliberately too old alire-1.2.1/testsuite/tests/index/old-incompat-version/test.py000066400000000000000000000010061430264165500245160ustar00rootroot00000000000000""" Test that an old compatible index can be loaded, but a warning is given """ from drivers.alr import run_alr from drivers.asserts import assert_match import re import os # Run a command that loads the index. This errs with a too old index version p = run_alr("search", "--crates", # Causes loading of the index complain_on_error=False) assert_match(".*" + re.escape("index version (0.0.0) is too old.") + " The minimum compatible version is .*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/old-incompat-version/test.yaml000066400000000000000000000001111430264165500250240ustar00rootroot00000000000000driver: python-script indexes: community: in_fixtures: false alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/000077500000000000000000000000001430264165500242465ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_1/000077500000000000000000000000001430264165500264035ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_1/he/000077500000000000000000000000001430264165500267775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_1/he/hello/000077500000000000000000000000001430264165500301025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_1/he/hello/hello-1.0.0.toml000066400000000000000000000003231430264165500325320ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "file:" alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_1/index.toml000066400000000000000000000000201430264165500303770ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_2/000077500000000000000000000000001430264165500264045ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_2/he/000077500000000000000000000000001430264165500270005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_2/he/hello/000077500000000000000000000000001430264165500301035ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_2/he/hello/hello-1.0.0.toml000066400000000000000000000003441430264165500325360ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] [origin] url = "file:non-existing-path" alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/bad_index_2/index.toml000066400000000000000000000000201430264165500304000ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/test.py000066400000000000000000000014371430264165500256040ustar00rootroot00000000000000""" Test that invalid filesystem origins are reported. """ import os from drivers.alr import prepare_env, prepare_indexes, run_alr from drivers.asserts import assert_match def run(i, error): config_dir = 'alr-config-{}'.format(i) prepare_env(config_dir, os.environ) prepare_indexes( config_dir, '.', {'bad_index_{}'.format(i): {'in_fixtures': False}}) p = run_alr("search", "--crates", complain_on_error=False, debug=False) assert_match( 'ERROR: {}\n'.format(error), p.out) run(1, '.*empty path given in local origin') # Since the location reported is an absolute path, and thus filesystem # dependent, check only that the beginning of the error is there: run(2, 'Local origin path is not a valid directory: .*non-existing-path') print('SUCCESS') alire-1.2.1/testsuite/tests/index/origin-filesystem-bad-path/test.yaml000066400000000000000000000000261430264165500261070ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/index/origin-no-archive-name/000077500000000000000000000000001430264165500233555ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-no-archive-name/my_index/000077500000000000000000000000001430264165500251715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-no-archive-name/my_index/index/000077500000000000000000000000001430264165500263005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-no-archive-name/my_index/index/he/000077500000000000000000000000001430264165500266745ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-no-archive-name/my_index/index/he/hello_world/000077500000000000000000000000001430264165500312065ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000004041430264165500347660ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-no-archive-name/my_index/index/he/hello_worldarchive-hash = "sha512:deadbeef" description = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["user@example.com"] maintainers-logins = ["mylogin"] [origin] url = "http://example.com/" alire-1.2.1/testsuite/tests/index/origin-no-archive-name/my_index/index/index.toml000066400000000000000000000000201430264165500302740ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/origin-no-archive-name/test.py000066400000000000000000000005411430264165500247060ustar00rootroot00000000000000""" Test that origins lacking archive names in indexes are properly reported. """ from drivers.alr import run_alr from drivers.asserts import assert_match import re p = run_alr('show', 'hello_world', complain_on_error=False, quiet=False) assert_match('.*unable to determine archive name from URL.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/origin-no-archive-name/test.yaml000066400000000000000000000001101430264165500252100ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/origin-unknown-kind/000077500000000000000000000000001430264165500230265ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-unknown-kind/my_index/000077500000000000000000000000001430264165500246425ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-unknown-kind/my_index/index/000077500000000000000000000000001430264165500257515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-unknown-kind/my_index/index/he/000077500000000000000000000000001430264165500263455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-unknown-kind/my_index/index/he/hello_world/000077500000000000000000000000001430264165500306575ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000003541430264165500344430ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/origin-unknown-kind/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["user@example.com"] maintainers-logins = ["mylogin"] [origin] url = "foo+http://blah.com/pkg.html" alire-1.2.1/testsuite/tests/index/origin-unknown-kind/my_index/index/index.toml000066400000000000000000000000201430264165500277450ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/origin-unknown-kind/test.py000066400000000000000000000005221430264165500243560ustar00rootroot00000000000000""" Test that origins of unknown kinds in indexes are properly reported. """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=False) assert_match( 'ERROR: .* unsupported scheme .*' '\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/origin-unknown-kind/test.yaml000066400000000000000000000001101430264165500246610ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/too-long-short-description/000077500000000000000000000000001430264165500243335ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/too-long-short-description/my_index/000077500000000000000000000000001430264165500261475ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/too-long-short-description/my_index/index/000077500000000000000000000000001430264165500272565ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/too-long-short-description/my_index/index/he/000077500000000000000000000000001430264165500276525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/too-long-short-description/my_index/index/he/hello_world/000077500000000000000000000000001430264165500321645ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000003761430264165500357540ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/too-long-short-description/my_index/index/he/hello_worlddescription = "This is a very very very very very very very very very very long description" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/too-long-short-description/my_index/index/index.toml000066400000000000000000000000201430264165500312520ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/too-long-short-description/test.py000066400000000000000000000006541430264165500256710ustar00rootroot00000000000000""" Test that too long descriptions are rejected """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr('show', 'hello_world', complain_on_error=False, debug=False, quiet=True) assert_match('.*Loading .*hello_world-0.1.0.toml:' '.*description:.*Description string is too long' ' \(must be no more than [0-9]+\)\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/index/too-long-short-description/test.yaml000066400000000000000000000001101430264165500261660ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/index/unexpected-contents/000077500000000000000000000000001430264165500231165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/unexpected-contents/my_index/000077500000000000000000000000001430264165500247325ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/unexpected-contents/my_index/index/000077500000000000000000000000001430264165500260415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/unexpected-contents/my_index/index/cr/000077500000000000000000000000001430264165500264455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/unexpected-contents/my_index/index/cr/crate/000077500000000000000000000000001430264165500275435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/unexpected-contents/my_index/index/cr/crate/crate-1.0.0.toml000066400000000000000000000002561430264165500321730ustar00rootroot00000000000000description = "Sample crate" name = "crate" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] url = "file:." alire-1.2.1/testsuite/tests/index/unexpected-contents/my_index/index/index.toml000066400000000000000000000000201430264165500300350ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/index/unexpected-contents/my_index/index/shouldnt_be_here000066400000000000000000000000001430264165500312630ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/index/unexpected-contents/test.py000066400000000000000000000004671430264165500244560ustar00rootroot00000000000000""" Check detection of bad file in index """ import re from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr("search", "--crates", complain_on_error=False) assert_match('.*ERROR: Unexpected file in index:.*shouldnt_be_here.+', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/index/unexpected-contents/test.yaml000066400000000000000000000001101430264165500247510ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/init/000077500000000000000000000000001430264165500167535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/init/default-executable/000077500000000000000000000000001430264165500225165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/init/default-executable/test.py000066400000000000000000000014101430264165500240430ustar00rootroot00000000000000""" Test "executable" only appears in --bin initializations """ import os.path from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import content_of test_dir = os.getcwd() # Binary crate run_alr("init", "--bin", "xxx") assert_match(".*executables = \[", content_of("xxx/alire.toml")) # Check that it builds and runs os.chdir("xxx") run_alr("run") # Library crate must not provide an executable os.chdir("..") run_alr("init", "--lib", "yyy") assert ".*executables = [" not in content_of("xxx/alire.toml"), \ "Unexpected contents in manifest" # Check the default executable is not built/runnable os.chdir("yyy") p = run_alr("run", complain_on_error=False) assert_match(".*Executable .* not found.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/init/default-executable/test.yaml000066400000000000000000000001701430264165500243570ustar00rootroot00000000000000driver: python-script indexes: basic_index: # needed to avoid cloning the community index in_fixtures: true alire-1.2.1/testsuite/tests/init/user-input-validation/000077500000000000000000000000001430264165500232165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/init/user-input-validation/test.py000066400000000000000000000012351430264165500245500ustar00rootroot00000000000000""" Check that a crate initialized with funny user name is loadable """ import os.path from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import content_of # Preconfigure needed fields name = "Äl O'Reilly O\"Raro" run_alr("config", "--global", "--set", "user.email", "abc@de.com") run_alr("config", "--global", "--set", "user.github_login", "abcde") run_alr("config", "--global", "--set", "user.name", name) # Create crate run_alr("init", "--bin", "xxx") # Check that it can be shown, which will load the manifest os.chdir("xxx") p = run_alr("show") assert name in p.out, f"Unexpected output: {p.out}" print('SUCCESS') alire-1.2.1/testsuite/tests/init/user-input-validation/test.yaml000066400000000000000000000001701430264165500250570ustar00rootroot00000000000000driver: python-script indexes: basic_index: # needed to avoid cloning the community index in_fixtures: true alire-1.2.1/testsuite/tests/misc/000077500000000000000000000000001430264165500167435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/bad-lockfile/000077500000000000000000000000001430264165500212575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/bad-lockfile/test.py000066400000000000000000000011561430264165500226130ustar00rootroot00000000000000""" A test that a bad lockfile is recovered from (losing pins) """ from drivers.alr import run_alr, alr_lockfile, init_local_crate import os import re # Create a new crate init_local_crate(name='xxx') # And muck its lockfile BADLINE = "SHOULND'T BE HERE" with open(alr_lockfile(), "a") as myfile: myfile.write(BADLINE) # Run a command that requires the lockfile p = run_alr('show') # Now the lockfile should be recreated and proper, so check no bad line: with open(alr_lockfile(), 'r') as myfile: for line in myfile: assert line != BADLINE, "Unexpected line found in file" print('SUCCESS') alire-1.2.1/testsuite/tests/misc/bad-lockfile/test.yaml000066400000000000000000000000631430264165500231210ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/misc/bad-tomlfile/000077500000000000000000000000001430264165500213025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/bad-tomlfile/test.py000066400000000000000000000010451430264165500226330ustar00rootroot00000000000000""" Check that a bad crate file is warned about """ from drivers.alr import run_alr from drivers.asserts import assert_match import os import re # Create a new crate run_alr('init', '--bin', 'xxx') # And muck its tomlfile os.chdir('xxx') with open("alire.toml", "a") as myfile: myfile.write("SHOULND'T BE HERE") # Verify that the expected error is given p = run_alr('show', complain_on_error=False) assert_match('.*Cannot continue with invalid session.*' 'Failed to load.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/misc/bad-tomlfile/test.yaml000066400000000000000000000000261430264165500231430ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/misc/clean-end/000077500000000000000000000000001430264165500205715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/clean-end/test.py000066400000000000000000000017541430264165500221310ustar00rootroot00000000000000""" Ensure that no unexpected output appears in the console. This happened in the past, where the finalization of something was causing an extra empty line. """ import os from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match # Check a few commands for unexpected output # Commands that require session assert_match(".*Cannot continue with invalid session:.*" # skip logging prefix " Could not detect a session folder" " at current or parent locations\n", run_alr('with', quiet=False, complain_on_error=False).out) # Commands within a trivial session assert_match(".*initialized successfully.*", run_alr('init', '--bin', 'xxx', quiet=False).out) os.chdir('xxx') assert_eq("", run_alr('update').out) assert_eq("Nothing to update.\n", run_alr('update', quiet=False).out) assert_eq("Dependencies (direct):\n" " (empty)\n", run_alr('with', quiet=False).out) print('SUCCESS') alire-1.2.1/testsuite/tests/misc/clean-end/test.yaml000066400000000000000000000000631430264165500224330ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/misc/force-switch/000077500000000000000000000000001430264165500213405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/force-switch/test.py000066400000000000000000000005211430264165500226670ustar00rootroot00000000000000""" Verify the global --force switch is in effect """ from drivers.alr import run_alr from drivers.asserts import assert_match import re assert_match('.*force flag:[\s]+TRUE.*', run_alr('version', force=True).out) assert_match('.*force flag:[\s]+TRUE', run_alr('version', force=True).out) print('SUCCESS') alire-1.2.1/testsuite/tests/misc/force-switch/test.yaml000066400000000000000000000000261430264165500232010ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/misc/gprbuild-switches/000077500000000000000000000000001430264165500224025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/gprbuild-switches/test.py000066400000000000000000000015711430264165500237370ustar00rootroot00000000000000""" Verify alr build switches are passed to gprbuild """ from glob import glob import os import re from drivers.alr import run_alr from drivers.asserts import assert_match # Get the "hello" project and enter its directory run_alr('get', 'hello') os.chdir(glob('hello*')[0]) # Switches before a double-dash are parsed for the alr build command p = run_alr('build', '-XTEST=TEST', complain_on_error=False, debug=False) assert_match('ERROR: Unrecognized option \'-X\'.*', p.out, flags=re.S) # Switches after a double-dash are passed to gprbuild p = run_alr('build', '--', '--this-is-not-a-valid-switch', complain_on_error=False, debug=False) assert_match('.*gprbuild: illegal option' ' "--this-is-not-a-valid-switch"' ' on the command line.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/misc/gprbuild-switches/test.yaml000066400000000000000000000000631430264165500242440ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/misc/hashes/000077500000000000000000000000001430264165500202165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/hashes/my_index/000077500000000000000000000000001430264165500220325ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/hashes/my_index/index/000077500000000000000000000000001430264165500231415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/hashes/my_index/index/cr/000077500000000000000000000000001430264165500235455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/hashes/my_index/index/cr/crate/000077500000000000000000000000001430264165500246435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/hashes/my_index/index/cr/crate/crate-1.0.0.toml000066400000000000000000000007651430264165500273000ustar00rootroot00000000000000description = "Sample crate" name = "crate" version = "1.0.0" licenses = [] maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] # Relative to where the index and the crates are placed by the test set up url = "file:../../../../crates/libhello_1.0.0.tgz" hashes = [ "sha256:c17d6ce87c6997c5f68ea4bfe6134c318073fed38ec0f81ccb1ae2bfdcc0187a", "sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac", ] alire-1.2.1/testsuite/tests/misc/hashes/my_index/index/cr/crate/crate-2.0.0.toml000066400000000000000000000010161430264165500272670ustar00rootroot00000000000000description = "Sample crate" name = "crate" version = "2.0.0" licenses = [] maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] # Relative to where the index and the crates are placed by the test set up url = "file:../../../../crates/libhello_1.0.0.tgz" # These hashes are wrong hashes = [ "sha256:000000007c6997c5f68ea4bfe6134c318073fed38ec0f81ccb1ae2bfdcc0187a", "sha512:00000000540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac", ] alire-1.2.1/testsuite/tests/misc/hashes/my_index/index/index.toml000066400000000000000000000000201430264165500251350ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/misc/hashes/test.py000066400000000000000000000011541430264165500215500ustar00rootroot00000000000000""" Verify the recognition of all supported hash types """ from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match # Verify loading p = run_alr("show", "crate") assert_match(".*Origin.*with hashes " "sha256:.{64}, sha512:.{128}", p.out) # Verify actual hash use. v1 of crate is correct, v2 contains bad hashes # This can only succeed if all hashes match p = run_alr("get", "crate=1") # Verify that a hash mismatch is also detected p = run_alr("get", "crate=2", complain_on_error=False) assert_match(".*release integrity test failed.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/misc/hashes/test.yaml000066400000000000000000000001461430264165500220620ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/misc/local-no-origin/000077500000000000000000000000001430264165500217345ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/local-no-origin/test.py000066400000000000000000000011221430264165500232610ustar00rootroot00000000000000""" Verify that workspace metadata does not specify an origin """ from drivers.alr import run_alr, init_local_crate from drivers.helpers import content_of from glob import glob from os import chdir from os.path import join def assert_no_origin(crate): assert "origin" not in content_of("alire.toml"), \ "found unexpected contents in manifest of crate " + crate # case 1, a gotten crate p = run_alr('get', 'libhello') chdir(glob("libhello*")[0]) assert_no_origin("libhello") chdir("..") # case 2, a fresh crate init_local_crate("xxx") assert_no_origin("xxx") print('SUCCESS') alire-1.2.1/testsuite/tests/misc/local-no-origin/test.yaml000066400000000000000000000000631430264165500235760ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/misc/local-reject-origin/000077500000000000000000000000001430264165500225745ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/local-reject-origin/test.py000066400000000000000000000007211430264165500241250ustar00rootroot00000000000000""" Verify that an origin definition is rejected in a local manifest """ from drivers.alr import run_alr, init_local_crate from drivers.asserts import assert_match from os.path import join init_local_crate("xxx") # Add manually the origin, and verify that it cannot be loaded with open("alire.toml", "a") as file: file.write("\n[origin]\n") p = run_alr("show", complain_on_error=False) assert_match(".*invalid property: origin.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/misc/local-reject-origin/test.yaml000066400000000000000000000000261430264165500244350ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/misc/lockfile-hiding/000077500000000000000000000000001430264165500217735ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/lockfile-hiding/test.py000066400000000000000000000025741430264165500233340ustar00rootroot00000000000000""" Verify that lockfiles are properly [re]moved from $crate/ to $crate/alire/ """ import os from drivers.alr import run_alr, init_local_crate, alr_lockfile, alr_with # from drivers.asserts import assert_eq, assert_match from drivers.helpers import content_of from os.path import isfile old_lockfile = "alire.lock" init_local_crate() # Add a dependency so the lockfile is not the same as the default one default_content = content_of(alr_lockfile()) alr_with("libhello") proper_content = content_of(alr_lockfile()) assert default_content != proper_content, \ "error setting up the test (contents should differ)" def verify(): """ Check that the lockfile is only in the new location, with proper contents """ assert isfile(alr_lockfile()) and not isfile(old_lockfile), \ "Unexpected lockfile placement" assert content_of(alr_lockfile()) == proper_content, "bad contents" # Case 1: lockfile is only in the old location, and it is moved to new location # First, get the current lockfile and put it in the old location: os.rename(alr_lockfile(), old_lockfile) run_alr("show") # Triggers migration verify() # Case 2: have an old lockfile that should be discarded without being copied, # as the new lockfile is already in place (at the end of Case 1): with open(old_lockfile, "wt") as file: file.write(default_content) run_alr("show") verify() print('SUCCESS') alire-1.2.1/testsuite/tests/misc/lockfile-hiding/test.yaml000066400000000000000000000000631430264165500236350ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/misc/sync-manual-edit/000077500000000000000000000000001430264165500221155ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/sync-manual-edit/test.py000066400000000000000000000021601430264165500234450ustar00rootroot00000000000000""" Verify that manual changes to the manifest result in an automatic update before other commands that require a valid workspace """ import os.path from drivers.alr import run_alr, alr_touch_manifest from shutil import rmtree # from drivers.asserts import assert_eq, assert_match target = 'alire/cache/dependencies/libhello_1.0.0_filesystem' # After manually adding a dependency run commands that require a valid session. # This should cause the expected dependency folder to exist for cmd in ['build', 'pin', 'run', 'show', 'with', 'printenv']: # Create a new project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # "Manually" add a dependency with open("alire.toml", "a") as file: file.write('[[depends-on]]\nlibhello="1"') # Make the lockfile "older" (otherwise timestamp is identical) alr_touch_manifest() # Run the command run_alr(cmd) # Check dependency folder is at the expected location: assert os.path.isdir(target), "Directory missing at expected location" # Go back up and clean up for next command os.chdir("..") rmtree("xxx") print('SUCCESS') alire-1.2.1/testsuite/tests/misc/sync-manual-edit/test.yaml000066400000000000000000000000631430264165500237570ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/misc/sync-missing-deps/000077500000000000000000000000001430264165500223175ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/misc/sync-missing-deps/test.py000066400000000000000000000016511430264165500236530ustar00rootroot00000000000000""" Verify that missing dependency sources are retrieved """ import os.path from drivers.alr import run_alr from shutil import rmtree # from drivers.asserts import assert_eq, assert_match # Create a new project and set up dependencies run_alr('init', '--bin', 'xxx') os.chdir('xxx') run_alr('with', 'hello') target = 'alire/cache/dependencies/hello_1.0.1_filesystem' # Ensure the hello dependency is there: assert os.path.isdir(target), "Directory missing at expected location" # Run commands that require a valid session after deleting a dependency. All # should succeed and recreate the missing dependency folder. for cmd in ['build', 'pin', 'run', 'show', 'with', 'printenv']: # Delete folder rmtree(target) # Run the command run_alr(cmd) # The successful run should be proof enough, but check folder is there: assert os.path.isdir(target), "Directory missing at expected location" print('SUCCESS') alire-1.2.1/testsuite/tests/misc/sync-missing-deps/test.yaml000066400000000000000000000000631430264165500241610ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/monorepo/000077500000000000000000000000001430264165500176465ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/basic/000077500000000000000000000000001430264165500207275ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/basic/my_index/000077500000000000000000000000001430264165500225435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/basic/my_index/index/000077500000000000000000000000001430264165500236525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/basic/my_index/index/index.toml000066400000000000000000000000201430264165500256460ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/monorepo/basic/test.py000066400000000000000000000043051430264165500222620ustar00rootroot00000000000000""" Publish a crate that is nested inside a git repository, get/build it and also use it as a dependency """ import os import shutil from drivers.alr import run_alr, init_local_crate, alr_with, alr_publish from drivers.helpers import init_git_repo, on_windows # from drivers.asserts import assert_eq, assert_match from subprocess import run # We create a repository with the nested crate that will act as the upstream # remote repository: start_dir = os.getcwd() os.mkdir("monoproject.upstream") os.chdir("monoproject.upstream") init_local_crate("mycrate", enter=False) os.chdir(start_dir) commit = init_git_repo("monoproject.upstream") # We clone the project to obtain our local copy assert run(["git", "clone", "monoproject.upstream", "monoproject"]).returncode == 0 # We enter the clone and verify that attempting to publish from the root fails, # as there is no crate at the git root os.chdir("monoproject") p = run_alr("publish", complain_on_error=False) assert p.status != 0, "alr failed to err as expected" assert "No Alire workspace found" in p.out, "Unexpected output: " + p.out # We enter the crate nested inside and publish. # We are now at monoproject/mycrate. os.chdir("mycrate") run_alr("show") # Verify the crate is detected properly # This call creates the manifest and puts it in place in the index alr_publish("mycrate", "0.1.0-dev", index_path=os.path.join(start_dir, "my_index")) # Verify that the crate can be got and compiled, and expected location os.chdir(start_dir) run_alr("get", "--build", "mycrate") assert os.path.isdir(os.path.join(f"monoproject_{commit[:8]}", "mycrate")), \ "Expected directory does not exist" # Verify that the crate is usable as a dependency, and expected binary location init_local_crate("top") alr_with("mycrate") run_alr("build") assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"monoproject_{commit[:8]}", "mycrate", "bin", f"mycrate{'.exe' if on_windows() else ''}")), \ "Expected binary does not exist" # Also that the info file is there assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"mycrate_0.1.0_in_monoproject_{commit[:8]}")), \ "Expected info file does not exist" print('SUCCESS') alire-1.2.1/testsuite/tests/monorepo/basic/test.yaml000066400000000000000000000001101430264165500225620ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/monorepo/doubly-nested/000077500000000000000000000000001430264165500224245ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/doubly-nested/my_index/000077500000000000000000000000001430264165500242405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/doubly-nested/my_index/index/000077500000000000000000000000001430264165500253475ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/doubly-nested/my_index/index/index.toml000066400000000000000000000000201430264165500273430ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/monorepo/doubly-nested/test.py000066400000000000000000000044461430264165500237650ustar00rootroot00000000000000""" Publish a doubly-nested crate: ./gitrepo/parent/child and test using it """ import os import shutil from drivers.alr import run_alr, init_local_crate, alr_with, alr_publish from drivers.helpers import init_git_repo from subprocess import run # We create a repository with the nested crate that will act as the upstream # remote repository: start_dir = os.getcwd() index_dir = os.path.join(os.getcwd(), "my_index") os.mkdir("monoproject.upstream") os.chdir("monoproject.upstream") init_local_crate("myparent") init_local_crate("mychild") os.chdir(start_dir) commit = init_git_repo("monoproject.upstream") # We clone the project to obtain our local copy assert run(["git", "clone", "monoproject.upstream", "monoproject"]).returncode == 0 # We enter the crate nested inside and publish. os.chdir(os.path.join("monoproject", "myparent", "mychild")) run_alr("show") # Verify the crate is detected properly # This call publishes and "submits" the release to our local index alr_publish("mychild", "0.1.0-dev", index_path=index_dir) # Publish also its parent for later test os.chdir("..") alr_publish("myparent", "0.1.0-dev", index_path=index_dir) # Verify that the crate can be got and compiled, and expected location os.chdir(start_dir) run_alr("get", "--build", "mychild") assert os.path.isdir(os.path.join(f"monoproject_{commit[:8]}", "myparent", "mychild")), \ "Expected directory does not exist" # Verify that the crate is usable as a dependency, and expected location init_local_crate("top") alr_with("mychild") run_alr("build") assert os.path.isdir(os.path.join("alire", "cache", "dependencies", f"monoproject_{commit[:8]}", "myparent", "mychild")), \ "Expected directory does not exist" # Verify that "with"ing the parent does not result in a new checkout alr_with("myparent", update=False) p = run_alr("-v", "update", quiet=False) assert "Skipping checkout of already available myparent=0.1.0-dev" in p.out, \ "Expected output not found: " + p.out # Verify the build is successful. As the dependencies were created with --bin, # they will be built even if not "with"ed in the Ada code to make their binary # available to the root crate during the build process. run_alr("build") print('SUCCESS') alire-1.2.1/testsuite/tests/monorepo/doubly-nested/test.yaml000066400000000000000000000001101430264165500242570ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/monorepo/get-dirname/000077500000000000000000000000001430264165500220425ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/get-dirname/my_index/000077500000000000000000000000001430264165500236565ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/get-dirname/my_index/index/000077500000000000000000000000001430264165500247655ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/get-dirname/my_index/index/cr/000077500000000000000000000000001430264165500253715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/get-dirname/my_index/index/cr/crate/000077500000000000000000000000001430264165500264675ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/get-dirname/my_index/index/cr/crate/crate-1.0.0.toml000066400000000000000000000004141430264165500311130ustar00rootroot00000000000000name = "crate" description = "A crate" version = "1.0" authors = ["author"] maintainers = ["author@at.me"] maintainers-logins = ["author"] [origin] url = "git+https://github.com/author/crate.git" commit = "12345678880ab9ed38d58ac08c1c9a16e7697752" subdir = "nested" alire-1.2.1/testsuite/tests/monorepo/get-dirname/my_index/index/index.toml000066400000000000000000000000201430264165500267610ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/monorepo/get-dirname/test.py000066400000000000000000000005461430264165500234000ustar00rootroot00000000000000""" Verify the output of `alr get --dirname` when the crate is in a monorepo """ import os import shutil from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match from drivers.helpers import dir_separator assert_eq(f"crate_12345678{dir_separator()}nested\n", run_alr("get", "crate", "--dirname").out) print('SUCCESS') alire-1.2.1/testsuite/tests/monorepo/get-dirname/test.yaml000066400000000000000000000001101430264165500236750ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/monorepo/multi-commit/000077500000000000000000000000001430264165500222665ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/multi-commit/my_index/000077500000000000000000000000001430264165500241025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/multi-commit/my_index/index/000077500000000000000000000000001430264165500252115ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/multi-commit/my_index/index/index.toml000066400000000000000000000000201430264165500272050ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/monorepo/multi-commit/test.py000066400000000000000000000046741430264165500236320ustar00rootroot00000000000000""" Publish two crates and use them as dependencies, but at different commits of the same monorepo. The monorepo must be checked out twice and the duplicated crate must not cause trouble. """ import os import shutil from drivers.alr import run_alr, init_local_crate, alr_with, alr_publish from drivers.helpers import init_git_repo, on_windows, commit_all # from drivers.asserts import assert_eq, assert_match from subprocess import run # We create a repository with two nested crates that will act as the upstream # remote repository: start_dir = os.getcwd() os.mkdir("monoproject.upstream") os.chdir("monoproject.upstream") init_local_crate("crate1", enter=False) os.chdir(start_dir) commit1 = init_git_repo("monoproject.upstream") # We clone the project to obtain our local copy assert run(["git", "clone", "monoproject.upstream", "monoproject"]).returncode == 0 # We enter the crate nested inside and publish. # We are now at monoproject/mycrate. os.chdir("monoproject") os.chdir("crate1") alr_publish("crate1", "0.1.0-dev", index_path=os.path.join(start_dir, "my_index")) # We create a second crate at another commit os.chdir(os.path.join(start_dir, "monoproject.upstream")) init_local_crate("crate2", enter=False) os.chdir(start_dir) commit2 = commit_all("monoproject.upstream") # Check out changes and publish crate2 os.chdir("monoproject") run(["git", "pull"]).check_returncode() os.chdir("crate2") alr_publish("crate2", "0.1.0-dev", index_path=os.path.join(start_dir, "my_index")) # Verify that the crates are usable as a dependency, and expected binary # locations init_local_crate("top") alr_with("crate1") alr_with("crate2") run_alr("build") assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"monoproject_{commit1[:8]}", "crate1", "bin", f"crate1{'.exe' if on_windows() else ''}")), \ "Expected binary does not exist" assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"monoproject_{commit2[:8]}", "crate2", "bin", f"crate2{'.exe' if on_windows() else ''}")), \ "Expected binary does not exist" # Also that the info files are there assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"crate1_0.1.0_in_monoproject_{commit1[:8]}")), \ "Expected info file does not exist" assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"crate2_0.1.0_in_monoproject_{commit2[:8]}")), \ "Expected info file does not exist" print('SUCCESS') alire-1.2.1/testsuite/tests/monorepo/multi-commit/test.yaml000066400000000000000000000001101430264165500241210ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/monorepo/subdir-in-tar/000077500000000000000000000000001430264165500223265ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/subdir-in-tar/my_index/000077500000000000000000000000001430264165500241425ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/subdir-in-tar/my_index/index/000077500000000000000000000000001430264165500252515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/monorepo/subdir-in-tar/my_index/index/index.toml000066400000000000000000000000201430264165500272450ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/monorepo/subdir-in-tar/test.py000066400000000000000000000020621430264165500236570ustar00rootroot00000000000000""" Test that "subdir" is rejected for source archive origins """ from drivers.alr import init_local_crate, run_alr, alr_submit from glob import glob from shutil import copyfile from subprocess import run import drivers.helpers import os # Prepare our "remote" repo init_local_crate("xxx", enter=True) # Publish it. We need to give input to alr, so we directly call it. We use the # generated location as the "online" location, and this works because we are # forcing. p = run(["alr", "-q", "-f", "-n", "publish", "--skip-build", "--tar"], input=f"file:{os.getcwd()}/alire/archives/xxx-0.1.0-dev.tbz2\n".encode()) p.check_returncode() # Add improper subdir to manifest with open("alire/releases/xxx-0.1.0-dev.toml", "at") as file: file.write("subdir='.'\n") # Submit manifest to index os.chdir("..") alr_submit("xxx/alire/releases/xxx-0.1.0-dev.toml", "my_index") # Should complain on subdir field p = run_alr("show", "xxx", complain_on_error=False) assert "forbidden extra entries: subdir" in p.out, \ "Unexpected output: " + p.out print('SUCCESS') alire-1.2.1/testsuite/tests/monorepo/subdir-in-tar/test.yaml000066400000000000000000000001101430264165500241610ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/pin/000077500000000000000000000000001430264165500165765ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/all/000077500000000000000000000000001430264165500173465ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/all/my_index/000077500000000000000000000000001430264165500211625ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/all/my_index/index/000077500000000000000000000000001430264165500222715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/all/my_index/index/he/000077500000000000000000000000001430264165500226655ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/all/my_index/index/he/hello1/000077500000000000000000000000001430264165500240515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/all/my_index/index/he/hello1/hello1-0.1.0.toml000066400000000000000000000003241430264165500265630ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello1" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/all/my_index/index/he/hello2/000077500000000000000000000000001430264165500240525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/all/my_index/index/he/hello2/hello2-0.1.0.toml000066400000000000000000000003241430264165500265650ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello2" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/all/my_index/index/index.toml000066400000000000000000000000201430264165500242650ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/all/test.py000066400000000000000000000010551430264165500207000ustar00rootroot00000000000000""" Test pin/unpin with --all """ import os from drivers.alr import run_alr from drivers.asserts import assert_eq # Create a new "xxx" program project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Make it depend on hello1 and hello2 run_alr('with', 'hello1') run_alr('with', 'hello2') # Pin and check run_alr('pin', '--all') p = run_alr('pin') assert_eq('hello1 0.1.0\n' 'hello2 0.1.0\n', p.out) # Unpin and check run_alr('pin', '--unpin', '--all') p = run_alr('pin') assert_eq('There are no pins\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/all/test.yaml000066400000000000000000000001101430264165500212010ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/pin/bad-path/000077500000000000000000000000001430264165500202565ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/bad-path/test.py000066400000000000000000000006461430264165500216150ustar00rootroot00000000000000""" Verify that pinning a bad path is rejected """ from drivers.alr import run_alr, alr_pin, init_local_crate from drivers.asserts import assert_eq, assert_match init_local_crate() alr_pin("badcrate", path="../bad/path", update=False) # Now the update should detect the bad path p = run_alr("update", complain_on_error=False) assert_match(".*Pin path is not a valid directory:.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/bad-path/test.yaml000066400000000000000000000000631430264165500221200ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/branch/000077500000000000000000000000001430264165500200335ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/branch/test.py000066400000000000000000000032401430264165500213630ustar00rootroot00000000000000""" Check pinning to a branch, and changing branches """ from drivers.alr import run_alr, alr_pin, alr_unpin, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import git_branch, git_head, init_git_repo from e3.os.fs import touch from re import escape import re import os import shutil import subprocess # "remote" is going to be the remote crate init_local_crate(name="remote", enter=False) url = os.path.join(os.getcwd(), "remote") head1 = init_git_repo("remote") os.chdir("remote") default_branch = git_branch() # Create a second branch and commit for testing subprocess.run(["git", "checkout", "-b", "devel"]).check_returncode() touch("telltale") subprocess.run(["git", "add", "telltale"]).check_returncode() subprocess.run(["git", "commit", "-m", "branching"]).check_returncode() os.chdir("..") # Now pin to the branch, and verify the telltale file exists in the checkout init_local_crate() alr_pin("remote", url=url, branch="devel") p = run_alr("pin") assert_match("remote file:alire/cache/pins/remote " + re.escape(url) + "#devel\n", # branch in the info matches p.out) # Also verify the file exists assert os.path.exists("alire/cache/pins/remote/telltale"), \ "Missing file in checkout" # Edit pin to point to the default branch, and verify telltale is missing alr_unpin("remote", update=False) alr_pin("remote", url=url, branch=default_branch) p = run_alr("pin") assert_match("remote file:alire/cache/pins/remote " + re.escape(url) + f"#{default_branch}\n", p.out) assert not os.path.exists("alire/cache/pins/remote/telltale"), \ "Unexpected file in checkout" print('SUCCESS') alire-1.2.1/testsuite/tests/pin/branch/test.yaml000066400000000000000000000000631430264165500216750ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/change-path/000077500000000000000000000000001430264165500207555ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/change-path/test.py000066400000000000000000000021021430264165500223010ustar00rootroot00000000000000""" Verify that the path of a pin can be changed and this is detected automatically """ from drivers.alr import run_alr, alr_pin, alr_unpin, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import on_windows import os def create_dep(nest): """ Create the same dependency yyy under the given nest path """ os.mkdir(nest) os.chdir(nest) init_local_crate("yyy", enter=False) os.chdir("..") # Two versions of the same crate create_dep("nest1") create_dep("nest2") # Dependent main crate init_local_crate() alr_pin("yyy", path="../nest1/yyy") # Edit the pin path by unpinning/repinning, without running alr in between, # so this is equivalent to just editing the pin alr_unpin("yyy", update=False) alr_pin("yyy", path="../nest2/yyy", update=False) # Now detect changes and show output p = run_alr("pin", quiet=False) assert_eq("""Note: Synchronizing workspace... Dependencies automatically updated as follows: · yyy 0.1.0-dev (path=../nest2/yyy) yyy file:../nest2/yyy \n""", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/change-path/test.yaml000066400000000000000000000000631430264165500226170ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/change-type/000077500000000000000000000000001430264165500210025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/change-type/my_index/000077500000000000000000000000001430264165500226165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/change-type/my_index/index.toml000066400000000000000000000000201430264165500246120ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/change-type/my_index/li/000077500000000000000000000000001430264165500232225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/change-type/my_index/li/libhello/000077500000000000000000000000001430264165500250145ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/change-type/my_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003151430264165500301340ustar00rootroot00000000000000description = "libhello" name = "libhello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["some@one.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/tests/pin/change-type/test.py000066400000000000000000000021411430264165500223310ustar00rootroot00000000000000""" Change a pinned dependency from a version to a folder and back, using manifest """ import os import re from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_match from drivers.helpers import dir_separator def check_version_pin(): p = run_alr('show', '--solve') assert_match('.*Dependencies \(solution\):' '.*libhello=1.0.0.*', p.out, flags=re.S) # Initialize a workspace, enter, and add a regular dependency run_alr('init', '--bin', 'xxx') os.chdir('xxx') run_alr('with', 'libhello^1') # Pin to a version alr_pin('libhello', version='1.0') # Check that it shows as such in the solution check_version_pin() # Repin to a folder alr_pin('libhello', path='../crates/libhello_1.0.0') # Check that it shows as such in the solution p = run_alr('show', '--solve') assert_match('.*Dependencies \(external\):.*' 'libhello.*\^1.*\(direct,linked' ',path=../crates/libhello_1.0.0\).*', p.out, flags=re.S) # Repin to a version and check again alr_pin('libhello', version='1.0') check_version_pin() print('SUCCESS') alire-1.2.1/testsuite/tests/pin/change-type/test.yaml000066400000000000000000000001461430264165500226460ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/pin/circularity/000077500000000000000000000000001430264165500211305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/circularity/test.py000066400000000000000000000046541430264165500224720ustar00rootroot00000000000000""" Verify pin circularity detection """ from drivers.alr import run_alr, alr_pin, alr_unpin, alr_with, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import on_windows, dir_separator import os import re import shutil # Obvious self-pinning detection init_local_crate() alr_pin("xxx", path=".", update=False) p = run_alr("pin", complain_on_error=False) assert_match(".*" "ERROR: Pin circularity detected when adding pin xxx --> xxx:\n" "ERROR: Last manifest in the cycle is .*\n", p.out) # A real cycle detection os.chdir("..") # back to top-level shutil.rmtree("xxx") # and restart from scratch # Prepare a cycle init_local_crate("xxx", enter=False) init_local_crate("yyy", enter=False) init_local_crate("zzz") alr_pin("xxx", path="../xxx", update=False) os.chdir("..") os.chdir("yyy") alr_pin("zzz", path="../zzz", update=False) os.chdir("..") os.chdir("xxx") alr_pin("yyy", path="../yyy", update=False) # At this point, xxx --> yyy --> zzz --> xxx p = run_alr("pin", complain_on_error=False) s = re.escape(dir_separator()) assert_match( ".*" "ERROR: Pin circularity detected when adding pin zzz --> xxx:\n" f"ERROR: Last manifest in the cycle is .*{s}zzz{s}alire.toml\n", p.out) # Verify that the buggy case that was reported does not happen again # In this case, we have # dep1 -> dep2 -> dep3 -> dep4; dep1 -> dep3; dep1 -> dep4; dep2 -> dep4 init_local_crate("dep4", enter=False) init_local_crate("dep3") alr_with("dep4", path="../dep4") os.chdir("..") init_local_crate("dep2") alr_with("dep3", path="../dep3") alr_with("dep4", path="../dep4") os.chdir("..") init_local_crate("dep1") alr_with("dep2", path="../dep2") alr_with("dep3", path="../dep3") alr_with("dep4", path="../dep4") p = run_alr("with", "--solve") assert_eq("""\ Dependencies (direct): dep2* dep3* dep4* Pins (direct): dep2 = { path='../dep2' } dep3 = { path='../dep3' } dep4 = { path='../dep4' } Dependencies (solution): dep2=0.1.0-dev (pinned) (origin: ../dep2) dep3=0.1.0-dev (pinned) (origin: ../dep3) dep4=0.1.0-dev (pinned) (origin: ../dep4) Dependencies (graph): dep1=0.1.0-dev --> dep2=0.1.0-dev (*) dep1=0.1.0-dev --> dep3=0.1.0-dev (*) dep1=0.1.0-dev --> dep4=0.1.0-dev (*) dep2=0.1.0-dev --> dep3=0.1.0-dev (*) dep2=0.1.0-dev --> dep4=0.1.0-dev (*) dep3=0.1.0-dev --> dep4=0.1.0-dev (*) """, p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/circularity/test.yaml000066400000000000000000000000631430264165500227720ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/conflicting-link/000077500000000000000000000000001430264165500220305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/conflicting-link/test.py000066400000000000000000000024551430264165500233670ustar00rootroot00000000000000""" Verify that two equal links for the same create are accepted but two different ones are rejected """ from drivers.alr import run_alr, alr_pin, alr_unpin, init_local_crate from drivers.asserts import assert_eq, assert_match import os # We are going to setup xxx --> yyy --> zzz, xxx --> zzz to verify same link # is accepted. init_local_crate(name="zzz", enter=False) os.mkdir("nest") # By nesting yyy, we force different relative paths that os.chdir("nest") # should not be a problem as internally is the same abs path. init_local_crate(name="yyy") alr_pin("zzz", path="../../zzz") os.chdir("..") os.chdir("..") init_local_crate() # This places us at ./xxx alr_pin("yyy", path="../nest/yyy") alr_pin("zzz", path="../zzz") # This is the doubly-linked same crate # Should work properly p = run_alr("pin") assert_eq('yyy file:../nest/yyy \n' 'zzz file:../zzz \n', p.out) # Now we will pin a different zzz from xxx, # so xxx --> ./xxx/zzz conflicts with ./nest/yyy --> ../../zzz alr_unpin("zzz") init_local_crate(name="zzz", enter=False) # This one is at ./xxx/zzz alr_pin("zzz", path="./zzz", update=False) # Should detect conflicting links p = run_alr("pin", complain_on_error=False) assert_match(".*Conflicting pin links for crate zzz:.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/conflicting-link/test.yaml000066400000000000000000000000631430264165500236720ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/conflicting-remote/000077500000000000000000000000001430264165500223665ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/conflicting-remote/test.py000066400000000000000000000060531430264165500237230ustar00rootroot00000000000000""" Check conflict detection for remote pins for the same crate """ from drivers.alr import run_alr, alr_pin, alr_unpin, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import git_blast, git_head, init_git_repo from e3.os.fs import touch from re import escape import re import os import shutil import subprocess # "remote" is going to be the remote crate. Two other crates will depend on it # with different branches/commits etc init_local_crate(name="zzz", enter=False) url = os.path.join(os.getcwd(), "zzz") head1 = init_git_repo("zzz") os.chdir("zzz") # Create a second branch and commit for testing subprocess.run(["git", "checkout", "-b", "devel"]).check_returncode() touch("x") subprocess.run(["git", "add", "x"]).check_returncode() subprocess.run(["git", "commit", "-m", "branching"]).check_returncode() head2 = git_head() os.chdir("..") # In this function we will test that two crates with the same remote works, # for several combinations def should_work(commit="", branch=""): os.mkdir("nest") os.chdir("nest") for crate in ["xxx", "yyy"]: init_local_crate(crate) alr_pin("zzz", url=url, commit=commit, branch=branch) os.chdir("..") os.chdir("xxx") alr_pin("yyy", path="../yyy") p = run_alr("pin") assert_match(escape("yyy file:../yyy") + ".*\n" + escape("zzz file:alire/cache/pins/zzz") + ".*" + escape(url), p.out) # Clean up for next trial os.chdir("..") os.chdir("..") git_blast("nest") # In this function we will test conflicts that should be detected def should_not_work(commits=["", ""], branches=["", ""], match_error="FAIL"): # Commits and branches must contain two values that go into each crate pin os.mkdir("nest") os.chdir("nest") crates = ["xxx", "yyy"] for i in [0, 1]: init_local_crate(crates[i]) alr_pin("zzz", url=url, commit=commits[i], branch=branches[i]) os.chdir("..") os.chdir("xxx") alr_pin("yyy", path="../yyy", update=False) p = run_alr("pin", complain_on_error=False) assert_match(match_error, p.out) # Clean up for next trial os.chdir("..") os.chdir("..") shutil.rmtree("nest") should_work() # Remote at default branch should_work(commit=head1) # Remote at given commit should_work(branch="devel") # Remote at given branch should_not_work(commits=[head1, head2], match_error=".*" + re.escape("Conflicting pin links for crate zzz: " "Crate xxx wants to link ") + ".*" + re.escape(", but a previous link exists to ") + ".*zzz#[0-9a-f]+.*") # with commit should_not_work(branches=["", "devel"], match_error=".*" + re.escape("Conflicting pin links for crate zzz: " "Crate xxx wants to link ") + ".*" + re.escape(", but a previous link exists to ") + ".*zzz#devel\n") # with branch print('SUCCESS') alire-1.2.1/testsuite/tests/pin/conflicting-remote/test.yaml000066400000000000000000000000631430264165500242300ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/dir-crate/000077500000000000000000000000001430264165500204505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/dir-crate/test.py000066400000000000000000000021371430264165500220040ustar00rootroot00000000000000""" Detect that a given folder to pin contains a crate and use its info """ import os import re from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_match from drivers.helpers import dir_separator from glob import glob # Retrieve a crate run_alr('get', 'hello=1') target = glob('hello*')[0] # Initialize a workspace run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Add dependency as regular crate; this has missing dependencies so we have to # force. This brings in hello=4. run_alr('with', 'hello', force=True) # Pin the hello crate as local dir dependency. The version in the folder is # different to the one we had in the solution, so this should cause a downgrade # but with complete solution. Now hello=1 --> libhello=1.1. alr_pin('hello', path='../' + target) # Verify that hello dependencies are detected and used, and are the ones # corresponding to the linked dir versions. p = run_alr('with', '--solve') assert_match('''.*Dependencies \(solution\): hello=1\.0\.0 .* libhello=1\.1\.0 .*''', # we skip non-relevant details p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/dir-crate/test.yaml000066400000000000000000000001131430264165500223060ustar00rootroot00000000000000driver: python-script indexes: solver_index: in_fixtures: true alire-1.2.1/testsuite/tests/pin/dir-mismatch/000077500000000000000000000000001430264165500211575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/dir-mismatch/test.py000066400000000000000000000020351430264165500225100ustar00rootroot00000000000000""" Detect that a given folder to pin contains an unexpected crate """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import dir_separator from glob import glob # Prepare an empty dir os.mkdir("nothello") # Retrieve a crate run_alr('get', 'hello=1') target = glob('hello*')[0] # Initialize a workspace run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Add a dependency as pinned dir without metadata; this should succeed run_alr('with', 'nothello', '--use', '..') # Detect a repin is rejected unless forced p = run_alr('with', 'nothello', '--use', '..' + dir_separator() + target, complain_on_error=False) assert_match(".*nothello is already pinned with pin .*", p.out) # Try to repin to a dir with valid crate metadata p = run_alr('with', 'nothello', '--use', '..' + dir_separator() + target, complain_on_error=False, force=True) # Expected error assert_match('.*expected nothello but found hello.*', p.out) # skip test-specific path print('SUCCESS') alire-1.2.1/testsuite/tests/pin/dir-mismatch/test.yaml000066400000000000000000000001131430264165500230150ustar00rootroot00000000000000driver: python-script indexes: solver_index: in_fixtures: true alire-1.2.1/testsuite/tests/pin/downgrade/000077500000000000000000000000001430264165500205505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/downgrade/my_index/000077500000000000000000000000001430264165500223645ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/downgrade/my_index/index/000077500000000000000000000000001430264165500234735ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/downgrade/my_index/index/index.toml000066400000000000000000000000201430264165500254670ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/downgrade/my_index/index/li/000077500000000000000000000000001430264165500240775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/downgrade/my_index/index/li/libchild/000077500000000000000000000000001430264165500256515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/downgrade/my_index/index/li/libchild/libchild-0.1.0.toml000066400000000000000000000002641430264165500307540ustar00rootroot00000000000000description = "Child" name = "libchild" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/downgrade/my_index/index/li/libchild/libchild-0.2.0.toml000066400000000000000000000002641430264165500307550ustar00rootroot00000000000000description = "Child" name = "libchild" version = "0.2.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/downgrade/my_index/index/li/libparent/000077500000000000000000000000001430264165500260575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/downgrade/my_index/index/li/libparent/libparent-1.0.0.toml000066400000000000000000000003251430264165500313660ustar00rootroot00000000000000description = "Parent" name = "libparent" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[depends-on]] libchild = "*" [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/downgrade/test.py000066400000000000000000000025011430264165500220770ustar00rootroot00000000000000""" Test that a pin to a lower version downgrades and retrieves the new version """ import os from drivers.alr import run_alr, alr_pin, alr_lockfile from drivers.asserts import assert_eq, assert_match from drivers.helpers import check_line_in import os import re # Verify that proper version of libchild is in the printed and disk solution def check_child(version, output, pinned): # Verify output assert_match('.*\n' 'Dependencies \(solution\):\n' ' libchild=' + version + (" \(pinned\)" if pinned else "") + '.*\n', output, flags=re.S) # Verify lockfile check_line_in(alr_lockfile(), 'name = "libchild"') check_line_in(alr_lockfile(), f'version = "{version}"') # Verify dependency folders assert os.path.exists('alire/cache/dependencies/libchild_' + version + '_filesystem') # Create a new "xxx" program project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Make it depend on child (there are 0.1 and 0.2, so 0.2 used initially) run_alr('with', 'libchild>0') p = run_alr('show', '--solve') check_child('0.2.0', p.out, pinned=False) # Pin it to a downgrade alr_pin('libchild', version='0.1') # Verify new version p = run_alr('show', '--solve') check_child('0.1.0', p.out, pinned=True) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/downgrade/test.yaml000066400000000000000000000001101430264165500224030ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/pin/equivalent/000077500000000000000000000000001430264165500207535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/equivalent/test.py000066400000000000000000000027261430264165500223130ustar00rootroot00000000000000""" Verify that using manual edition and `alr pin` result in equivalent outputs """ from drivers.alr import run_alr, alr_pin, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import init_git_repo, git_branch import os import shutil def check_equivalent(crate, path="", url="", commit="", branch=""): """ Run manual and auto and compare outputs """ manual = [False, True] p = [None, None] for i in [0, 1]: init_local_crate() # run command alr_pin(crate=crate, path=path, url=url, commit=commit, branch=branch, manual=manual[i]) # get pins output p[i] = run_alr("pin").out if i == 1: assert_eq(p[0], p[1]) # Cleanup os.chdir("..") shutil.rmtree("xxx") # Local pinnable crate init_local_crate("yyy", enter=False) yyy_path = "../yyy" # Local pinnable raw project os.mkdir("zzz") zzz_path = "../zzz" # Simple pin, no restrictions check_equivalent("yyy", path=yyy_path) check_equivalent("zzz", path=zzz_path) # Prepare repository head = init_git_repo("yyy") branch = git_branch("yyy") os.rename("yyy", "yyy.git") # to be recognizable as a git url url = "../yyy.git" # Simple git remote, explicit crate check_equivalent(crate="yyy", url=url) # Explicit commit check_equivalent(crate="yyy", url=url, commit=head) # Explicit branch check_equivalent(crate="yyy", url=url, branch=branch) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/equivalent/test.yaml000066400000000000000000000000631430264165500226150ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/000077500000000000000000000000001430264165500227775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/000077500000000000000000000000001430264165500246135ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/crates/000077500000000000000000000000001430264165500260745ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/crates/crate/000077500000000000000000000000001430264165500271725ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/crates/crate/.emptydir000066400000000000000000000000001430264165500310160ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/index/000077500000000000000000000000001430264165500257225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/index/cr/000077500000000000000000000000001430264165500263265ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/index/cr/crate/000077500000000000000000000000001430264165500274245ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/index/cr/crate/crate-1.0.0.toml000066400000000000000000000002661430264165500320550ustar00rootroot00000000000000description = "Sample crate" name = "crate" version = "1.0.0" licenses = [] maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] url = "file:../../../crates/crate" alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/my_index/index/index.toml000066400000000000000000000000201430264165500277160ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/test.py000066400000000000000000000047261430264165500243410ustar00rootroot00000000000000""" Verify various bad pins in the manifest are rejected """ from drivers.alr import run_alr, init_local_crate, alr_lockfile, alr_manifest from drivers.helpers import lines_of from drivers.asserts import assert_match import os.path def check(pin, error): """ Insert a pin at the end of the manifest, verify that it is rejected, and remove it from the manifest. Check the error produced against the one given """ with open(alr_manifest(), "a") as manifest: manifest.write("\n[[pins]]\n" + pin + "\n") # Remove lockfile to ensure reload if os.path.exists(alr_lockfile()): os.remove(alr_lockfile()) p = run_alr("pin", complain_on_error=False) assert p.status != 0, "Unexpected success for pin: " + pin assert_match(".*Cannot continue with invalid session.*" + error + ".*\n", p.out) # Restore the manifest lines = lines_of(alr_manifest()) lines.pop() with open(alr_manifest(), "w") as manifest: manifest.write("".join(lines)) # Verify the manifest is OK again run_alr("pin") init_local_crate() # Invalid empty pins check("foo = { }", "invalid pin description") check("foo = ''", "Malformed semantic version in pin") # Single string must be a version check("foo = 'https://github.com/alire-project/alire.git'", "Malformed semantic version in pin") # Mixed incompatible fields check("foo = { version = '3', url='https://' }", "forbidden extra entries") check("foo = { path = '/', url='https://' }", "forbidden extra entries") check("foo = { path = '/', version='6976' }", "forbidden extra entries") check("foo = { path = '/', " "commit = '0123456789012345678901234567890123456789' }", "forbidden extra entries") # Extraneous field check("foo = { wont_ever_exist='' }", "invalid pin description") # Commit without url check("foo = { commit = '0123456789012345678901234567890123456789' }", "invalid pin description") # Invalid commit check("foo = { url = 'https://', commit = '1234abcd' }", "invalid commit") # Extra unknown field check("foo = { version = '3', wont_exist='' }", "forbidden extra entries") check("foo = { path = '/', wont_exist='' }", "forbidden extra entries") check("foo = { url = 'https://', wont_exist='' }", "forbidden extra entries") check("foo = { url = 'https://', wont_exist='', " "commit = '0123456789012345678901234567890123456789' }", "forbidden extra entries") print('SUCCESS') alire-1.2.1/testsuite/tests/pin/manifest-invalid-pins/test.yaml000066400000000000000000000001101430264165500246320ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/pin/missing-version/000077500000000000000000000000001430264165500217325ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/missing-version/test.py000066400000000000000000000027231430264165500232670ustar00rootroot00000000000000""" Pin forcibly a dependency that cause missing dependencies """ import re import os from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_match from glob import glob # Initialize a new crate and add the "hello*" dependency. This is solved as: # xxx=0.0.0 -> hello=1.0.1 --> libhello=1.1.0 run_alr('init', '--bin', 'xxx') os.chdir('xxx') run_alr('with', 'hello>0') # 1st test: pin to an existing version that brings in missing dependencies. # Pinning hello=3 brings in a libhello^3 dependency that is unavailable, so: # xxx=0.0.0 -> hello=3.0.0 --> libhello^3 (missing) alr_pin('hello', version='3') # Check solution is as expected p = run_alr('with', '--solve') assert_match('.*Dependencies \(solution\):\n' ' hello=3\.0\.0 \(pinned\).*\n' # skip irrelevant origin info '.*Dependencies \(external\):\n' ' libhello\^3\.0.*', p.out, flags=re.S) # 2nd test: directly pin to a missing version (hello=5). This causes libhello # to disappear from the solution, since hello's dependencies are now unknown: # xxx=0.0.0 -> hello=5 (missing) alr_pin('hello', version='5') # Check solution is as expected. Depending on the solver options and # optimizations, this may show as hello=5.0.0 or hello(=5.0.0&>0), hence the # permissive regex p = run_alr('with', '--solve') assert_match('.*Dependencies \(external\):\n' ' hello.*=5\.0\.0.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/missing-version/test.yaml000066400000000000000000000000641430264165500235750ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/pin/pin-dir-with-regular/000077500000000000000000000000001430264165500225505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/pin-dir-with-regular/my_index/000077500000000000000000000000001430264165500243645ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/pin-dir-with-regular/my_index/index.toml000066400000000000000000000000201430264165500263600ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/pin-dir-with-regular/my_index/li/000077500000000000000000000000001430264165500247705ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/pin-dir-with-regular/my_index/li/libhello/000077500000000000000000000000001430264165500265625ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/pin-dir-with-regular/my_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003151430264165500317020ustar00rootroot00000000000000description = "libhello" name = "libhello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["some@one.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/tests/pin/pin-dir-with-regular/test.py000066400000000000000000000016151430264165500241040ustar00rootroot00000000000000""" Test that pinning another crate doesn't affect a regularly solved one """ import os import re from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_match # Initialize a workspace, enter, and add a regular dependency run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Add a regular solvable dependency run_alr('with', 'libhello') # Add a missing crate run_alr('with', 'unobtanium', force=True) # Pin the missing crate alr_pin('unobtanium', path='/') # Check the solution shows both pinned dir and regular dependency p = run_alr('with', '--solve') # For this match we don't know where the test is temporarily put, so we skip # over some parts of the output assert_match('.*Dependencies \(solution\):.*' 'libhello=1\.0\.0.*' 'Dependencies \(external\):.*' 'unobtanium\* \(direct,linked,.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/pin-dir-with-regular/test.yaml000066400000000000000000000001461430264165500244140ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/pin/pin-dir/000077500000000000000000000000001430264165500201405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/pin-dir/my_index/000077500000000000000000000000001430264165500217545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/pin-dir/my_index/index.toml000066400000000000000000000000201430264165500237500ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/pin-dir/my_index/li/000077500000000000000000000000001430264165500223605ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/pin-dir/my_index/li/libhello/000077500000000000000000000000001430264165500241525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/pin-dir/my_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003151430264165500272720ustar00rootroot00000000000000description = "libhello" name = "libhello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["some@one.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/tests/pin/pin-dir/test.py000066400000000000000000000025441430264165500214760ustar00rootroot00000000000000""" Replacing a dependency with a pinned folder """ import os import re from drivers.alr import run_alr, alr_pin, alr_unpin from drivers.asserts import assert_match from drivers.helpers import dir_separator, with_project # Initialize a workspace, enter, and add a regular dependency run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Prepend the library we want to use to its project file with_project('xxx.gpr', 'libhello') # Verify it doesn't build without it p = run_alr('build', complain_on_error=False) assert p.status != 0, "Build should fail" # Add normally and then pin, check that it builds run_alr('with', 'libhello') alr_pin('libhello', path='../crates/libhello_1.0.0') run_alr('build') # Check the pin shows in the solution p = run_alr('with', '--solve') # For this match we don't know where the test is temporarily put, so we skip # over some parts of the output assert_match('.*Dependencies \(external\):.*' 'libhello\^1.0.0 \(direct,linked' ',path=../crates/libhello_1.0.0\).*', # relative, always fwd slash p.out, flags=re.S) # Check that unpinning the dependency works and now the dependency is show # as a regular one from the index alr_unpin('libhello') p = run_alr('show', '--solve') assert_match('.*Dependencies \(solution\):' '.*libhello=1.0.0.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/pin-dir/test.yaml000066400000000000000000000001461430264165500220040ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/pin/portable-path/000077500000000000000000000000001430264165500213405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/portable-path/test.py000066400000000000000000000022551430264165500226750ustar00rootroot00000000000000""" Verify that, in windows, an absolute path is accepted but a relative one is preferred to be given in portable format (forward slashes) """ from drivers.alr import run_alr, alr_pin, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import on_windows import os # Dependency to be pinned with absolute path init_local_crate(name="dep_absolute") path_absolute = os.getcwd() os.chdir("..") # Dependency to be pinned with portable relative path init_local_crate(name="dep_portable", enter=False) # Dependency to be pinned with bad relative path init_local_crate(name="dep_not_portable", enter=False) # Dependent main crate init_local_crate() # Should not cause error alr_pin("dep_absolute", path=path_absolute) # Should not cause error alr_pin("dep_portable", path="../dep_portable") # Now the update should detect the bad path. This check is only useful on Win if on_windows(): alr_pin("dep_not_portable", path=r"..\dep_not_portable", update=False) p = run_alr("update", complain_on_error=False) assert_match(".*Pin relative paths must use " "forward slashes to be portable.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/portable-path/test.yaml000066400000000000000000000000631430264165500232020ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/post-update/000077500000000000000000000000001430264165500210435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/post-update/my_index/000077500000000000000000000000001430264165500226575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/post-update/my_index/index/000077500000000000000000000000001430264165500237665ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/post-update/my_index/index/index.toml000066400000000000000000000000201430264165500257620ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/post-update/my_index/index/li/000077500000000000000000000000001430264165500243725ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/post-update/my_index/index/li/libchild/000077500000000000000000000000001430264165500261445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/post-update/my_index/index/li/libchild/libchild-0.1.0.toml000066400000000000000000000002641430264165500312470ustar00rootroot00000000000000description = "Child" name = "libchild" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/post-update/my_index/index/li/libchild/libchild-0.2.0.toml000066400000000000000000000002641430264165500312500ustar00rootroot00000000000000description = "Child" name = "libchild" version = "0.2.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/post-update/my_index/index/li/libparent/000077500000000000000000000000001430264165500263525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/post-update/my_index/index/li/libparent/libparent-1.0.0.toml000066400000000000000000000003251430264165500316610ustar00rootroot00000000000000description = "Parent" name = "libparent" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[depends-on]] libchild = "*" [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/post-update/test.py000066400000000000000000000034501430264165500223760ustar00rootroot00000000000000""" Test that a pinned release does not get updated """ import os from drivers.alr import run_alr, alr_pin, alr_unpin, alr_lockfile from drivers.asserts import assert_eq, assert_match from drivers.helpers import check_line_in import re # Verify that proper version of libchild is in the printed and disk solution def check_child(version, output, pinned): # Verify output assert_match('.*\n' 'Dependencies \(solution\):\n' ' libchild=' + version + (' \(pinned\)' if pinned else "") + '\n' ' libparent=1\.0\.0\n' '.*\n', output, flags=re.S) # Verify lockfile check_line_in(alr_lockfile(), 'name = "libchild"') check_line_in(alr_lockfile(), f'version = "{version}"') # Create a new "xxx" program project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Make it depend on child=0.1 (there is also 0.2) run_alr('with', 'libchild=0.1') # Pin it alr_pin('libchild', version="0.1") # To avoid pinning and downgrading (that's a different test), we depend on # a crate that also depends on libchild. This way we can remove the exact # libchild dependency and verify the pin holds run_alr('with', 'libparent') # Remove child dependency run_alr('with', '--del', 'libchild') # But keeping the pin (alr with --del will remove also the pin) alr_pin('libchild', version="0.1") # Verify pinned version is still in the solution, pre-update: p = run_alr('show', '--solve') check_child('0.1.0', p.out, pinned=True) # Run an update and verify solution is still the same run_alr('update') p = run_alr('show', '--solve') check_child('0.1.0', p.out, pinned=True) # Unpin and check upgraded solution alr_unpin('libchild') p = run_alr('show', '--solve') check_child('0.2.0', p.out, pinned=False) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/post-update/test.yaml000066400000000000000000000001101430264165500226760ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/pin/recursive-local/000077500000000000000000000000001430264165500216755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/recursive-local/test.py000066400000000000000000000012401430264165500232230ustar00rootroot00000000000000""" Verify that recursive pins work for local paths """ from drivers.alr import run_alr, alr_pin, init_local_crate from drivers.asserts import assert_eq, assert_match import os # We are going to setup xxx --> yyy --> zzz, where xxx and zzz live at the # same level, and yyy is at ./nest/yyy init_local_crate(name="zzz", enter=False) os.mkdir("nest") os.chdir("nest") init_local_crate(name="yyy") alr_pin("zzz", path="../../zzz") os.chdir("..") os.chdir("..") init_local_crate() alr_pin("yyy", path="../nest/yyy") # Should work properly p = run_alr("pin") assert_eq('yyy file:../nest/yyy \n' 'zzz file:../zzz \n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/recursive-local/test.yaml000066400000000000000000000000631430264165500235370ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/recursive-remote/000077500000000000000000000000001430264165500220765ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/recursive-remote/test.py000066400000000000000000000026031430264165500234300ustar00rootroot00000000000000""" Verify that recursive pins work for remote urls (simulated as local git remotes using absolute paths) """ from drivers.alr import run_alr, alr_pin, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import init_git_repo, dir_separator import re import os # We are going to setup xxx --> yyy --> zzz, where xxx and zzz live at the # same level, and yyy is at ./nest/yyy. Both yyy and zzz will be git # repositories, so we refer to them by their absolute path (as if they were # remote URLs) # zzz crate/repo init_local_crate(name="zzz", enter=False) path_zzz = os.path.join(os.getcwd(), "zzz") init_git_repo(path_zzz) # yyy crate/repo os.mkdir("nest") os.chdir("nest") init_local_crate(name="yyy") alr_pin("zzz", url=path_zzz) os.chdir("..") path_yyy = os.path.join(os.getcwd(), "yyy") init_git_repo(path_yyy) # xxx crate os.chdir("..") init_local_crate() alr_pin("yyy", url=path_yyy) # Should work properly p = run_alr("pin") # Absolute path to simulate a remote URL is platform dependent: s = dir_separator() assert_match(re.escape('yyy file:alire/cache/pins/yyy ') + # local rel path '.*' + re.escape(f'{s}nest{s}yyy\n') + # remote abs url re.escape('zzz file:alire/cache/pins/zzz ') + # local rel path '.*' + re.escape(f'{s}zzz \n'), # remote abs url p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/recursive-remote/test.yaml000066400000000000000000000000631430264165500237400ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/remote/000077500000000000000000000000001430264165500200715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/remote/test.py000066400000000000000000000040201430264165500214160ustar00rootroot00000000000000""" Check pinning to a remote, cleanup and redeploy """ import os import shutil from drivers.alr import run_alr, init_local_crate from drivers.helpers import init_git_repo, git_branch from drivers.asserts import assert_eq def verify(head=""): # Either head or branch /= "" # Check that the linked dir exists at the expected location pin_path = (f"alire/cache/pins/upstream" + ("" if head == "" else f"_{head[:8]}")) assert os.path.isdir(pin_path) # Verify info reported by alr p = run_alr("pin") assert_eq(f"upstream file:{pin_path} ../upstream.git" + ("" if head == "" else f"#{head[0:8]}") + "\n", p.out) # Verify building with pinned dependency run_alr("build") # Verify removal of cached download run_alr("clean", "--cache") assert not os.path.isdir(pin_path) # Verify automatic redownload when needed run_alr("build") # Prepare for next test run_alr("with", "--del", "upstream") # Remove dependency p = run_alr("pin") assert_eq(f"There are no pins\n", p.out) # Ensure pin is gone shutil.rmtree("alire") # Total cleanup outside of alr # Initialize a git repo that will act as the "online" remote init_local_crate(name="upstream", binary=False) head = init_git_repo(".") os.chdir("..") os.rename("upstream", "upstream.git") # so it is recognized as git repo # Initialize a client crate that will use the remote init_local_crate() # This leaves us inside the new crate # Add using with directly run_alr("with", "--use", "../upstream.git", "--commit", head) verify(head) # Add using with, without head commit run_alr("with", "--use", "../upstream.git") verify() # Pin afterwards, with commit run_alr("with", "upstream", force=True) # force, as it is unsolvable run_alr("pin", "upstream", "--use", "../upstream.git", "--commit", head) verify(head) # Pin afterwards, without commit run_alr("with", "upstream", force=True) run_alr("pin", "upstream", "--use", "../upstream.git") verify() print('SUCCESS') alire-1.2.1/testsuite/tests/pin/remote/test.yaml000066400000000000000000000000631430264165500217330ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/to-parent/000077500000000000000000000000001430264165500205075ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/to-parent/test.py000066400000000000000000000017741430264165500220510ustar00rootroot00000000000000""" Check that a pin to the parent crate results in a simple ".." relative path. This is for the common case of testing/demo subcrates """ from drivers.alr import run_alr, init_local_crate, alr_pin, alr_manifest from drivers.helpers import lines_of, content_of from shutil import rmtree import os def try_path(path: str): """ Pin the parent crate using the given path, that must be equivalent to ".." """ if os.path.isdir("child"): rmtree("child") init_local_crate("child") alr_pin("parent", path=path, manual=False) # This should result in the pin being simplified to ".." assert "parent = { path='..' }\n" in lines_of(alr_manifest()), \ "Unexpected manifest contents: " + content_of(alr_manifest()) os.chdir("..") # We entered during init_local_crate() init_local_crate("parent") # We enter it by default # Try some variants try_path("..") try_path("../") try_path("../../parent") try_path("src/../..") try_path("src/../../../parent") print('SUCCESS') alire-1.2.1/testsuite/tests/pin/to-parent/test.yaml000066400000000000000000000000261430264165500223500ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/pin/twice-in-manifest/000077500000000000000000000000001430264165500221215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/twice-in-manifest/my_index/000077500000000000000000000000001430264165500237355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/twice-in-manifest/my_index/index.toml000066400000000000000000000000201430264165500257310ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/twice-in-manifest/my_index/li/000077500000000000000000000000001430264165500243415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/twice-in-manifest/my_index/li/libhello/000077500000000000000000000000001430264165500261335ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/twice-in-manifest/my_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003151430264165500312530ustar00rootroot00000000000000description = "libhello" name = "libhello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["some@one.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/tests/pin/twice-in-manifest/test.py000066400000000000000000000013541430264165500234550ustar00rootroot00000000000000""" Detect a crate with two pins in the manifest """ import os import re from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_match from drivers.helpers import dir_separator # Initialize a workspace, enter, and add a regular dependency run_alr('init', '--bin', 'xxx') os.chdir('xxx') run_alr('with', 'libhello^1') # Pin to a version alr_pin('libhello', version='1.0') # Manually force a second pin with open("alire.toml", "at") as manifest: manifest.write("[[pins]]\n") manifest.write("libhello = { path = '.' }\n") # Check that the second pin is rejected p = run_alr('pin', complain_on_error=False) assert_match('.*pin for crate libhello is specified more than once.*', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/twice-in-manifest/test.yaml000066400000000000000000000001461430264165500237650ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/pin/unneeded-held/000077500000000000000000000000001430264165500212775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/000077500000000000000000000000001430264165500231135ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/index/000077500000000000000000000000001430264165500242225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/index/index.toml000066400000000000000000000000201430264165500262160ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/index/li/000077500000000000000000000000001430264165500246265ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/index/li/libchild/000077500000000000000000000000001430264165500264005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/index/li/libchild/libchild-0.1.0.toml000066400000000000000000000002641430264165500315030ustar00rootroot00000000000000description = "Child" name = "libchild" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/index/li/libchild/libchild-0.2.0.toml000066400000000000000000000002641430264165500315040ustar00rootroot00000000000000description = "Child" name = "libchild" version = "0.2.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/index/li/libparent/000077500000000000000000000000001430264165500266065ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/unneeded-held/my_index/index/li/libparent/libparent-1.0.0.toml000066400000000000000000000003251430264165500321150ustar00rootroot00000000000000description = "Parent" name = "libparent" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[depends-on]] libchild = "*" [origin] url = "file:." alire-1.2.1/testsuite/tests/pin/unneeded-held/test.py000066400000000000000000000022651430264165500226350ustar00rootroot00000000000000""" Test that removing a pinned dependency keeps the pinned release in the solution """ import os from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_eq, assert_match from drivers.helpers import check_line_in import os import re # Create a new "xxx" program project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Make it depend on a couple of crates (simplifies checking the solution later) # libparent depends on libchild run_alr('with', 'libparent') # Pin the child alr_pin('libchild', version='0.2') # Remove parent run_alr('with', '--del', 'libparent') # Check pin is there p = run_alr('pin') assert_eq('libchild 0.2.0\n', p.out) # Check that there are no dependencies p = run_alr('with') assert_eq("Dependencies (direct):\n" " (empty)\n" "Pins (direct):\n" " libchild = { version='0.2.0' }\n", p.out) # But the pinned release is still in the solution p = run_alr('with', '--solve') assert_match('.*' 'Dependencies \(solution\):\n' ' libchild=0\.2\.0 \(pinned\) \(origin: filesystem\)\n' 'Dependencies \(graph\):.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/unneeded-held/test.yaml000066400000000000000000000001101430264165500231320ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/pin/unpin/000077500000000000000000000000001430264165500177275ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/unpin/test.py000066400000000000000000000015351430264165500212640ustar00rootroot00000000000000""" Test unpinning """ import os from drivers.alr import run_alr, alr_pin, alr_unpin, alr_lockfile from drivers.asserts import assert_eq from drivers.helpers import check_line_in # Create a new "xxx" program project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Make it depend on libhello run_alr('with', 'libhello') # Pin the version of libhello and verify pin is there alr_pin('libhello', version="1") p = run_alr('pin') assert_eq('libhello 1.0.0\n', p.out) # Update and verify that the pin has survived run_alr('update') p = run_alr('pin') assert_eq('libhello 1.0.0\n', p.out) # Delete lockfile and verify the pin has survived os.remove(alr_lockfile()) p = run_alr('pin') assert_eq('libhello 1.0.0\n', p.out) # Unpin and verify pin is not there alr_unpin('libhello') p = run_alr('pin') assert_eq('There are no pins\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/unpin/test.yaml000066400000000000000000000001121430264165500215640ustar00rootroot00000000000000driver: python-script indexes: basic_index: in_fixtures: true alire-1.2.1/testsuite/tests/pin/version/000077500000000000000000000000001430264165500202635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/version/test.py000066400000000000000000000023101430264165500216100ustar00rootroot00000000000000""" Test pinning to a version """ from drivers.alr import run_alr, alr_pin, alr_with, init_local_crate from drivers.asserts import assert_eq, assert_match init_local_crate() alr_with("hello") # Test pinning to the version currently in the solution alr_pin("hello", manual=False) p = run_alr("pin") assert_eq("hello 1.0.1\n", p.out) # Test pinning to a different explicit version alr_pin("hello", version="1.0", manual=False, force=True) p = run_alr("pin") assert_eq("hello 1.0.0\n", p.out) # Test that trying to use a non-equal restriction fails p = run_alr("pin", "hello^1.0", complain_on_error=False) assert_eq("ERROR: Plain crate name or crate=version argument expected" " for pinning, but got: hello^1.0\n", p.out) # Test that pinning to a non-existent version is doable but solution is missing p = run_alr("pin", "hello=7.7.7", force=True) p = run_alr("pin") assert_eq("hello 7.7.7\n", p.out) p = run_alr("with", "--solve") assert_eq("""\ Dependencies (direct): hello* Pins (direct): hello = { version='7.7.7' } Dependencies (external): hello=7.7.7 (direct,missed,pin=7.7.7) (pinned) Dependencies (graph): xxx=0.1.0-dev --> hello* """, p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/version/test.yaml000066400000000000000000000000631430264165500221250ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/pin/without-lockfile/000077500000000000000000000000001430264165500220675ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/pin/without-lockfile/test.py000066400000000000000000000011271430264165500234210ustar00rootroot00000000000000""" Verify that pins when there is no lockfile are correctly applied on first run """ from drivers.alr import run_alr, alr_pin, init_local_crate, alr_lockfile from drivers.asserts import assert_eq import os fake_dep = "unobtainium" # Create a crate init_local_crate() # Add a dependency run_alr("with", fake_dep, force=True) # Pin to a local folder os.mkdir(fake_dep) alr_pin(fake_dep, path=fake_dep) # Remove the lockfile os.remove(alr_lockfile()) # Check that the pin is applied on next command run p = run_alr("pin") assert_eq(f"{fake_dep} file:{fake_dep} \n", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/pin/without-lockfile/test.yaml000066400000000000000000000001121430264165500237240ustar00rootroot00000000000000driver: python-script indexes: basic_index: in_fixtures: true alire-1.2.1/testsuite/tests/printenv/000077500000000000000000000000001430264165500176555ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/basic/000077500000000000000000000000001430264165500207365ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/basic/test.py000066400000000000000000000032631430264165500222730ustar00rootroot00000000000000""" Test the environment set for a basic crate """ from glob import glob import os from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match import re import platform # Get the "hello" project and enter its directory run_alr('get', 'hello') os.chdir(glob('hello*')[0]) # Run it not quietly to ensure that at normal level # the output is not broken by some log message p = run_alr('printenv', quiet=False) assert_eq(0, p.status) def make_path(list): if platform.system() == 'Windows': return "\\\\".join(list) else: return "/".join(list) expected_hello_path = make_path(['.*', 'hello_1.0.1_filesystem']) expected_libhello_path = make_path(['.*', 'alire', 'cache', 'dependencies', 'libhello_1\.0\.0_filesystem']) expected_gpr_path = os.pathsep.join([expected_hello_path, expected_libhello_path]) assert_match('export ALIRE="True"\n' '.*' 'export GPR_PROJECT_PATH="' + expected_gpr_path + '"\n' '.*' 'export HELLO_ALIRE_PREFIX="' + expected_hello_path + '"\n' '.*' 'export LIBHELLO_ALIRE_PREFIX="' + expected_libhello_path + '"\n' '.*' 'export TEST_GPR_EXTERNAL="gpr_ext_B"\n' '.*', p.out, flags=re.S) # Verify that project paths are prepended before anything that the user already # has configured in the environment, so for example GNAT libraries do not get # mixed (compiler in PATH is ours but libraries are from the user). os.environ["GPR_PROJECT_PATH"] = "canary" assert_match( '.*' f'export GPR_PROJECT_PATH="{expected_gpr_path}{os.pathsep}canary"\n', run_alr('printenv', quiet=False).out) print('SUCCESS') alire-1.2.1/testsuite/tests/printenv/basic/test.yaml000066400000000000000000000000631430264165500226000ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/printenv/compiler-indirect/000077500000000000000000000000001430264165500232665ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/compiler-indirect/test.py000066400000000000000000000025761430264165500246310ustar00rootroot00000000000000""" This is an attempt to replicate the bug fixed in #875. The root cause was that a crate preceding "gnat" alphabetically was used to provide the environment for GNAT, due to a mistype in the function that returns the concrete crate that fills in for a virtual crate. Hence, we setup a root crate, that depends on "gnat" and "another_crate" (which comes first alphabetically), and verify the environment contains the compiler. """ import os import re import subprocess from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match from drivers.helpers import dir_separator # Install a binary compiler for later use run_alr("toolchain", "--select", "gnat_native") init_local_crate("another_crate") # This enters the crate alr_with("gnat") # Make it depend on gnat (in the original bug, the dependency # was also indirect, although it would have been a problem with a direct # dependency as well). os.chdir("..") # Back to root folder init_local_crate() alr_with(path="../another_crate", manual=False) # Autodetect the linked crate p = run_alr("printenv") s = re.escape(dir_separator()) # Ensure the compiler-set flag is in there: assert_match(".*export TEST_PATH=.*" f"printenv__compiler-indirect{s}alr-config{s}cache{s}" f"dependencies{s}gnat_native_8888\.0\.0_99fa3a55{s}bin", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/printenv/compiler-indirect/test.yaml000066400000000000000000000001161430264165500251270ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/printenv/double-set/000077500000000000000000000000001430264165500217205ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/000077500000000000000000000000001430264165500235345ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/crates/000077500000000000000000000000001430264165500250155ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/crates/checkenv/000077500000000000000000000000001430264165500266035ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/crates/checkenv/checkenv.gpr000066400000000000000000000007411430264165500311050ustar00rootroot00000000000000project Checkenv is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Exec_Dir use "."; for Main use ("checkenv.adb"); package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end Checkenv; alire-1.2.1/testsuite/tests/printenv/double-set/my_index/crates/checkenv/src/000077500000000000000000000000001430264165500273725ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/crates/checkenv/src/checkenv.adb000066400000000000000000000006241430264165500316320ustar00rootroot00000000000000with GNAT.IO; use GNAT.IO; with GNAT.OS_Lib; use GNAT.OS_Lib; procedure Checkenv is begin -- Check that "CHECKENV_TEST_VAR" is defined and print message accordingly -- to stderr if Getenv ("CHECKENV_TEST_VAR").all /= "" then Put_Line (Standard_Error, "CHECKENV_TEST_VAR exists"); else Put_Line (Standard_Error, "CHECKENV_TEST_VAR does NOT exist"); end if; end Checkenv; alire-1.2.1/testsuite/tests/printenv/double-set/my_index/index/000077500000000000000000000000001430264165500246435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/index/ch/000077500000000000000000000000001430264165500252355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/index/ch/checkenv/000077500000000000000000000000001430264165500270235ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/index/ch/checkenv/checkenv-1.0.0.toml000066400000000000000000000003541430264165500321420ustar00rootroot00000000000000description = "Sample crate" name = "checkenv" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [gpr-set-externals] DOUBLE = "set" [origin] url = "file:../../../crates/checkenv" alire-1.2.1/testsuite/tests/printenv/double-set/my_index/index/ch/checkparent/000077500000000000000000000000001430264165500275245ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/double-set/my_index/index/ch/checkparent/checkparent-1.0.0.toml000066400000000000000000000003671430264165500333500ustar00rootroot00000000000000description = "Sample crate" name = "checkparent" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [gpr-set-externals] DOUBLE = "set" [[depends-on]] checkenv = "*" [origin] url = "file:." alire-1.2.1/testsuite/tests/printenv/double-set/my_index/index/index.toml000066400000000000000000000000201430264165500266370ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/printenv/double-set/test.py000066400000000000000000000005521430264165500232530ustar00rootroot00000000000000""" Check that an env var can be set twice to the same value """ import os import re from drivers.alr import init_local_crate, run_alr from drivers.asserts import assert_match # Create a local workspace and enter it init_local_crate() # checkparent depends on checkenv that sets the same environment variable run_alr("with", "checkparent") print('SUCCESS') alire-1.2.1/testsuite/tests/printenv/double-set/test.yaml000066400000000000000000000001101430264165500235530ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/printenv/env-during-fetch/000077500000000000000000000000001430264165500230225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/000077500000000000000000000000001430264165500246365ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/crates/000077500000000000000000000000001430264165500261175ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/crates/checkenv/000077500000000000000000000000001430264165500277055ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/crates/checkenv/checkenv.gpr000066400000000000000000000007411430264165500322070ustar00rootroot00000000000000project Checkenv is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Exec_Dir use "."; for Main use ("checkenv.adb"); package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end Checkenv; alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/crates/checkenv/src/000077500000000000000000000000001430264165500304745ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/crates/checkenv/src/checkenv.adb000066400000000000000000000006241430264165500327340ustar00rootroot00000000000000with GNAT.IO; use GNAT.IO; with GNAT.OS_Lib; use GNAT.OS_Lib; procedure Checkenv is begin -- Check that "CHECKENV_TEST_VAR" is defined and print message accordingly -- to stderr if Getenv ("CHECKENV_TEST_VAR").all /= "" then Put_Line (Standard_Error, "CHECKENV_TEST_VAR exists"); else Put_Line (Standard_Error, "CHECKENV_TEST_VAR does NOT exist"); end if; end Checkenv; alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/index/000077500000000000000000000000001430264165500257455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/index/ch/000077500000000000000000000000001430264165500263375ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/index/ch/checkenv/000077500000000000000000000000001430264165500301255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/index/ch/checkenv/checkenv-1.0.0.toml000066400000000000000000000005601430264165500332430ustar00rootroot00000000000000description = "Sample crate" name = "checkenv" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [[actions]] type = "post-fetch" command = ["gprbuild", "-p"] [[actions]] type = "post-fetch" command = ["./checkenv"] [environment.CHECKENV_TEST_VAR] set = "defined" [origin] url = "file:../../../crates/checkenv" alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/index/ch/checkparent/000077500000000000000000000000001430264165500306265ustar00rootroot00000000000000checkparent-1.0.0.toml000066400000000000000000000003231430264165500343630ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/index/ch/checkparentdescription = "Sample crate" name = "checkparent" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [[depends-on]] checkenv = "*" [origin] url = "file:." alire-1.2.1/testsuite/tests/printenv/env-during-fetch/my_index/index/index.toml000066400000000000000000000000201430264165500277410ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/printenv/env-during-fetch/test.py000066400000000000000000000016421430264165500243560ustar00rootroot00000000000000""" Check that an env var is defined during dependency retrieval (get and with) """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match def verify_output(text): assert_match('.*CHECKENV_TEST_VAR exists\n.*', text, flags=re.S) # The "checkenv" crate defines CHECKENV_TEST_VAR. Also, its executable prints # "CHECKENV_TEST_VAR exists" or "CHECKENV_TEST_VAR does NOT exist" when run. # The crate defines post-fetch actions to self-build and self-run, so the # output is generated at the moment we want to check. # Retrieve a crate that depends on checkenv: checkparent --> checkenv p = run_alr("get", "checkparent") verify_output(p.out) # Create a crate from scratch and add the same dependency to perform the check # during retrieval by `with` run_alr("init", "--bin", "xxx") os.chdir("xxx") p = run_alr("with", "checkenv") verify_output(p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/printenv/env-during-fetch/test.yaml000066400000000000000000000001101430264165500246550ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/printenv/linked-paths/000077500000000000000000000000001430264165500222405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/000077500000000000000000000000001430264165500240545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/crates/000077500000000000000000000000001430264165500253355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/crates/crate_1234/000077500000000000000000000000001430264165500271045ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/crates/crate_1234/.emptydir000066400000000000000000000000001430264165500307300ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/crates/crate_1234/alire.toml000066400000000000000000000002721430264165500310760ustar00rootroot00000000000000name = "crate_1234" version = "0.0.0" description = "Shiny new project" maintainers = ["your@email.here"] maintainers-logins = ["github-username"] project-files = ["nested/project.gpr"] alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/crates/crate_1234/alire/000077500000000000000000000000001430264165500302005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/crates/crate_1234/alire/.emptydir000066400000000000000000000000001430264165500320240ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/index/000077500000000000000000000000001430264165500251635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/linked-paths/my_index/index/index.toml000066400000000000000000000000201430264165500271570ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/printenv/linked-paths/test.py000066400000000000000000000023151430264165500235720ustar00rootroot00000000000000""" Check that both base path, and a extra project path for a softlinked crate is properly added to the environment """ import os import re import platform from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import dir_separator, path_separator # Initialize test crate run_alr("init", "--bin", "xxx") os.chdir("xxx") # Link a folder which also contains crate metadata for a project file inside a # 'nested'-named folder run_alr("with", "--use=../my_index/crates/crate_1234") expected_gpr_path = [] expected_gpr_path += [['.*', 'my_index', 'crates', 'crate_1234', 'nested']] expected_gpr_path += [['.*', 'xxx']] for i, path in enumerate(expected_gpr_path): if platform.system() == 'Windows': expected_gpr_path[i] = "\\\\".join(path) else: expected_gpr_path[i] = "/".join(path) expected_gpr_path = os.pathsep.join(expected_gpr_path) # Check paths are proper (base and one extra nested) p = run_alr("printenv") assert_match(('.*' 'export ALIRE="True"\n' '.*' 'export GPR_PROJECT_PATH="' + expected_gpr_path + '"\n' '.*').replace('/', re.escape(dir_separator())), p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/printenv/linked-paths/test.yaml000066400000000000000000000001101430264165500240730ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/printenv/with-external/000077500000000000000000000000001430264165500224505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/printenv/with-external/test.py000066400000000000000000000021141430264165500237770ustar00rootroot00000000000000""" Test the output when a external crate is in the dependencies """ from glob import glob import os from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match import re import platform # Retrieve a crate with an external dependency run_alr('get', 'libhello=0.9-test-unav-native', force=True) os.chdir('libhello_0.9.0_filesystem') # Run it not quietly to ensure that at normal level # the output is not broken by some log message p = run_alr('printenv', quiet=False) assert_eq(0, p.status) expected_gpr_path = "" if platform.system() == 'Windows': expected_gpr_path = '.*\\\\libhello_0.9.0_filesystem' else: expected_gpr_path = '.*/libhello_0.9.0_filesystem' # Check the printenv output assert_match('warn: Generating possibly incomplete environment' ' because of missing dependencies\n' # Note: this warning is via stderr so it's OK '.*' 'export ALIRE="True"\n' '.*' 'export GPR_PROJECT_PATH="' + expected_gpr_path + '"\n' '.*', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/printenv/with-external/test.yaml000066400000000000000000000000641430264165500243130ustar00rootroot00000000000000driver: python-script indexes: native_index: {} alire-1.2.1/testsuite/tests/publish/000077500000000000000000000000001430264165500174565ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/bad-arguments/000077500000000000000000000000001430264165500222075ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/bad-arguments/test.py000066400000000000000000000030361430264165500235420ustar00rootroot00000000000000""" Tests for bad arguments to publish """ from drivers.alr import run_alr from drivers.asserts import assert_match # Check that a local zip is rejected (as it must be remote) p = run_alr("publish", "file:/fake.zip", complain_on_error=False) assert_match(".*The origin must be a definitive remote location.*", p.out) # Bad combo, explicit file + commit p = run_alr("publish", "file:/fake.zip", "deadbeef", complain_on_error=False) assert_match(".*Expected a VCS origin but got.*", p.out) # Bad combo, implicit file + commit p = run_alr("publish", "fake.zip", "deadbeef", complain_on_error=False) assert_match(".*unknown VCS URL.*", p.out) # Missing commit for git remotes p = run_alr("publish", "git+http://github.com/repo", complain_on_error=False) assert_match(".*commit id is mandatory for a VCS origin.*", p.out) # Detect github case and give more precise error. This serves also to check # that github remotes without leading git+ or trailing .git are accepted. p = run_alr("publish", "https://github.com/missingext", complain_on_error=False) assert_match(".*commit id is mandatory for a VCS origin.*", p.out) # Bad commit length p = run_alr("publish", "git+http://github.com/repo", "deadbeef", complain_on_error=False) assert_match(".*invalid git commit id, 40 digits hexadecimal expected.*", p.out) # VCS without transport or extension p = run_alr("publish", "http://somehost.com/badrepo", "deadbeef", complain_on_error=False) assert_match(".*ambiguous VCS URL.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/publish/bad-arguments/test.yaml000066400000000000000000000000261430264165500240500ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/publish/broken-manifest/000077500000000000000000000000001430264165500225425ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/broken-manifest/test.py000066400000000000000000000012611430264165500240730ustar00rootroot00000000000000""" Check that a locally broken manifest is reported with its full error """ from drivers.alr import run_alr, init_local_crate from drivers.asserts import assert_match from drivers.helpers import contents, content_of, init_git_repo, zip_dir from shutil import copyfile, rmtree from zipfile import ZipFile import os # Prepare a repo for publishing and break its manifest init_local_crate() # Break the manifest with open("alire.toml", "wt") as manifest: manifest.write("\n---\n") # Attempt to publish; should fail with the expected syntax error p = run_alr("publish", force=True, complain_on_error=False) assert_match(".*invalid syntax at.*alire\.toml.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/publish/broken-manifest/test.yaml000066400000000000000000000000261430264165500244030ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/publish/check-build/000077500000000000000000000000001430264165500216305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-build/my_index/000077500000000000000000000000001430264165500234445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-build/my_index/crates/000077500000000000000000000000001430264165500247255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-build/my_index/crates/crate.tgz000066400000000000000000000010421430264165500265460ustar00rootroot00000000000000‹ÉZ_í–_o›0ÀyæSœü´J%3’‡ªÒ´®S*íeš&c\â„d`Y¿ýÎ@þ4Ò–t‘ªÝ/ X¹óÝ‘ó'­hÔ{oT82Owç ?¼oñÂé<šÅ< çS‡|q’qÃêiëFXo)Lù'½Sò7Šìòß]'yeGñá<‹ãßæ>¶ùG ê…QM=à£DsÄžÿÊ–K%¸s'tíûðTZx,[+Õ÷OÚÖÐÖ Þ±ÚJvu³•?¤nŸ“wbV¦K¶ÞÿTr/JµÙ‹> mƒý©YêÌ:y%äJä >¶ºÈ”uá@GÐF7r¡jÜ(2Á®#Á’³k`A>ĦL¶ÝÿÒè]¹®tqŽÕA ÎznDóEôp¹–Ýõ!b×;ÝAa¯Zv«'<^r  ¹:ˆpÌÑsksöcßׇÜmDcm÷·Þøç忯Líˆï€WôΓë?ŒyDýÿìó¿«ÆîãTÿç({™ÿiϨÿ_ìÿRe­Uû7@ªrm^ßIˆ·H_ÿ¢ÐVMšr]ŒáãTýGQr<ÿÍxHõ 2UK««F—n=.´y£60 †Ì_ãÀÖàWá x _}öŒ“á…?“…² g o‡JAQbÿtsÝ,Ú4À™Å±îuÝÂùêŽóàžÁ;Ÿà‡ùÔp‚ ‚ ‚ ‚ ‚ ‚ þž_-õ¥ƒ(alire-1.2.1/testsuite/tests/publish/check-build/my_index/crates/crate/000077500000000000000000000000001430264165500260235ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-build/my_index/crates/crate/alire.toml000066400000000000000000000002251430264165500300130ustar00rootroot00000000000000description = "Shiny new project" maintainers = [ "your@email.here", ] maintainers-logins = [ "github-username", ] name = "crate" version = "0.0.0" alire-1.2.1/testsuite/tests/publish/check-build/my_index/crates/crate/crate.gpr000066400000000000000000000007321430264165500276350ustar00rootroot00000000000000project Crate is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Exec_Dir use "bin"; for Main use ("crate.adb"); package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end Crate; alire-1.2.1/testsuite/tests/publish/check-build/my_index/crates/crate/src/000077500000000000000000000000001430264165500266125ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-build/my_index/crates/crate/src/crate.adb000066400000000000000000000000441430264165500303560ustar00rootroot00000000000000procedure Crate is begin end Crate; alire-1.2.1/testsuite/tests/publish/check-build/my_index/index/000077500000000000000000000000001430264165500245535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-build/my_index/index/cr/000077500000000000000000000000001430264165500251575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-build/my_index/index/cr/crate/000077500000000000000000000000001430264165500262555ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-build/my_index/index/cr/crate/crate-1.0.0.toml000066400000000000000000000005461430264165500307070ustar00rootroot00000000000000# NOTE: this crate is not used in the text, but we need at least one crate in # the index or the community index will get cloned due to empty in-memory # catalog. description = "Sample crate" name = "crate" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["any@bo.dy"] maintainers-logins = ["someone"] [origin] url = "file:../../../crates/crate" alire-1.2.1/testsuite/tests/publish/check-build/my_index/index/index.toml000066400000000000000000000000201430264165500265470ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/publish/check-build/test.py000066400000000000000000000004611430264165500231620ustar00rootroot00000000000000""" Tests that a failing build is reported during publishing """ from drivers.alr import run_alr from drivers.asserts import assert_match p = run_alr("publish", "my_index/crates/crate.tgz", complain_on_error=False, force=True) assert_match(".*Compilation failed.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/publish/check-build/test.yaml000066400000000000000000000001101430264165500234630ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/publish/check-properties/000077500000000000000000000000001430264165500227255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-properties/my_index/000077500000000000000000000000001430264165500245415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-properties/my_index/crates/000077500000000000000000000000001430264165500260225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-properties/my_index/crates/crate/000077500000000000000000000000001430264165500271205ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-properties/my_index/crates/crate/.emptydir000066400000000000000000000000001430264165500307440ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/publish/check-properties/my_index/crates/nomaint.tgz000066400000000000000000000010221430264165500302100ustar00rootroot00000000000000‹bêY_í–QoÛ €ýì_xZ¥:'¶¢½lëãÖ‡J{™¦ cê8`½lÿ~àâÆ‹¶¥•’HÕî‹°î¸;tÜ¥·LªîmtFˆ£È2?Ò"#Óq$¢ó"ÍçyFŠ<"”¦$PvΠFzÛ1ƒP´fJÿKï˜ü•¢BþÃ8«[sr>Áùbñ×ü‹Iþ‰Ó£óyF#DNÉøÏóß½¼CŸó¤c„Ѓ6èN÷†‹ûÒXÔ[Þ`k8¾ZŽòÛÒ¯ôòAŒu¹ÆO›‚ïE¥T{Ñ'ç(O«JoØk´ŒoX-Ðû^6•0> 40„´“_ ë–²Šá«`&Y|pR‡è„ªÆõ¿ý ·­lžc5ˆ‘·^+Ö}aÜt¦ÃÿmНŸtƒÂ^U³wÄø&q.øfáÌÁ¾¥zö¶oìtÃÃBgÌ¿„t.ãcùëߥöl߀õÿ¡þi‘èÿ—`šÿI5žÔDZþOrzÿ)Rèÿ—Àõ.ªÞˆé µT¾¯¨¾i–/k(À«b¬ÖH#fÞ6§÷q¬þižÜÿçêÿ2TÂr#ÛNj…Þ!|·’ê'Rb‡ÂÅÇÃùp06i´k Ö)~q-»U_&î*bÛ w úû‰7NŽ¿»UÁ4™¹Ž¡œ•_Uxûf(alire-1.2.1/testsuite/tests/publish/check-properties/my_index/crates/notags.tgz000066400000000000000000000010451430264165500300430ustar00rootroot00000000000000‹kêY_í–Qo›0€ó̯8ùi•Jf ÀCTiÚÖÇ­•ö2U“—8!62°¬ÿ~68 kµ%F¤j÷E‰î|wÖÙÇIÕ²²y;›jHãØŽAÓñ¸cDi˜DI„ÑŒ ƒÄ“Fåèš–i€ÙŠIõ'½còWŠò? ó²Öø° N®®~›ÿ4Š÷ù§ÍD#“:A,ÏøÏó_kµây Ÿû¢ñ<xPîT§sþí£Ð t ‡7¤Ñ9¹Xìä·™]h彘¨lEö›` """ import re from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match p = run_alr("show", "hello", "--solve") # Should not be missing dependencies assert_match(".*" + re.escape(""" Dependencies (solution): libhello=1.0.0 Dependencies (graph): hello=1.0.1 --> libhello=1.0.0 (^1.0) """) + ".*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/show/solve-remote/test.yaml000066400000000000000000000000631430264165500232530ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/show/system-hint/000077500000000000000000000000001430264165500212545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/show/system-hint/test.py000066400000000000000000000010041430264165500226000ustar00rootroot00000000000000""" Test that hinted native dependencies appear correctly in 'alr show'. More precisely, a "Dependencies (native)" section is added to list them. """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_match import re p = run_alr('show', 'libhello=0.9-test-unav-native', '--solve', complain_on_error=True) assert_match('.*' 'Dependencies \(external\):\n' ' make\*' '.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/show/system-hint/test.yaml000066400000000000000000000000641430264165500231170ustar00rootroot00000000000000driver: python-script indexes: native_index: {} alire-1.2.1/testsuite/tests/solver/000077500000000000000000000000001430264165500173225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/compiler-installed/000077500000000000000000000000001430264165500231115ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/compiler-installed/test.py000066400000000000000000000054511430264165500244470ustar00rootroot00000000000000""" Check that, for generic gnat dependencies, no compilers are installed (only a locally available one is used). """ import subprocess import re from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution # With no compiler selected, the external compiler in the environment should be # the only one available. We will verify this and capture its version (which is # actually the version returned by `make`) for later use # Verify only external compiler available p = run_alr("toolchain") assert_match(".*\n" # Headers "gnat_external.*Available.*Detected.*\n", p.out) # Capture version version = re.search("gnat_external ([0-9.]+)", p.out, re.MULTILINE).group(1) print(version) # When no compiler is selected, since the external one is available, it should # be used before offering to download a new compiler. # Create a crate for our experiments init_local_crate("xxx") # Check that a generic dependency results in the external being used alr_with("gnat") match_solution(f"gnat={version} (gnat_external) (installed)", escape=True) # Check that requesting a version different to the one externally available # results in missing compiler, as Alire won't try to install one. alr_with("gnat", delete=True, manual=False) alr_with(f"gnat/={version}") match_solution(f"gnat/={version} (direct,hinted)", escape=True) # Hinted because we know the crate exists as external # Now, if the user installs a cross compiler, it will be used run_alr("toolchain", "--install", "gnat_cross_2") run_alr("update") match_solution("gnat=1.0.0 (gnat_cross_2) (installed)", escape=True) # Likewise, if we install a native compiler, it will be preferred to a # cross-compiler. run_alr("toolchain", "--install", "gnat_native") run_alr("update") match_solution("gnat=8888.0.0 (gnat_native) (installed)", escape=True) # If we remove the version exclusion, the external compiler will still be # preferred as there is no selected compiler yet. alr_with("gnat", delete=True, manual=False) alr_with("gnat") match_solution(f"gnat={version} (gnat_external) (installed)", escape=True) # But, if the user selects a compiler as preferred, it will be used first run_alr("config", "--set", "toolchain.use.gnat", "gnat_cross_2=7777.0.0") run_alr("update") match_solution("gnat=1.0.0 (gnat_cross_2) (installed)", escape=True) # Finally, if the crate requests explicitly an uninstalled compiler, it will be # downloaded, installed, and used before the rest of installed compilers. alr_with("gnat_cross_1") match_solution("gnat=9999.0.0 (gnat_cross_1) (installed)", escape=True) match_solution("gnat_cross_1=9999.0.0 (installed)", escape=True) # Verify it was actually installed p = run_alr("toolchain") assert_match(".*gnat_cross_1\s+9999.0.0\s+Available", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/solver/compiler-installed/test.yaml000066400000000000000000000001161430264165500247520ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/solver/compiler-mixing/000077500000000000000000000000001430264165500224255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/compiler-mixing/test.py000066400000000000000000000055441430264165500237660ustar00rootroot00000000000000""" Check mixing gnat/gnat_xxx dependencies without configured preferred compiler """ import subprocess import os import re from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # Verify only external compiler available p = run_alr("toolchain") assert_match(".*\n" # Headers "gnat_external.*Available.*Detected.*\n", p.out) # Capture version version = re.search("gnat_external ([0-9.]+)", p.out, re.MULTILINE).group(1) # Prepare a couple of dependencies, one depending on gnat, and another one # depending on gnat_native. init_local_crate("dep_generic") alr_with("gnat") os.chdir("..") init_local_crate("dep_targeted") alr_with("gnat_native") # This step also installs the native compiler os.chdir("..") # First we check that a root generic dependency mixes well with either of the # two dependencies init_local_crate("xxx_generic_generic") run_alr("with", "--use=../dep_generic") alr_with("gnat") # gnat x gnat results in the external available compiler being used, preferred # over the native also available compiler (but not selected) match_solution(f"gnat={version} (gnat_external) (installed)", escape=True) # If we add a precise dependency on e.g. the installed native compiler, this # should override the external compiler alr_with("gnat_native") match_solution("gnat=8888.0.0 (gnat_native) (installed)", escape=True) match_solution("gnat_native=8888.0.0 (installed)", escape=True) # Let us swap the generic dependency with a targeted dependency, starting from # scratch os.chdir("..") init_local_crate("xxx_generic_targeted") run_alr("with", "--use=../dep_targeted") alr_with("gnat") # In this case the only possible solution is with the targeted compiler match_solution("gnat=" + e("8888.0.0 (gnat_native) (installed)") + ".*" + "gnat_native=" + e("8888.0.0 (installed)") + ".*") # Second, we check a root targeted gnat with both dependencies os.chdir("..") init_local_crate("xxx_targeted_generic") run_alr("with", "--use=../dep_generic") alr_with("gnat_native") # In this case the only possible solution is with the targeted compiler. The # Generic dependency also appears, coming from the dep_generic crate match_solution("gnat=" + e("8888.0.0 (gnat_native) (installed)") + ".*" + "gnat_native=" + e("8888.0.0 (installed)") + ".*") # Last combination is targeted x targeted os.chdir("..") init_local_crate("xxx_targeted_targeted") run_alr("with", "--use=../dep_targeted") alr_with("gnat_native") # In this case the only possible solution is with the targeted compiler. The # generic dependency no longer exists, as nobody requested a generic gnat. match_solution("gnat_native=" + e("8888.0.0 (installed)") + ".*") p = run_alr("with", "--solve") assert "gnat=" not in p.out, "Unexpected output" print('SUCCESS') alire-1.2.1/testsuite/tests/solver/compiler-mixing/test.yaml000066400000000000000000000001161430264165500242660ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/solver/compiler-priorities/000077500000000000000000000000001430264165500233235ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/compiler-priorities/test.py000066400000000000000000000103531430264165500246560ustar00rootroot00000000000000""" Check compiler priorities in the solver. These priorities are: - The selected compiler, if defined - An externally available compiler - Newest installed native compiler - Newest installed cross-compiler - Newest uninstalled native compiler - Newest uninstalled cross-compiler Generic dependencies on gnat= never cause compiler installation. Those only match installed or externally available compilers. """ import subprocess import re from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution # With no compiler selected, the external compiler in the environment should be # the only one available. We will verify this and capture its version (which is # actually the version returned by `make` for later use # Verify only external compiler available p = run_alr("toolchain") assert_match(".*\n" # Headers "gnat_external.*Available.*Detected.*\n", p.out) # Capture version version = re.search("gnat_external ([0-9.]+)", p.out, re.MULTILINE).group(1) # When no compiler is selected, only the gnat_external one should be used # unless a targeted compiler dependency is used # Create a crate for our experiments init_local_crate("xxx") # Check that a generic dependency results in the external being used alr_with("gnat") match_solution(f"gnat={version} (gnat_external) (installed)", escape=True) # Check that adding a second dependency on native packaged compiler is honored. # Both dependencies should appear in the solution. alr_with("gnat_native") match_solution("gnat=8888.0.0 (gnat_native) (installed)", escape=True) match_solution("gnat_native=8888.0.0 (installed)", escape=True) # The previous dependency also should have caused the installation of the # native compiler as an available compiler, which we will check: p = run_alr("toolchain") assert_match(".*gnat_native.*8888.0.0.*Available.*", p.out) # Move to a new crate init_local_crate("yyy") # Preinstall the v9999 compiler run_alr("toolchain", "--install", "gnat=9999") # Note also that we don't say the exact compiler to use, but the only one that # provides that version is a cross-compiler # Verify compiler availability p = run_alr("toolchain") assert_match(".*gnat_cross_1.*9999.*Available.*", p.out) # Depend on any gnat. Since no default is selected, the external one is used, # even if other installed compilers are newer (cross_2=9999) alr_with("gnat") match_solution(f"gnat={version} (gnat_external) (installed)", escape=True) # Depend on any gnat but the externally available. Since we have gnat_native=8888 # and gnat_cross_1=9999, normal version comparison would select the cross # compiler, but native compilers take precedence. So the solution should # match v2. alr_with("gnat", delete=True, manual=False) alr_with(f"gnat/={version}") match_solution("gnat=8888.0.0 (gnat_native)", escape=True) # If we uninstall the native compiler, the cross compiler will be preferred now run_alr("toolchain", "--uninstall", "gnat_native=8888") run_alr("update") match_solution("gnat=9999.0.0 (gnat_cross_1)", escape=True) # Let's reinstall the newest native compiler and verify the previous situation run_alr("toolchain", "--install", "gnat_native") p = run_alr("toolchain") assert_match(".*gnat_native.*8888.0.0.*Available.*", p.out) run_alr("update") match_solution("gnat=8888.0.0 (gnat_native)", escape=True) # We can force the use of the cross-compiler by selecting it as default: run_alr("config", "--global", "--set", "toolchain.use.gnat", "gnat_cross_1=9999") run_alr("update") match_solution("gnat=9999.0.0 (gnat_cross_1) (installed)", escape=True) # Check that a targeted compiler is retrieved when needed. Note that another # cross-compiler is still selected as default, but since we need a different # one, this setting is properly ignored in favor of the correct cross compiler. init_local_crate("zzz") alr_with("gnat") # Will be solved with the selected cross compiler 1 match_solution("gnat=9999.0.0 (gnat_cross_1) (installed)", escape=True) alr_with("gnat_cross_2") # Now, this compiler should appear in the solution and be available, as it # overrides the preferred compiler match_solution("gnat_cross_2=1.0.0 (installed)", escape=True) print('SUCCESS') alire-1.2.1/testsuite/tests/solver/compiler-priorities/test.yaml000066400000000000000000000001161430264165500251640ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/solver/compiler-selected/000077500000000000000000000000001430264165500227225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/compiler-selected/test.py000066400000000000000000000021721430264165500242550ustar00rootroot00000000000000""" Check solving with a configured preferred compiler """ import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # Select the default preferred compiler, which is the native packaged one run_alr("toolchain", "--select") # Init a crate depending on gnat init_local_crate("xxx") alr_with("gnat*") # Will appear in the solution as generic fulfilled by the preferred compiler match_solution("gnat=8888.0.0 (gnat_native) (installed)", escape=True) # Selecting another default will cause a corresponding change in the solution run_alr("config", "--set", "toolchain.use.gnat", "gnat_cross_2=1") run_alr("update") match_solution("gnat=1.0.0 (gnat_cross_2) (installed)", escape=True) # Adding another incompatible compiler dependency should result in overriding # the configured one alr_with("gnat_cross_1") # Both dependencies will appear in the solution, matching the same crate match_solution("gnat=9999.0.0 \(gnat_cross_1\) \(installed\).*" "gnat_cross_1=9999.0.0 \(installed\)") print('SUCCESS') alire-1.2.1/testsuite/tests/solver/compiler-selected/test.yaml000066400000000000000000000001161430264165500245630ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/solver/equivalences/000077500000000000000000000000001430264165500220065ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/equivalences/test.py000066400000000000000000000026111430264165500233370ustar00rootroot00000000000000""" Test solver using the "provides" field for regular crates """ import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # This test relies on two crates in the index: crate_lone=1.0 is unavailable. # crate_equiv=2.0 also provides crate_lone=1.0 and crate_virtual=1.0. # Finally there is crate_lone=2.0 that is available and nobody else provides. init_local_crate("xxx") alr_with("crate_lone^1") # Since crate_lone is unavailable, in the solution we should find crate_equiv: match_solution("crate_lone=2.0.0 (crate_equiv)", escape=True) # Likewise, a dependency on crate_virtual will be fulfilled by the same crate alr_with("crate_virtual") match_solution("crate_virtual=2.0.0 (crate_equiv)", escape=True) # Whereas a dependency on crate_equiv will show plainly without equivalence alr_with("crate_equiv") match_solution( "Dependencies (solution):\n" " crate_equiv=2.0.0 (origin: filesystem)\n" " crate_lone=2.0.0 (crate_equiv) (origin: filesystem)\n" " crate_virtual=2.0.0 (crate_equiv) (origin: filesystem)\n", escape=True) # Finally check that a dependency on crate_lone^2 is only fulfilled by itself os.chdir("..") init_local_crate("yyy") alr_with("crate_lone^2") match_solution("crate_lone=2.0.0 (origin: filesystem)", escape=True) print('SUCCESS') alire-1.2.1/testsuite/tests/solver/equivalences/test.yaml000066400000000000000000000001161430264165500236470ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/solver/forbids-replace/000077500000000000000000000000001430264165500223635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/forbids-replace/test.py000066400000000000000000000027001430264165500237130ustar00rootroot00000000000000""" Test the usual use case in which a drop-in replacement crate forbids equivalent crates in the solution. This works by both providing and forbidding the same crate, which incidentally is the same modus operandi of apt-get "conflicts": https://www.debian.org/doc/manuals/debian-reference/ch02.en.html#_package_dependencies """ import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # This test relies on two crates in the toolchain_index: # crate_subst both provides and forbids crate_real # crate_real is a regular crate only provided by itself and crate_subst # The following has only one possible solution, which is for crate_subst # providing both dependencies. init_local_crate("test") alr_with("crate_real") # Check that this is initially solved with the regular crate. This is currently # guaranteed by the solver attempting crates in alphabetical order. We will # need eventually a way to disable equivalences (via pins, or solver config). match_solution("crate_real=1.0.0 (origin: filesystem)", escape=True) # Let's add the drop-in equivalent crate that provides+forbids crate_lone alr_with("crate_subst") match_solution("crate_real=1.0.0 (crate_subst) (origin: filesystem)", escape=True) # This is the substituted release match_solution("crate_subst=1.0.0 (origin: filesystem)", escape=True) print('SUCCESS') alire-1.2.1/testsuite/tests/solver/forbids-replace/test.yaml000066400000000000000000000001161430264165500242240ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/solver/forbids/000077500000000000000000000000001430264165500207525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/forbids/test.py000066400000000000000000000022661430264165500223110ustar00rootroot00000000000000""" Test that the forbids field works for regular and provided crates """ import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # This test relies on three crates in the toolchain_index: # crate_conflict=1.2.3 conflicts with crate_lone* and crate_virtual* # crate_lone is a regular crate # crate_virtual has no releases, but is provided by crate_conflict_1 # Crate conflict cannot appear with any of the others in a solution, because of # its [forbids] table. init_local_crate("conflict_lone") alr_with("crate_conflict") alr_with("crate_lone") match_solution("crate_(conflict|lone)=.* \(origin:.*\)") # has origin: solved match_solution("crate_(conflict|lone)\* \(direct,missed\)") # Because of load/solving details, we do not know which of the two crates is # going to be missed/accepted in the solution, so we check there is one of each init_local_crate("conflict_virtual") alr_with("crate_conflict") alr_with("crate_virtual") match_solution("crate_(conflict|virtual)=.* \(origin:.*\)") match_solution("crate_(conflict|virtual)\* \(direct,missed\)") print('SUCCESS') alire-1.2.1/testsuite/tests/solver/forbids/test.yaml000066400000000000000000000001161430264165500226130ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/solver/one-dep-two-constraints/000077500000000000000000000000001430264165500240255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/one-dep-two-constraints/test.py000066400000000000000000000022471430264165500253630ustar00rootroot00000000000000""" Test that a dependency that is introduced by two dependents with different constraints is properly solved and shown. """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match # Initialize project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Add dependency on hello^1. Solution is hello=1.0.1 --> libhello=1.1.0 run_alr('with', 'hello^1') p = run_alr('with', '--solve') assert_match('.*' # skip solution 'Dependencies \(graph\):\n' ' hello=1.0.1 --> libhello=1.1.0 \(\^1.0\)\n' ' xxx=0.1.0-dev --> hello=1.0.1 \(\^1\).*', p.out, flags=re.S) # Add dependency on superhello*. Solution is superhello=1.0 --> libhello=1.0.1 # This implies a downgrade from libhello=1.1.0 to libhello=1.0.1, which is the # only possible combination of libhello^1.0 & libhello~1.0 run_alr('with', 'superhello') p = run_alr('with', '--solve') assert_match('.*' # skip solution 'Dependencies \(graph\):\n' ' hello=1.0.1 --> libhello=1.0.1 \(\^1.0\)\s*\n' ' superhello=1.0.0 --> libhello=1.0.1 \(~1.0\).*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/solver/one-dep-two-constraints/test.yaml000066400000000000000000000000641430264165500256700ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/solver/provides-no-conflict/000077500000000000000000000000001430264165500233665ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/solver/provides-no-conflict/test.py000066400000000000000000000016471430264165500247270ustar00rootroot00000000000000""" Test that two crates providing the same third crate are compatible """ import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # This test relies on two crates in the index: # crate_virt_1=2.0 also provides crate_virtual=1.0 # crate_virt_2=1.0 also provides crate_virtual=1.0 # Verify that these crates provide the same virtual release p = run_alr("show", "crate_virt_1") assert_match(".*Provides: crate_virtual=1.0.0.*", p.out) p = run_alr("show", "crate_virt_2") assert_match(".*Provides: crate_virtual=1.0.0.*", p.out) init_local_crate("xxx") alr_with("crate_virt_1") alr_with("crate_virt_2") # Both crates must appear in the solution match_solution("crate_virt_1=2.0.0 (origin: filesystem)", escape=True) match_solution("crate_virt_2=1.0.0 (origin: filesystem)", escape=True) print('SUCCESS') alire-1.2.1/testsuite/tests/solver/provides-no-conflict/test.yaml000066400000000000000000000001161430264165500252270ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/test/000077500000000000000000000000001430264165500167675ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/000077500000000000000000000000001430264165500212215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/my_index/000077500000000000000000000000001430264165500230355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/my_index/crates/000077500000000000000000000000001430264165500243165ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/my_index/crates/hello_1.0.0/000077500000000000000000000000001430264165500261355ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/my_index/crates/hello_1.0.0/hello.gpr000066400000000000000000000001731430264165500277530ustar00rootroot00000000000000project Hello is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Main use ("hello.adb"); end Hello; alire-1.2.1/testsuite/tests/test/action-test/my_index/crates/hello_1.0.0/src/000077500000000000000000000000001430264165500267245ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/my_index/crates/hello_1.0.0/src/hello.adb000066400000000000000000000001471430264165500305010ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; procedure Hello is begin Put_Line ("Hello, world!"); end Hello; alire-1.2.1/testsuite/tests/test/action-test/my_index/index/000077500000000000000000000000001430264165500241445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/my_index/index/he/000077500000000000000000000000001430264165500245405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/my_index/index/he/hello/000077500000000000000000000000001430264165500256435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/test/action-test/my_index/index/he/hello/hello-1.0.0.toml000066400000000000000000000004771430264165500303050ustar00rootroot00000000000000description = "action test" name = "hello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["some@one.com"] maintainers-logins = ["mylogin"] [[actions]] type = "test" command = ["echo", "ABRACADABRA"] [[actions]] type = "test" command = ["gprbuild", "-p"] [origin] url = "file:../../../crates/hello_1.0.0" alire-1.2.1/testsuite/tests/test/action-test/my_index/index/index.toml000066400000000000000000000000201430264165500261400ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/test/action-test/test.py000066400000000000000000000006021430264165500225500ustar00rootroot00000000000000""" Test custom actions for `alr test` """ from drivers.alr import run_alr from drivers.helpers import check_line_in from glob import glob from os import chdir p = run_alr('test', '--continue', 'hello') # Enter logging folder chdir(glob('hello*')[0]) chdir('alire') # Check the magic string in the test output log check_line_in(glob('*.log')[0], 'ABRACADABRA') print('SUCCESS') alire-1.2.1/testsuite/tests/test/action-test/test.yaml000066400000000000000000000001101430264165500230540ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/toolchain/000077500000000000000000000000001430264165500177705ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/toolchain/bad-switches/000077500000000000000000000000001430264165500223455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/toolchain/bad-switches/test.py000066400000000000000000000015461430264165500237040ustar00rootroot00000000000000""" Check that bad combos of switches for toolchain are detected """ from drivers.alr import run_alr # from drivers.asserts import assert_eq, assert_match p = run_alr("toolchain", "--install", "--uninstall", complain_on_error=False) assert p.status != 0, "Call should have failed" p = run_alr("toolchain", "--install", "--select", complain_on_error=False) assert p.status != 0, "Call should have failed" p = run_alr("toolchain", "--select", "--uninstall", complain_on_error=False) assert p.status != 0, "Call should have failed" p = run_alr("toolchain", "--select", "--install-dir", complain_on_error=False) assert p.status != 0, "Call should have failed" p = run_alr("toolchain", "--uninstall", "--install-dir", complain_on_error=False) assert p.status != 0, "Call should have failed" # Bonus: test a proper invocation p = run_alr("toolchain") print('SUCCESS') alire-1.2.1/testsuite/tests/toolchain/bad-switches/test.yaml000066400000000000000000000001161430264165500242060ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/toolchain/basic/000077500000000000000000000000001430264165500210515ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/toolchain/basic/test.py000066400000000000000000000046441430264165500224120ustar00rootroot00000000000000""" Check basic use: manual install, uninstall, and listing of toolchains """ import re from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match # Install a precise version of gnat run_alr("toolchain", "--install", "gnat_native=7777") # Verify that it appears as available p = run_alr("toolchain") assert_match(".*gnat_native.*" + re.escape("7777.0.0") + ".*Available", p.out) # Also that the external compiler is detected and always available assert_match(".*gnat_external.*Available", p.out) # Also that the external compiler cannot be uninstalled (and short switch) p = run_alr("toolchain", "-u", "gnat_external", complain_on_error=False) assert_match(".*Only regular releases deployed through Alire can be removed.*", p.out) # Verify that it can be uninstalled run_alr("toolchain", "--uninstall", "gnat_native=7777") p = run_alr("toolchain") assert "gnat_native" not in p.out, "Unexpected output" # Repeat install but without giving a version, and one should be autoidentified # as the newest available version p = run_alr("toolchain", "-i", "gnat_native", quiet=False) # Test short switch assert_match(".*Requested crate resolved as gnat_native=8888.0.0.*", p.out) # Verify that we can explicitly install a second version for the same target run_alr("toolchain", "--install", "gnat_native=7777") p = run_alr("toolchain") assert_match(".*gnat_native.*" + re.escape("7777.0.0") + ".*Available", p.out) # Verify that uninstalling without specifying version isn't allowed when there # are two matching crates installed. p = run_alr("toolchain", "--uninstall", "gnat_native", complain_on_error=False) assert_match(".*Requested crate has several installed releases.*", p.out) # Uninstall successfully by giving a version run_alr("toolchain", "--uninstall", "gnat_native=8888") # Now we can uninstall without specifying the version of the remaining release run_alr("toolchain", "--uninstall", "gnat_native") # Verify that two components can be installed at once run_alr("toolchain", "--install", "gnat_native", "gnat_cross_1") p = run_alr("toolchain") assert_match(".*gnat_native.*" + re.escape("8888.0.0") + ".*Available", p.out) assert_match(".*gnat_cross_1.*" + re.escape("9999.0.0") + ".*Available", p.out) # Uninstall both components run_alr("toolchain", "--uninstall", "gnat_native", "gnat_cross_1") print('SUCCESS') alire-1.2.1/testsuite/tests/toolchain/basic/test.yaml000066400000000000000000000001161430264165500227120ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/toolchain/custom_install_dir/000077500000000000000000000000001430264165500236665ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/toolchain/custom_install_dir/test.py000066400000000000000000000025431430264165500252230ustar00rootroot00000000000000""" Check folders when installing binary compiler crates at a custom location """ import os import re from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from drivers.helpers import contents install_dir = os.path.join (os.getcwd(), "custom_install").replace("\\", "/") install_dir_2 = os.path.join (os.getcwd(), "custom_install").replace("\\", "/") unk_re = "[0-9]+\.[0-9]+\.[0-9]+_[0-9a-f]{8}" # Unknown version + Unknown hash def config_path_re(crate): return re.escape(f"{install_dir}/{crate}_") + unk_re def check_content(crate, dir): paths = contents(dir, crate) try: assert len(paths) >= 1 and \ re.search(config_path_re(crate), paths[0]), \ "Unexpected contents: " + str(paths) except: print(f"erroneous regex was: {config_path_re(crate)}") print(f"erroneous path was: {paths[0]}") raise # First we test installation of one component run_alr("toolchain", "--install", "gnat_native", "--install-dir", install_dir) check_content("gnat_native", install_dir) # We now test installation of two components run_alr("toolchain", "--install", "gnat_native", "gnat_cross_1", "--install-dir", install_dir_2) check_content("gnat_native", install_dir_2) check_content("gnat_cross_1", install_dir_2) print('SUCCESS') alire-1.2.1/testsuite/tests/toolchain/custom_install_dir/test.yaml000066400000000000000000000001161430264165500255270ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/toolchain/directories/000077500000000000000000000000001430264165500223045ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/toolchain/directories/test.py000066400000000000000000000041441430264165500236400ustar00rootroot00000000000000""" Check created folders are where expected when installing binary compiler crates """ import os import re from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from drivers.helpers import contents # Identify config location p = run_alr("version") config_dir = re.search("config folder:([^\n]*)", p.out).group(1).strip() config_dir = config_dir.replace("\\", "/") cache_dir = os.path.join(config_dir, "cache") # The 'contents` function we use to compare these strings normalizes all paths # to forward slashes, so we do the same with the config_dir unk_re = "[0-9]+\.[0-9]+\.[0-9]+_[0-9a-f]{8}" # Unknown version + Unknown hash def config_path_re(crate): return re.escape(f"{config_dir}/cache/dependencies/{crate}_") + unk_re def check_content(crate): paths = contents(cache_dir, crate) try: assert len(paths) >= 1 and \ re.search(config_path_re(crate), paths[0]), \ "Unexpected contents: " + str(paths) except: print(f"erroneous regex was: {config_path_re(crate)}") print(f"erroneous path was: {paths[0]}") raise # First we test manual installation run_alr("toolchain", "--install", "gnat_native") check_content("gnat_native") # Uninstall the compiler and verify absence run_alr("toolchain", "--uninstall", "gnat_native", quiet=False) paths = contents(cache_dir, "gnat_native") assert len(paths) == 0, "Unexpected contents: " + str(paths) # Require the external compiler and verify no trace appears in install folder # nor in local folder init_local_crate("xxx") alr_with("gnat_external") match_solution("gnat_external=.* \(installed\)") paths = contents(cache_dir, "gnat_external") assert len(paths) == 0, "Unexpected contents: " + str(paths) paths = contents(".", "gnat_external") assert len(paths) == 0, "Unexpected contents: " + str(paths) # Require a cross compiler and verify it is automatically installed alr_with("gnat_external", delete=True, manual=False) alr_with("gnat_cross_1") match_solution("gnat_cross_1=.* \(installed\)") check_content("gnat_cross_1") print('SUCCESS') alire-1.2.1/testsuite/tests/toolchain/directories/test.yaml000066400000000000000000000001161430264165500241450ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/toolchain/select-dontmix/000077500000000000000000000000001430264165500227275ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/toolchain/select-dontmix/test.py000066400000000000000000000057451430264165500242730ustar00rootroot00000000000000""" Check that mixing of toolchain tools is properly detected/handled """ from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match import re # Capture version of "external" gnat/gprbuild p = run_alr("toolchain") ver = re.search("gnat_external ([0-9.]+)", p.out, re.MULTILINE).group(1) # First, see that trying to use a native with an external is reported p = run_alr("toolchain", "--select", "gnat_external", "gprbuild=8888", complain_on_error=False) assert p.status != 0, "Expected error didn't happend" assert_match(".*Use --force to override compatibility checks.*", p.out) # Same thing works if forced run_alr("toolchain", "--select", "gnat_external", "gprbuild=8888", force=True) # Now, not forcing the native gprbuild also succeeds by automatically selecting # gprbuild as external too run_alr("toolchain", "--select", "gnat_external", "gprbuild") p = run_alr("toolchain") assert_match(f".*gprbuild .*{ver}.*Default.*", p.out) # External version assert_match(f".*gnat_external.*{ver}.*Default.*", p.out) # Likewise, picking first a native and requesting a second external tool fails p = run_alr("toolchain", "--select", "gnat_native", "gprbuild/=8888", complain_on_error=False) assert p.status != 0, "Expected error didn't happend" assert_match(".*Use --force to override compatibility checks.*", p.out) # But leaving free choice of gprbuild will result in the native being chosen run_alr("toolchain", "--select", "gnat_native", "gprbuild") p = run_alr("toolchain") assert_match(".*gprbuild 8888.0.0 Default.*", p.out) assert_match(".*gnat_native 8888.0.0 Default.*", p.out) # Now, trying to only select an external gnat fails because of native gprbuild p = run_alr("toolchain", "--select", "gnat_external", complain_on_error=False) assert p.status != 0, "Expected error didn't happend" assert_match(".*Use --force to override compatibility checks.*", p.out) # This can be forced again, and then we can ask for a gprbuild and again the # proper one will be picked up automatically run_alr("toolchain", "--select", "gnat_external", force=True) run_alr("toolchain", "--select", "gprbuild") p = run_alr("toolchain") assert_match(f".*gprbuild .*{ver}.*Default.*", p.out) assert_match(f".*gnat_external.*{ver}.*Default.*", p.out) # Reverse order combo also works: here we ask first for gprbuild, which # will be solved as the latest one (native), and the appropriate gnat will be # chosen. As we are changing both in one go, the previously selected ones do # not restrict the new choices. run_alr("toolchain", "--select", "gprbuild", "gnat") p = run_alr("toolchain") assert_match(".*gprbuild 8888.0.0 Default.*", p.out) assert_match(".*gnat_native 8888.0.0 Default.*", p.out) # Finally, note that installing without selecting is not affected by checks, # as these are not setting the default toolchain to be used, but merely making # available these tools as alternatives. run_alr("toolchain", "--install", "gnat_external", "gprbuild=8888") print('SUCCESS') alire-1.2.1/testsuite/tests/toolchain/select-dontmix/test.yaml000066400000000000000000000000671430264165500245750ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: {} alire-1.2.1/testsuite/tests/toolchain/select/000077500000000000000000000000001430264165500212475ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/toolchain/select/test.py000066400000000000000000000030611430264165500226000ustar00rootroot00000000000000""" Check toolchain selection assistant """ import os import re import subprocess from drivers.alr import run_alr, init_local_crate from drivers.asserts import assert_eq, assert_match p = run_alr("index") print(p.out) # Activate the default compiler p = run_alr("toolchain", "--select") # Check that the newest native compiler is the Default now (vs Available) p = run_alr("toolchain") assert_match(".*gnat_native.*" + re.escape("8888.0.0") + ".*Default.*", p.out) # Select an older compiler as default run_alr("toolchain", "--select", "gnat_native=7777") p = run_alr("toolchain") assert_match(".*gnat_native.*" + re.escape("7777.0.0") + ".*Default.*", p.out) # Test local selection by configuring locally inside a crate init_local_crate() run_alr("toolchain", "--select", "gnat_native=8888", "--local") p = run_alr("toolchain") assert_match(".*gnat_native.*" + re.escape("8888.0.0") + ".*Default.*", p.out) # And check that outside the global selection is still in effect os.chdir("..") p = run_alr("toolchain") assert_match(".*gnat_native.*" + re.escape("7777.0.0") + ".*Default.*", p.out) # I've (mosteo) been unable to connect stdin with an alr launched via # # subprocess.run, so no way to do further interactive tests at this time. # My attempt follows. (I also attempted using subprocess.Popen.) subprocess.run(["alr", "toolchain", "--select"], input="2\n", text=True, capture_output=True) # This actually runs, but there is no input sent to alr. stdin=PIPE fails too. print('SUCCESS') alire-1.2.1/testsuite/tests/toolchain/select/test.yaml000066400000000000000000000001161430264165500231100ustar00rootroot00000000000000driver: python-script indexes: toolchain_index: in_fixtures: true alire-1.2.1/testsuite/tests/update/000077500000000000000000000000001430264165500172725ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/manual-once/000077500000000000000000000000001430264165500214715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/manual-once/test.py000066400000000000000000000025151430264165500230250ustar00rootroot00000000000000""" Verify that, after manually touching the manifest, updates happen only once """ from drivers.alr import run_alr, init_local_crate, alr_touch_manifest from drivers.asserts import assert_eq, assert_match import os # There are two scenarios to test: both start with a manual edition of the # manifest. Afterwards, the user can either run 'update', which goes straight # into applying any changes found; or, they can run any other command, which # should also check for changes before doing anything, so the lockfile is in # sync with the manifest. We test both here. def prepare_crate(name): """Prepare a crate with outdated lockfile""" init_local_crate(name) alr_touch_manifest() warning_text = "Synchronizing workspace" # Test when directly doing an update. Should report no changes. prepare_crate("test1") p = run_alr("update", quiet=False) assert_eq("Nothing to update.\n", p.out) # Also check that the modified manifest warning is not shown, as we are # requesting the update explicitly: assert warning_text not in p.out # Test when doing other things. Should warn once of possible changes. prepare_crate("test2") p = run_alr("with", quiet=False) # First run must warn assert_match(".*" + warning_text + ".*", p.out) p = run_alr("with", quiet=False) # Second run must not warn assert warning_text not in p.out print('SUCCESS') alire-1.2.1/testsuite/tests/update/manual-once/test.yaml000066400000000000000000000000631430264165500233330ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/update/missing-deps/000077500000000000000000000000001430264165500216745ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/missing-deps/test.py000066400000000000000000000015341430264165500232300ustar00rootroot00000000000000""" Check that updating an incomplete solution is doable resulting in no changes. This is labeled manual because the pin is added through the manifest. """ import re import os from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_match from glob import glob # Add a dependency and force it missing by pinning it to non-existing version run_alr('init', '--bin', 'xxx') os.chdir('xxx') run_alr('with', 'libhello') alr_pin('libhello', version="3") # See that updating succeeds run_alr('update') # Check that the solution is still the expected one, and also that the original # dependency is included in the restrictions p = run_alr('with', '--solve') assert_match( '.*Dependencies \(external\):\n' ' ' + re.escape('libhello(=3.0.0) & (^2.0.0) (direct,missed,pin=3.0.0)') + '.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/update/missing-deps/test.yaml000066400000000000000000000000641430264165500235370ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/update/pinned/000077500000000000000000000000001430264165500205475ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/pinned/test.py000066400000000000000000000017511430264165500221040ustar00rootroot00000000000000""" Check that updating a manifest-pinned crate results in a recoverable error """ import re import os from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_match from glob import glob # Add a dependency and force it missing by pinning it to non-existing version run_alr('init', '--bin', 'xxx') os.chdir('xxx') run_alr('with', 'libhello^1') # This causes libhello=1.1 alr_pin('libhello', version='1') # Downgrade to 1.0 # Check that updating without specific crate does not err run_alr('update') # See that updating the pinned crate errs p = run_alr('update', 'libhello', complain_on_error=False) assert p.status != 0, "should have erred" # Check that force updating the pinned crate does not err run_alr('update', 'libhello', force=True) # Check that the solution is still the expected one p = run_alr('with', '--solve') assert_match('.*Dependencies \(solution\):\n' ' libhello=1.0.0 \(pinned\).*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/update/pinned/test.yaml000066400000000000000000000000641430264165500224120ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/update/selective/000077500000000000000000000000001430264165500212555ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/000077500000000000000000000000001430264165500230715ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/index/000077500000000000000000000000001430264165500242005ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/index/he/000077500000000000000000000000001430264165500245745ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/index/he/hello1/000077500000000000000000000000001430264165500257605ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/index/he/hello1/hello1-0.1.0.toml000066400000000000000000000003241430264165500304720ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello1" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/update/selective/my_index/index/he/hello2/000077500000000000000000000000001430264165500257615ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/index/he/hello2/hello2-0.1.0.toml000066400000000000000000000003241430264165500304740ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello2" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/update/selective/my_index/index/index.toml000066400000000000000000000000201430264165500261740ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/update/selective/my_index/updated/000077500000000000000000000000001430264165500245175ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/000077500000000000000000000000001430264165500256265ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/he/000077500000000000000000000000001430264165500262225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/he/hello1/000077500000000000000000000000001430264165500274065ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/he/hello1/hello1-0.1.0.toml000066400000000000000000000003241430264165500321200ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello1" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/he/hello1/hello1-0.2.0.toml000066400000000000000000000003241430264165500321210ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello1" version = "0.2.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/he/hello2/000077500000000000000000000000001430264165500274075ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/he/hello2/hello2-0.1.0.toml000066400000000000000000000003241430264165500321220ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello2" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/he/hello2/hello2-0.2.0.toml000066400000000000000000000003241430264165500321230ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello2" version = "0.2.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/update/selective/my_index/updated/index/index.toml000066400000000000000000000000201430264165500276220ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/update/selective/test.py000066400000000000000000000016451430264165500226140ustar00rootroot00000000000000""" Test selective crate update """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match # Create a new "xxx" program project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Make it depend on hello1 and hello2 run_alr('with', 'hello1>0', 'hello2>0') # Verify solution depends on 0.1 versions p = run_alr('with', '--solve') assert_match('.*Dependencies \(solution\):\n' ' hello1=0\.1.*\n' ' hello2=0\.1.*\n', p.out, flags=re.S) # Add a new index that contains updates run_alr('index', '--name', 'updates', '--add', '../my_index/updated') # Do selective update and check than only the requested crate has been updated run_alr('update', 'hello2') p = run_alr('with', '--solve') assert_match('.*Dependencies \(solution\):\n' ' hello1=0\.1.*\n' ' hello2=0\.2.*\n', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/update/selective/test.yaml000066400000000000000000000001101430264165500231100ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/version/000077500000000000000000000000001430264165500174755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/version/inside-outside/000077500000000000000000000000001430264165500224225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/version/inside-outside/test.py000066400000000000000000000011621430264165500237530ustar00rootroot00000000000000""" Verify that `alr version` works without error without, with and with broken manifest """ from drivers.alr import run_alr, init_local_crate, alr_manifest from drivers.asserts import assert_eq, assert_match # Run in several situations with minimal double-check p = run_alr("version") assert_match(".*root status:.*OUTSIDE", p.out) init_local_crate() p = run_alr("version") assert_match(".*root status:.*VALID", p.out) # break the manifest with open(alr_manifest(), "a") as manifest: manifest.write("not valid TOML methinks...") p = run_alr("version") assert_match(".*root status:.*BROKEN", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/version/inside-outside/test.yaml000066400000000000000000000000631430264165500242640ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/version/nothing/000077500000000000000000000000001430264165500211435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/version/nothing/test.py000066400000000000000000000006311430264165500224740ustar00rootroot00000000000000""" Validate just `alr` is printing something that makes sense and not throwing some initialization exception during elaboration as sometimes has happened """ from drivers.alr import run_alr from drivers.asserts import assert_match # Check the first line looks like a version and then comes the USAGE assert_match("^alr \S*?\n\nUSAGE.*", run_alr(complain_on_error=False).out) print('SUCCESS') alire-1.2.1/testsuite/tests/version/nothing/test.yaml000066400000000000000000000000261430264165500230040ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/version/short/000077500000000000000000000000001430264165500206345ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/version/short/test.py000066400000000000000000000006371430264165500221730ustar00rootroot00000000000000""" Validate the output of alr --version """ import re from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match # Extract version from alr version version = re.search("alr version:\s*?([^\s$]+)", run_alr("version").out, flags=re.M)[1] # Match against the output we want assert_eq(run_alr("--version").out, f"alr {version}\n") print('SUCCESS') alire-1.2.1/testsuite/tests/version/short/test.yaml000066400000000000000000000000261430264165500224750ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/with/000077500000000000000000000000001430264165500167635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/add-several/000077500000000000000000000000001430264165500211525ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/add-several/test.py000066400000000000000000000010121430264165500224750ustar00rootroot00000000000000""" Verify that more than one dependency can be added """ import os from drivers.alr import run_alr from drivers.asserts import assert_match import re # Initialize a project, enter it and two dependencies p = run_alr('init', '--bin', 'xxx') os.chdir('xxx') p = run_alr('with', 'libhello^1') p = run_alr('with', 'hello^1') p = run_alr('show') assert_match('.*\n' 'Dependencies \(direct\):\n' ' hello\^1\n' ' libhello\^1\n', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/add-several/test.yaml000066400000000000000000000000631430264165500230140ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/with/auto-gpr-with/000077500000000000000000000000001430264165500214725ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/000077500000000000000000000000001430264165500225535ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/my_index/000077500000000000000000000000001430264165500243675ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/my_index/ex/000077500000000000000000000000001430264165500250035ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/my_index/ex/extern/000077500000000000000000000000001430264165500263105ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/my_index/ex/extern/extern-external.toml000066400000000000000000000003671430264165500323400ustar00rootroot00000000000000description = "Some external crate for testing" name = "extern" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["example"] [[external]] kind = "system" [external.origin."case(distribution)"] "..." = ["make"] alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/my_index/index.toml000066400000000000000000000000201430264165500263630ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/my_index/li/000077500000000000000000000000001430264165500247735ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/my_index/li/libhello_nogprwith/000077500000000000000000000000001430264165500306665ustar00rootroot00000000000000libhello_nogprwith-1.0.0.toml000066400000000000000000000004541430264165500360340ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/my_index/li/libhello_nogprwithauto-gpr-with = false description = "auto-gpr-with=false" name = "libhello_nogprwith" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] project-files = ["will_fail_if_withed.gpr"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/test.py000066400000000000000000000020431430264165500241030ustar00rootroot00000000000000""" Test a basic auto withing of gpr file. """ from glob import glob import os from drivers.alr import run_alr from drivers.asserts import assert_eq # Get the "hello" project and enter its directory run_alr('init', '--bin', 'myhello') os.chdir(glob('myhello*')[0]) # Get the libhello dependency that should also add a with in update test.gpr run_alr('with', 'libhello') # Re-write the source code by using libhello with open("src/myhello.adb", "w") as text_file: text_file.write(""" with libhello; procedure Myhello is begin libhello.Hello_World; end Myhello; """) # Build it run_alr('build') # Run it p = run_alr('run') assert_eq('Hello, world!\n', p.out) # Get a dependency with auto-gpr-with=false run_alr('with', 'libhello_nogprwith') # Build again, the build would fail if the project file from libhello_nogprwith # is wrongly withed. run_alr('build') # Get an external dependency run_alr('with', 'extern') # Build again, the build would fail if a default project file is added for # external crates. run_alr('build') print('SUCCESS') alire-1.2.1/testsuite/tests/with/auto-gpr-with/basic/test.yaml000066400000000000000000000002211430264165500244110ustar00rootroot00000000000000driver: python-script indexes: basic_index: in_fixtures: true my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/with/auto-gpr-with/gpr_in_subdir/000077500000000000000000000000001430264165500243205ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/gpr_in_subdir/my_index/000077500000000000000000000000001430264165500261345ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/gpr_in_subdir/my_index/gp/000077500000000000000000000000001430264165500265425ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/gpr_in_subdir/my_index/gp/gpr_in_subdir/000077500000000000000000000000001430264165500313705ustar00rootroot00000000000000gpr_in_subdir-1.0.0.toml000066400000000000000000000004311430264165500354640ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/auto-gpr-with/gpr_in_subdir/my_index/gp/gpr_in_subdirdescription = "gpr file in subdirs" name = "gpr_in_subdir" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] project-files = ["dir1/dir2/dir3/gpr_in_subdir.gpr"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/tests/with/auto-gpr-with/gpr_in_subdir/my_index/index.toml000066400000000000000000000000201430264165500301300ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/with/auto-gpr-with/gpr_in_subdir/test.py000066400000000000000000000015611430264165500256540ustar00rootroot00000000000000""" Test the with statement for a project file in sub dirs """ from glob import glob import os from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match import re import platform from drivers.helpers import check_line_in # Get the "hello" project and enter its directory run_alr('init', '--bin', 'myhello') os.chdir(glob('myhello*')[0]) # Get dependencies that should also add a with statement in myhello.gpr run_alr('with', 'libhello') run_alr('with', 'gpr_in_subdir') check_line_in('config/myhello_config.gpr', 'with "libhello.gpr";') # When the crate declares a project file: `dir1/dir2/dir3/prj.gpr`, the with # statement has to be `with "prj.gpr"`. Without the sub-dirs because # GPR_PROJECT_PATH is already set with dirs that contain the project file. check_line_in('config/myhello_config.gpr', 'with "gpr_in_subdir.gpr";') print('SUCCESS') alire-1.2.1/testsuite/tests/with/auto-gpr-with/gpr_in_subdir/test.yaml000066400000000000000000000002211430264165500261560ustar00rootroot00000000000000driver: python-script indexes: basic_index: in_fixtures: true my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/with/changes-info/000077500000000000000000000000001430264165500213245ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/changes-info/test.py000066400000000000000000000110751430264165500226610ustar00rootroot00000000000000""" Check summary of changes shown to the user when modifying dependencies """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import path_separator, with_project # Initialize a workspace for the test run_alr('init', '--bin', 'xxx') os.chdir('xxx') ############################################################################### # Add a regular solvable dependency p = run_alr('with', 'libhello', quiet=False) assert_match(".*" + re.escape("""Requested changes: + libhello ^2.0.0 (add) Changes to dependency solution: + libhello 2.0.0 (new)""") + ".*", p.out, flags=re.S) ############################################################################### # Check adding a missing crate p = run_alr('with', 'unobtanium', quiet=False) assert_match(".*" + re.escape("""Requested changes: + unobtanium * (add) Changes to dependency solution: New solution is incomplete. +! unobtanium * (new,missing)""") + ".*", p.out, flags=re.S) ############################################################################### # Check adding a pinned dir (the dir must exist) os.mkdir("local_crate") p = run_alr('with', 'local_crate', '--use=local_crate', quiet=False) assert_match(".*" + re.escape("""Requested changes: + local_crate * (add) Changes to dependency solution: +· local_crate unknown (new,path=local_crate)""") + ".*", p.out, flags=re.S) ############################################################################### # Pinning a crate to a version p = run_alr('pin', 'libhello', quiet=False) assert_match(".*" + re.escape("""Changes to dependency solution: · libhello 2.0.0 (pin=2.0.0)""") + ".*", p.out, flags=re.S) ############################################################################### # Unpinning p = run_alr('pin', '--unpin', 'libhello', quiet=False) assert_match(".*" + re.escape("""Changes to dependency solution: o libhello 2.0.0 (unpinned)""") + ".*", p.out, flags=re.S) ############################################################################### # Removal p = run_alr('with', '--del', 'libhello', quiet=False) assert_match(".*" + re.escape("""Requested changes: - libhello ^2.0.0 (remove) Changes to dependency solution: - libhello 2.0.0 (removed)""") + ".*", p.out, flags=re.S) ############################################################################### # Indirect dependency p = run_alr('with', 'hello', quiet=False) assert_match(".*" + re.escape("""Requested changes: + hello ^1.0.1 (add) Changes to dependency solution: + hello 1.0.1 (new)""") + "\s*\n\s*" + re.escape("+ libhello 1.1.0 (new,indirect)") + ".*", p.out, flags=re.S) ############################################################################### # Going from indirect to direct. Since the dependency is already in the # solution, there is no version change (=). p = run_alr('with', 'libhello', quiet=False) assert_match(".*" + re.escape("""Requested changes: + libhello ^1.1.0 (add) Changes to dependency solution: = libhello 1.1.0 (direct)""") + ".*", p.out, flags=re.S) ############################################################################### # Going from direct to indirect. Likewise, removing the dependency leaves it in # the solution because is still needed indirectly via 'hello' p = run_alr('with', '--del', 'libhello', quiet=False) assert_match(".*" + re.escape("""Requested changes: - libhello ^1.1.0 (remove) Changes to dependency solution: = libhello 1.1.0 (indirect)""") + ".*", p.out, flags=re.S) ############################################################################### # Display of downgrades. Forcing libhello=1, it results in a downgrade. p = run_alr('with', 'libhello=1', quiet=False) assert_match(".*" + re.escape("""Requested changes: + libhello =1 (add) Changes to dependency solution: v libhello 1.0.0 (direct,downgraded from 1.1.0)""") + ".*", p.out, flags=re.S) ############################################################################### # Display of upgrades. By removing libhello=1, it can be upgraded. p = run_alr('with', '--del', 'libhello', quiet=False) assert_match(".*" + re.escape("""Requested changes: - libhello =1 (remove) Changes to dependency solution: ^ libhello 1.1.0 (indirect,upgraded from 1.0.0)""") + ".*", p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/changes-info/test.yaml000066400000000000000000000001131430264165500231620ustar00rootroot00000000000000driver: python-script indexes: solver_index: in_fixtures: true alire-1.2.1/testsuite/tests/with/delete-two/000077500000000000000000000000001430264165500210345ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/delete-two/test.py000066400000000000000000000027041430264165500223700ustar00rootroot00000000000000""" Check that we can delete dependencies from an array with several entries """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match from drivers.helpers import content_of manifest = "alire.toml" run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Manually add two dependencies to the same array entry with open(manifest, 'a') as file: file.write('[[depends-on]]\n' 'libhello = "*"\n' 'hello = "*"') # Check removal in 1st-2nd order run_alr('with', '--del', 'libhello') assert 'libhello = "*"' not in content_of(manifest) # Dep gone assert 'hello = "*"' in content_of(manifest) # Dep stays run_alr('with', '--del', 'hello') assert 'hello = "*"' not in content_of(manifest) # No trace of deps anymore assert '[[depends-on]]' not in content_of(manifest) # No trace of deps anymore # Same tests in reverse order of dependency with open(manifest, 'a') as file: file.write('[[depends-on]]\n' 'hello = "*"\n' 'libhello = "*"') # Check removal in 2nd-1st order run_alr('with', '--del', 'libhello') assert 'libhello = "*"' not in content_of(manifest) # Dep gone assert 'hello = "*"' in content_of(manifest) # Dep stays run_alr('with', '--del', 'hello') assert 'hello = "*"' not in content_of(manifest) # No trace of deps anymore assert '[[depends-on]]' not in content_of(manifest) # No trace of deps anymore print('SUCCESS') alire-1.2.1/testsuite/tests/with/delete-two/test.yaml000066400000000000000000000000641430264165500226770ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/with/dynamic-dependencies/000077500000000000000000000000001430264165500230335ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/dynamic-dependencies/test.py000066400000000000000000000026201430264165500243640ustar00rootroot00000000000000""" Check that dynamic dependencies don't affect the use of `alr with` """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match from drivers.helpers import content_of manifest = "alire.toml" run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Manually add a regular and a dynamic dependency with open(manifest, 'a') as file: file.write('[[depends-on]]\n' 'libhello = "*"\n\n' '[[depends-on]]\n' '[depends-on."case(os)"."..."]\n' 'superhello = "*"') # Check adding a dependency run_alr('with', 'hello^1') assert 'hello = "^1"' in content_of(manifest) # Check removal run_alr('with', '--del', 'hello') assert 'hello = "^1"' not in content_of(manifest) # Check that the dependency that precedes the dynamic expression is removable run_alr('with', '--del', 'libhello') assert 'libhello = "*"' not in content_of(manifest) # Check that empty array entries have been cleaned up assert content_of(manifest).count('[[depends-on]]') == 1 # Check that removing the dynamic dependency isn't allowed p = run_alr('with', '--del', 'superhello', complain_on_error=False, quiet=False) assert_match(".*" + re.escape("Crate slated for removal is not among" " direct static dependencies: superhello") + ".*", p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/dynamic-dependencies/test.yaml000066400000000000000000000000641430264165500246760ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/with/equivalent/000077500000000000000000000000001430264165500211405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/equivalent/test.py000066400000000000000000000032021430264165500224660ustar00rootroot00000000000000""" Verify that using manual edition and `alr with` result in equivalent manifests """ from drivers.alr import run_alr, alr_with, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import init_git_repo, git_branch import os import shutil def check_equivalent(dep="", path="", url="", commit="", branch=""): """ Run manual and auto and compare outputs """ manual = [False, True] p = [None, None] for i in [0, 1]: init_local_crate() # run command alr_with(dep=dep, path=path, url=url, commit=commit, branch=branch, force=True, manual=manual[i]) # get output of solution p[i] = run_alr("with", "--solve").out if i == 1: assert_eq(p[0], p[1]) # Cleanup os.chdir("..") shutil.rmtree("xxx") # Simple with without subset cannot be tested as `alr with` will narrow down # the dependency causing a discrepancy # Existing crate with subset check_equivalent("libhello^1") # Non-existent version check_equivalent("libhello^777") # Non-existent crate check_equivalent("unobtanium") # Pinned folder init_local_crate("yyy", enter=False) check_equivalent("yyy~0", path="../yyy") # Prepare repository head = init_git_repo("yyy") branch = git_branch("yyy") os.rename("yyy", "yyy.git") # to be recognizable as a git url url = "../yyy.git" # Simple git remote, explicit crate & version check_equivalent(dep="yyy~0", url=url) # Explicit commit check_equivalent(dep="yyy~0", url=url, commit=head) # Explicit branch check_equivalent(dep="yyy~0", url=url, branch=branch) print('SUCCESS') alire-1.2.1/testsuite/tests/with/equivalent/test.yaml000066400000000000000000000000631430264165500230020ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/with/external/000077500000000000000000000000001430264165500206055ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/external/test.py000066400000000000000000000015011430264165500221330ustar00rootroot00000000000000""" Verify that withing a dependency on a crate with only unavailable externals works """ from glob import glob import os import re from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match # Initialize a new project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Add a dependency on 'make', defined in the index as only a hint run_alr('with', 'make', force=True) # Verify that it appears in the solution as unavailable external p = run_alr('with', '--solve') assert_match('Dependencies \(direct\):\n' ' make\*\n' 'Dependencies \(external\):\n' ' make\* \(direct,hinted\)\n' 'Dependencies \(graph\):\n' ' xxx=0.1.0-dev --> make\*\n' '.*', # skip plot or warning p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/external/test.yaml000066400000000000000000000000631430264165500224470ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/with/git-reference/000077500000000000000000000000001430264165500215025ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/git-reference/test.py000066400000000000000000000020771430264165500230410ustar00rootroot00000000000000""" Test conversion of git references into commits during pinning """ from drivers.alr import run_alr, alr_with, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import init_git_repo import os import subprocess # Create a new "remote" repository with a tag that we'll use as reference init_local_crate("remote") init_git_repo(".") subprocess.run(["git", "tag", "v1"]).check_returncode() # Verify that pinning to a valid reference succeeds os.chdir("..") init_local_crate() alr_with(path="../remote", commit="v1", manual=False) p = run_alr("pin") assert_match("remote file:alire/cache/pins/remote_.{,8} ../remote#.{,8}", p.out) # Remove dependency for next test alr_with("remote", delete=True, manual=False) p = run_alr("pin") assert_eq("There are no pins\n", p.out) # Verify that pinning to an invalid reference fails p = run_alr("with", "--use", "../remote", "--commit", "v2", complain_on_error=False) assert_match(".*Requested remote reference v2 not found in repository.*", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/with/git-reference/test.yaml000066400000000000000000000000631430264165500233440ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/with/missing-deps/000077500000000000000000000000001430264165500213655ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/missing-deps/test.py000066400000000000000000000016301430264165500227160ustar00rootroot00000000000000""" Check that `with` works with missing dependencies """ import re import os from drivers.alr import run_alr from drivers.asserts import assert_match from glob import glob # Initialize test crate run_alr('init', '--bin', 'xxx') os.chdir('xxx') # 1st test, adding an entirely inexistent crate run_alr('with', 'unobtanium', force=True) # 2nd test, adding a dependency that exists but with missing version run_alr('with', 'libhello^3', force=True) # 3rd test, adding a dependency that has missing dependencies run_alr('with', 'hello^3', force=True) # Check that the solution contains the requested dependencies p = run_alr('with', '--solve') assert_match('.*Dependencies \(solution\):\n' ' hello=3\.0\.0.*' # skip origin 'Dependencies \(external\):\n' ' libhello\^3.*' # skip flags ' unobtanium\*.*', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/missing-deps/test.yaml000066400000000000000000000000641430264165500232300ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/with/narrow-pre1/000077500000000000000000000000001430264165500211405ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/narrow-pre1/my_index/000077500000000000000000000000001430264165500227545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/narrow-pre1/my_index/index/000077500000000000000000000000001430264165500240635ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/narrow-pre1/my_index/index/he/000077500000000000000000000000001430264165500244575ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/narrow-pre1/my_index/index/he/hello1/000077500000000000000000000000001430264165500256435ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/narrow-pre1/my_index/index/he/hello1/hello1-0.1.2.toml000066400000000000000000000003241430264165500303570ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello1" version = "0.1.2" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/with/narrow-pre1/my_index/index/he/hello2/000077500000000000000000000000001430264165500256445ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/narrow-pre1/my_index/index/he/hello2/hello2-1.2.3.toml000066400000000000000000000003241430264165500303640ustar00rootroot00000000000000description = "\"Hello, world!\" demonstration project" name = "hello2" version = "1.2.3" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [origin] url = "file:." alire-1.2.1/testsuite/tests/with/narrow-pre1/my_index/index/index.toml000066400000000000000000000000201430264165500260570ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/with/narrow-pre1/test.py000066400000000000000000000012631430264165500224730ustar00rootroot00000000000000""" Test that a dependency added as *, solved as 0.x, is narrowed down to ~0.x, whereas one solved as 1.x is narrowed down to ^1.x """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match # Create a new "xxx" program project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Make it depend on hello1 and hello2 run_alr('with', 'hello1', 'hello2') # Verify solution dependencies have been properly narrowed down as ^ or ~, with # also the proper lower version p = run_alr('with') assert_match('.*Dependencies \(direct\):\n' ' hello1~0\.1\.2\n' ' hello2\^1\.2\.3\n', p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/narrow-pre1/test.yaml000066400000000000000000000001101430264165500227730ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/with/nested-prj/000077500000000000000000000000001430264165500210365ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/nested-prj/test.py000066400000000000000000000012201430264165500223620ustar00rootroot00000000000000""" Verify proper working of nested project files (bugfix for #634) """ import os from drivers.alr import run_alr, init_local_crate from drivers.asserts import assert_eq # Initialize a project, have it to have a nested project file init_local_crate("xxx") # Make the project file nested (sources too, to avoid modifying the gpr file) os.mkdir("nested") os.rename("xxx.gpr", os.path.join("nested", "xxx.gpr")) os.rename("src", os.path.join("nested", "src")) # Update info in the manifest with open("alire.toml", "at") as manifest: manifest.write("project-files=['nested/xxx.gpr']") # Should not fail run_alr("with", "libhello") print('SUCCESS') alire-1.2.1/testsuite/tests/with/nested-prj/test.yaml000066400000000000000000000000631430264165500227000ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/with/no-double-add/000077500000000000000000000000001430264165500213755ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/no-double-add/test.py000066400000000000000000000007051430264165500227300ustar00rootroot00000000000000""" Verify prevention of double-add of dependencies """ import os from drivers.alr import run_alr from drivers.asserts import assert_eq # Initialize a project, enter it and double-add a dependency p = run_alr('init', '--bin', 'xxx') os.chdir('xxx') p = run_alr('with', 'libhello') p = run_alr('with', 'libhello', quiet=False, complain_on_error=False) assert_eq( 'ERROR: libhello is already a direct dependency.\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/with/no-double-add/test.yaml000066400000000000000000000000631430264165500232370ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/with/pin-dir-crate-autodetect/000077500000000000000000000000001430264165500235605ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir-crate-autodetect/test.py000066400000000000000000000017061430264165500251150ustar00rootroot00000000000000""" Test that `alr with --url` without explicit crate autodetects the target crate and correctly adds the pinned dependency """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import dir_separator from glob import glob # Retrieve a crate run_alr('get', 'hello=1') target = glob('hello*')[0] # Initialize a workspace run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Add the directory as pinned crate, with autodetection (no crate given, # inferred from the crate metadata found at target). run_alr('with', '--use', '..' + dir_separator() + target) # Verify that hello^1 is a new dependency and also that hello dependencies are # in the solution. p = run_alr('with', '--solve') assert_match('''Dependencies \(direct\): hello\^1\.0\.0 .*Dependencies \(solution\): hello=1\.0\.0 .* libhello=1\.1\.0 .*''', # we skip non-relevant details p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/pin-dir-crate-autodetect/test.yaml000066400000000000000000000001131430264165500254160ustar00rootroot00000000000000driver: python-script indexes: solver_index: in_fixtures: true alire-1.2.1/testsuite/tests/with/pin-dir-crate/000077500000000000000000000000001430264165500214215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir-crate/test.py000066400000000000000000000013651430264165500227570ustar00rootroot00000000000000""" Detect that a given folder to pin contains a crate and use its info """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import dir_separator from glob import glob # Retrieve a crate run_alr('get', 'hello=1') target = glob('hello*')[0] # Initialize a workspace run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Pin the hello crate as local dir dependency run_alr('with', 'hello', '--use', '..' + dir_separator() + target) # Verify that hello dependencies are detected and used p = run_alr('with', '--solve') assert_match('''.*Dependencies \(solution\): hello=1\.0\.0 .* libhello=1\.1\.0 .*''', # we skip non-relevant details p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/pin-dir-crate/test.yaml000066400000000000000000000001131430264165500232570ustar00rootroot00000000000000driver: python-script indexes: solver_index: in_fixtures: true alire-1.2.1/testsuite/tests/with/pin-dir-mismatch/000077500000000000000000000000001430264165500221305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir-mismatch/test.py000066400000000000000000000012311430264165500234560ustar00rootroot00000000000000""" Detect that a given folder to pin contains an unexpected crate """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import dir_separator from glob import glob # Retrieve a crate run_alr('get', 'hello=1') target = glob('hello*')[0] # Initialize a workspace run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Try to pin the hello crate as local dir dependency p = run_alr('with', 'nothello', '--use', '..' + dir_separator() + target, complain_on_error=False) # Expected error assert_match('.*expected nothello but found hello.*', p.out) # skip test-specific path print('SUCCESS') alire-1.2.1/testsuite/tests/with/pin-dir-mismatch/test.yaml000066400000000000000000000001131430264165500237660ustar00rootroot00000000000000driver: python-script indexes: solver_index: in_fixtures: true alire-1.2.1/testsuite/tests/with/pin-dir/000077500000000000000000000000001430264165500203255ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir/my_index/000077500000000000000000000000001430264165500221415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir/my_index/crates/000077500000000000000000000000001430264165500234225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir/my_index/crates/libhello_1.0.0/000077500000000000000000000000001430264165500257305ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir/my_index/crates/libhello_1.0.0/libhello.gpr000066400000000000000000000010151430264165500302310ustar00rootroot00000000000000project Libhello is for Library_Name use "Libhello"; for Library_Version use "0.0.0"; for Source_Dirs use ("src"); for Object_Dir use "obj"; for Library_Dir use "lib"; package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end Libhello; alire-1.2.1/testsuite/tests/with/pin-dir/my_index/crates/libhello_1.0.0/src/000077500000000000000000000000001430264165500265175ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir/my_index/crates/libhello_1.0.0/src/libhello.ads000066400000000000000000000000431430264165500307770ustar00rootroot00000000000000package Libhello is end Libhello; alire-1.2.1/testsuite/tests/with/pin-dir/my_index/index/000077500000000000000000000000001430264165500232505ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir/my_index/index/index.toml000066400000000000000000000000201430264165500252440ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/with/pin-dir/my_index/index/li/000077500000000000000000000000001430264165500236545ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir/my_index/index/li/libhello/000077500000000000000000000000001430264165500254465ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-dir/my_index/index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003151430264165500305660ustar00rootroot00000000000000description = "libhello" name = "libhello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["some@one.com"] maintainers-logins = ["mylogin"] [origin] url = "file:../../../crates/libhello_1.0.0" alire-1.2.1/testsuite/tests/with/pin-dir/test.py000066400000000000000000000023441430264165500216610ustar00rootroot00000000000000""" Addition of dependencies directly as a pinned directory """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match from drivers.helpers import dir_separator, with_project # Initialize a workspace, enter, and add a pinned dependency run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Prepend the library we want to use to its project file with_project('xxx.gpr', 'libhello') # Verify it doesn't build without it p = run_alr('build', complain_on_error=False) assert p.status != 0, "Build should fail" # Add pinned, check that it builds run_alr('with', 'libhello', '--use', '../my_index/crates/libhello_1.0.0') run_alr('build') # Check the pin shows in the solution p = run_alr('with', '--solve') # For this match we don't know where the test is temporarily put, so we skip # over some parts of the output assert_match('.*Dependencies \(external\):.*' 'libhello\^1\.0\.0 \(direct,linked' ',path=.*/my_index/crates/libhello_1.0.0\).*', p.out, flags=re.S) # Check that removing the dependency works and build is again failing run_alr('with', '--del', 'libhello') p = run_alr('build', complain_on_error=False) assert p.status != 0, "Build should fail" print('SUCCESS') alire-1.2.1/testsuite/tests/with/pin-dir/test.yaml000066400000000000000000000001101430264165500221600ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/with/pin-transitive/000077500000000000000000000000001430264165500217375ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/pin-transitive/test.py000066400000000000000000000021451430264165500232720ustar00rootroot00000000000000""" Check transitive links (a pinned dir that contains pinned dirs itself) """ import os import re from drivers.alr import run_alr, init_local_crate from drivers.asserts import assert_eq # The test will create ./indirect, ./direct, and ./nest/base crates. # Then they are pinned as base -> direct -> indirect. As "base" has a different # relative path to "indirect" than "direct", this is also checked. init_local_crate(name="indirect", binary=False, enter=False) # Now create "direct" and pin to "indirect" init_local_crate(name="direct", binary=False) run_alr("with", "--use=../indirect") # Now create "base" and pin to "direct" os.chdir("..") os.mkdir("nest") os.chdir("nest") init_local_crate(name="base") run_alr("with", "--use=../../direct") # Verify created pins p = run_alr("pin") assert_eq("direct file:../../direct \n" "indirect file:../../indirect \n", p.out) # Check pin removal os.chdir("../../direct") run_alr("with", "--del", "indirect") os.chdir("../nest/base") run_alr("update") p = run_alr("pin") assert_eq("direct file:../../direct \n", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/with/pin-transitive/test.yaml000066400000000000000000000001111430264165500235730ustar00rootroot00000000000000driver: python-script indexes: basic_index: in_fixtures: truealire-1.2.1/testsuite/tests/with/tree-switch/000077500000000000000000000000001430264165500212215ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/tree-switch/test.py000066400000000000000000000022601430264165500225520ustar00rootroot00000000000000""" Check output of the --tree switch """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match # Initialize project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Add dependency on hello^1. Solution is hello=1.0.1 --> libhello=1.1.0 run_alr('with', 'hello^1') # Add dependency on superhello*. Solution is superhello=1.0 --> libhello=1.0.1 # This implies a downgrade from libhello=1.1.0 to libhello=1.0.1, which is the # only possible combination of libhello^1.0 & libhello~1.0 run_alr('with', 'superhello') # Add more dependencies, without a proper release os.mkdir("fake") run_alr('with', 'wip', '--use', 'fake', force=True) # force bc dir is missing run_alr('with', 'unobtanium', force=True) # Verify printout (but for test-dependent path) # Note that superhello was auto-narrowed down to ^1, but missed ones did not p = run_alr('with', '--tree') assert_match(re.escape('''xxx=0.1.0-dev +-- hello=1.0.1 (^1) | +-- libhello=1.0.1 (^1.0) +-- superhello=1.0.0 (^1.0.0) | +-- libhello=1.0.1 (~1.0) +-- unobtanium* (direct,missed) (*) +-- wip* (direct,linked,path=''') + '.*' + re.escape(') (*)'), p.out, flags=re.S) print('SUCCESS') alire-1.2.1/testsuite/tests/with/tree-switch/test.yaml000066400000000000000000000000641430264165500230640ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/with/versions-switch/000077500000000000000000000000001430264165500221325ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/with/versions-switch/test.py000066400000000000000000000022461430264165500234670ustar00rootroot00000000000000""" Check output of with --versions switch """ import os import re from drivers.alr import run_alr from drivers.asserts import assert_match # Initialize project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Add dependency on hello^1. Solution is hello=1.0.1 --> libhello=1.1.0 run_alr('with', 'hello^1') # Add dependency on superhello*. Solution is superhello=1.0 --> libhello=1.0.1 # This implies a downgrade from libhello=1.1.0 to libhello=1.0.1, which is the # only possible combination of libhello^1.0 & libhello~1.0 run_alr('with', 'superhello') # Add a pinned directory and a missing dependency os.mkdir("fake") run_alr('with', 'wip', '--use', 'fake') run_alr('with', 'unobtanium', force=True) # Check output p = run_alr('with', '--versions') assert_match (re.escape ('CRATE DEPENDENCY SOLVED LATEST \n' 'hello ^1 1.0.1 4.0.0 \n' 'libhello (^1.0) & (~1.0) 1.0.1 2.0.0 \n' 'superhello * 1.0.0 1.0.0 \n' 'unobtanium * missing unindexed\n' 'wip * ') + '.*fake' + re.escape('unindexed\n' 'xxx (root) 0.0.0 unindexed\n'), p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/with/versions-switch/test.yaml000066400000000000000000000000641430264165500237750ustar00rootroot00000000000000driver: python-script indexes: solver_index: {} alire-1.2.1/testsuite/tests/workflows/000077500000000000000000000000001430264165500200455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/000077500000000000000000000000001430264165500242225ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/000077500000000000000000000000001430264165500260365ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/hello_src/000077500000000000000000000000001430264165500300105ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/hello_src/hello_world.gpr000066400000000000000000000001101430264165500330240ustar00rootroot00000000000000project Hello_World is for Source_Dirs use ("src"); end Hello_World; alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/hello_src/src/000077500000000000000000000000001430264165500305775ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/hello_src/src/.emptydir000066400000000000000000000000001430264165500324230ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/index/000077500000000000000000000000001430264165500271455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/index/he/000077500000000000000000000000001430264165500275415ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/index/he/hello_world/000077500000000000000000000000001430264165500320535ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000021131430264165500356320ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] executables = ["hello_world"] [[actions."case(os)".linux]] type = "post-fetch" command = ["touch", "test_post_fetch"] [[actions."case(os)".linux]] type = "pre-build" command = ["touch", "test_pre_build"] [[actions."case(os)".linux]] type = "post-build" command = ["touch", "test_post_build"] [[actions."case(os)".macos]] type = "post-fetch" command = ["touch", "test_post_fetch"] [[actions."case(os)".macos]] type = "pre-build" command = ["touch", "test_pre_build"] [[actions."case(os)".macos]] type = "post-build" command = ["touch", "test_post_build"] [[actions."case(os)".windows]] type = "post-fetch" command = ["cmd", "/C", "copy NUL test_post_fetch"] [[actions."case(os)".windows]] type = "pre-build" command = ["cmd", "/C", "copy NUL test_pre_build"] [[actions."case(os)".windows]] type = "post-build" command = ["cmd", "/C", "copy NUL test_post_build"] [origin] url = "file:../../../hello_src" alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/my_index/index/index.toml000066400000000000000000000000201430264165500311410ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/test.py000066400000000000000000000054101430264165500255530ustar00rootroot00000000000000""" Test pre-build/post-build/post-fetch executions in a crate that is a dependency """ from drivers.alr import run_alr, init_local_crate, add_action, alr_with from drivers.asserts import assert_match from drivers.helpers import compare, contents, on_windows from glob import glob from pathlib import Path from shutil import rmtree import os def check_expected(expected): if not (expected in contents('.')): assert False, "%s expected in %s\n Got: %s" % \ (expected, '.', str(contents('.'))) def check_not_expected(expected): if expected in contents('.'): assert False, "%s is unexpected in %s\n Got: %s" % \ (expected, '.', str(contents('.'))) def check(file, to_be_or_not_to_be): if to_be_or_not_to_be: check_expected(file) else: check_not_expected(file) def do_checks(path_to_dependency): flag_post_fetch = path_to_dependency + "/test_post_fetch" flag_pre_build = path_to_dependency + "/test_pre_build" flag_post_build = path_to_dependency + "/test_post_build" # Immediately after adding the dependency, this is the situation: check(flag_post_fetch, True) check(flag_pre_build, False) check(flag_post_build, False) # Remove post-fetch to check it doesn't come back unexpectedly os.remove(flag_post_fetch) # Build with error, so only pre-build runs but not post-build Path(f"{path_to_dependency}/src/empty.adb").touch() p = run_alr('build', complain_on_error=False) assert_match(".*compilation of empty.adb failed.*", p.out) # Post build shouldn't be here because of build failure check(flag_post_fetch, False) check(flag_pre_build, True) check(flag_post_build, False) os.remove(flag_pre_build) os.remove(f"{path_to_dependency}/src/empty.adb") # Build without error run_alr('build') # pre/post-build expected for successful build check(flag_post_fetch, False) check(flag_pre_build, True) check(flag_post_build, True) return # updating dependencies causes the post-fetch action to run: run_alr('update') check(flag_post_fetch, True) check(flag_pre_build, True) check(flag_post_build, True) # Initialize a crate and add as dependency the crate that contains the triggers init_local_crate("root", binary=False) # Lib so all contents are compiled alr_with("hello_world") # Test all triggers do_checks(glob("./alire/cache/dependencies/hello*")[0].replace('\\', '/')) # Repeat tests, for a crate that has been added as a linked dependency os.chdir("..") rmtree("root") run_alr("get", "hello_world") hello = glob("hello*")[0].replace('\\', '/') init_local_crate("root", binary=False) os.rename(f"../{hello}", f"./{hello}") alr_with(path=f"{hello}", manual=False) do_checks(f"./{hello}") print('SUCCESS') alire-1.2.1/testsuite/tests/workflows/actions-as-dependency/test.yaml000066400000000000000000000001101430264165500260550ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/workflows/actions-as-root/000077500000000000000000000000001430264165500230675ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-root/my_index/000077500000000000000000000000001430264165500247035ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-root/my_index/hello_src/000077500000000000000000000000001430264165500266555ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-root/my_index/hello_src/hello_world.gpr000066400000000000000000000001101430264165500316710ustar00rootroot00000000000000project Hello_World is for Source_Dirs use ("src"); end Hello_World; alire-1.2.1/testsuite/tests/workflows/actions-as-root/my_index/index/000077500000000000000000000000001430264165500260125ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-root/my_index/index/he/000077500000000000000000000000001430264165500264065ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-root/my_index/index/he/hello_world/000077500000000000000000000000001430264165500307205ustar00rootroot00000000000000hello_world-0.1.0.toml000066400000000000000000000020541430264165500345030ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/actions-as-root/my_index/index/he/hello_worlddescription = "\"Hello, world!\" demonstration project" name = "hello_world" version = "0.1.0" licenses = "GPL-3.0-only" maintainers = ["example@example.com"] maintainers-logins = ["mylogin"] [[actions."case(os)".linux]] type = "post-fetch" command = ["touch", "test_post_fetch"] [[actions."case(os)".linux]] type = "pre-build" command = ["touch", "test_pre_build"] [[actions."case(os)".linux]] type = "post-build" command = ["touch", "test_post_build"] [[actions."case(os)".macos]] type = "post-fetch" command = ["touch", "test_post_fetch"] [[actions."case(os)".macos]] type = "pre-build" command = ["touch", "test_pre_build"] [[actions."case(os)".macos]] type = "post-build" command = ["touch", "test_post_build"] [[actions."case(os)".windows]] type = "post-fetch" command = ["cmd", "/C", "copy NUL test_post_fetch"] [[actions."case(os)".windows]] type = "pre-build" command = ["cmd", "/C", "copy NUL test_pre_build"] [[actions."case(os)".windows]] type = "post-build" command = ["cmd", "/C", "copy NUL test_post_build"] [origin] url = "file:../../../hello_src" alire-1.2.1/testsuite/tests/workflows/actions-as-root/my_index/index/index.toml000066400000000000000000000000201430264165500300060ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/workflows/actions-as-root/test.py000066400000000000000000000046011430264165500244210ustar00rootroot00000000000000""" Test pre-build/post-build/post-fetch executions on a crate that is the root """ from drivers.alr import run_alr, init_local_crate, add_action, alr_with from drivers.asserts import assert_match from drivers.helpers import compare, contents, on_windows from pathlib import Path import os def check_expected(expected): if not (expected in contents('.')): assert False, "%s expected in %s\n Got: %s" % \ (expected, '.', str(contents('.'))) def check_not_expected(expected): if expected in contents('.'): assert False, "%s is unexpected in %s\n Got: %s" % \ (expected, '.', str(contents('.'))) # Get and check post fetch action run_alr('get', 'hello_world') os.chdir("hello_world_0.1.0_filesystem/") check_expected('./test_post_fetch') check_not_expected('./test_pre_build') check_not_expected('./test_post_build') # Remove post-fetch to check it doesn't come back os.remove('./test_post_fetch') # Build with error os.mkdir('src') Path('src/empty.adb').touch() p = run_alr('build', complain_on_error=False) assert_match(".*compilation of empty.adb failed.*", p.out) # Post build shouldn't be here because of build failure check_not_expected('./test_post_fetch') check_expected('./test_pre_build') check_not_expected('./test_post_build') os.remove('./test_pre_build') os.remove('src/empty.adb') # Build without error run_alr('build', complain_on_error=False) # pre/post-build expected for successful build check_not_expected('./test_post_fetch') check_expected('./test_pre_build') check_expected('./test_post_build') # updating dependencies causes the post-fetch action on the root crate to run: run_alr('update') check_expected('./test_post_fetch') check_expected('./test_pre_build') check_expected('./test_post_build') # Add a linked dependency. Since these are never "fetched", in order to # complete their action cycle, post-fetch is also run on updates init_local_crate("depended", binary=False, enter=True) # Add a similar action if on_windows(): add_action("post-fetch", ["cmd", "/C", "copy NUL test_post_fetch_dep"]) else: add_action("post-fetch", ["touch", "test_post_fetch_dep"]) check_not_expected('./test_post_fetch_dep') os.chdir("..") # Back to parent crate alr_with("depended", path="depended", update=False) run_alr("update") check_not_expected('./test_post_fetch_dep') check_expected('./depended/test_post_fetch_dep') print('SUCCESS') alire-1.2.1/testsuite/tests/workflows/actions-as-root/test.yaml000066400000000000000000000001101430264165500247220ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false alire-1.2.1/testsuite/tests/workflows/edit/000077500000000000000000000000001430264165500207725ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/edit/my_index/000077500000000000000000000000001430264165500226065ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/edit/my_index/index.toml000066400000000000000000000000201430264165500246020ustar00rootroot00000000000000version = "1.1" alire-1.2.1/testsuite/tests/workflows/edit/my_index/li/000077500000000000000000000000001430264165500232125ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/edit/my_index/li/libhello/000077500000000000000000000000001430264165500250045ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/edit/my_index/li/libhello/libhello-1.0.0.toml000066400000000000000000000003731430264165500301300ustar00rootroot00000000000000auto-gpr-with = false description = "test" name = "libhello" version = "1.0.0" licenses = "GPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] project-files = ["project1.gpr", "project2.gpr"] [origin] url = "file:." alire-1.2.1/testsuite/tests/workflows/edit/test.py000066400000000000000000000024541430264165500223300ustar00rootroot00000000000000""" Test alr edit with two project files defined. """ from glob import glob from drivers.alr import run_alr from drivers.asserts import assert_match import os import shutil # Get the "libhello" project and enter its directory run_alr('get', 'libhello') os.chdir(glob('libhello*')[0]) gs = shutil.which('gnatstudio') if gs is None: # GNATstudio not in PATH: Check that we get an error saying GS not # available p = run_alr('edit', complain_on_error=False) assert_match(".*GNAT Studio not available or not in PATH.*", p.out) else: # GNATstudio in PATH: Check that we get an error when multiple project # files are defined p = run_alr('edit', complain_on_error=False) assert_match(".*Please specify a project file with --project=.*", p.out) # Set an editor that doesn't exist (different than GNAT Studio) run_alr('config', '--set', 'editor.cmd', 'doesnt_exist arg1 ab${GPR_FILE}ab arg3') p = run_alr('edit', '--project=project1.gpr', complain_on_error=False) assert_match("ERROR: 'doesnt_exist' not available or not in PATH.*", p.out) print(p.out) # Use echo as an editor to check command line args run_alr('config', '--set', 'editor.cmd', 'echo arg1 ab${GPR_FILE}ab arg3') p = run_alr('edit', '--project=project1.gpr') assert_match("arg1 abproject1.gprab arg3", p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/workflows/edit/test.yaml000066400000000000000000000001461430264165500226360ustar00rootroot00000000000000driver: python-script indexes: my_index: in_fixtures: false copy_crates_src: true alire-1.2.1/testsuite/tests/workflows/get-build-run-clean/000077500000000000000000000000001430264165500236035ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/get-build-run-clean/test.py000066400000000000000000000007001430264165500251310ustar00rootroot00000000000000""" Test a basic get-build-run workflow. """ from glob import glob import os from drivers.alr import run_alr from drivers.asserts import assert_eq # Get the "hello" project and enter its directory run_alr('get', 'hello') os.chdir(glob('hello*')[0]) # Build it run_alr('build') # Run it p = run_alr('run') assert_eq('Hello, world!\n', p.out) # Clean it assert os.listdir('obj') run_alr('clean') assert not os.listdir('obj') print('SUCCESS') alire-1.2.1/testsuite/tests/workflows/get-build-run-clean/test.yaml000066400000000000000000000000631430264165500254450ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/testsuite/tests/workflows/init-options/000077500000000000000000000000001430264165500225015ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/init-options/test.py000066400000000000000000000043661430264165500240430ustar00rootroot00000000000000""" Test init command produced artifacts and options """ import os.path from drivers.alr import run_alr from drivers.asserts import assert_eq, assert_match from drivers.helpers import compare, contents test_dir = os.getcwd() # Invalid crate name p = run_alr('init', '--bin', 'invalid-name', complain_on_error=False) assert_match(".*Identifiers must be.*", p.out) # Plain init run_alr('init', '--bin', 'xxx') compare(contents('xxx'), ['xxx/.gitignore', 'xxx/alire.toml', 'xxx/share', 'xxx/share/xxx', 'xxx/src', 'xxx/src/xxx.adb', 'xxx/xxx.gpr']) # Plain init, existing empty dir os.mkdir('aaa') run_alr('init', '--bin', 'aaa') compare(contents('aaa'), ['aaa/.gitignore', 'aaa/aaa.gpr', 'aaa/alire.toml', 'aaa/share', 'aaa/share/aaa', 'aaa/src', 'aaa/src/aaa.adb']) # Init without skeleton run_alr('init', '--bin', '--no-skel', 'yyy') compare(contents('yyy'), ['yyy/alire.toml', ]) # Init with existing crate os.chdir('yyy') run_alr('init', '--bin', '--no-skel', 'yyy', quiet=False) # Init in place with existing crate FAIL (we do not overwrite files) os.chdir('yyy') p = run_alr('init', '--bin', '--in-place', '--no-skel', 'yyy', complain_on_error=False, quiet=False) assert_match(".*alire.toml already exists.*", p.out) # Init in place with existing invalid crate FAIL (we don't even try to load it) with open('alire.toml', 'w') as f: f.write("plop") p = run_alr('init', '--bin', '--in-place', '--no-skel', 'yyy', complain_on_error=False, quiet=False) assert_match(".*alire.toml already exists.*", p.out) os.chdir(test_dir) # Init in place os.mkdir('zzz') os.chdir('zzz') run_alr('init', '--bin', '--in-place', 'zzz') compare(contents('.'), ['./.gitignore', './alire.toml', './share', './share/zzz', './src', './src/zzz.adb', './zzz.gpr']) print('SUCCESS') alire-1.2.1/testsuite/tests/workflows/init-options/test.yaml000066400000000000000000000000261430264165500243420ustar00rootroot00000000000000driver: python-script alire-1.2.1/testsuite/tests/workflows/init-with-pin/000077500000000000000000000000001430264165500225455ustar00rootroot00000000000000alire-1.2.1/testsuite/tests/workflows/init-with-pin/test.py000066400000000000000000000022171430264165500241000ustar00rootroot00000000000000""" Test a basic init-with-pin-run workflow. """ import os from drivers.alr import run_alr, alr_pin from drivers.asserts import assert_eq from drivers.helpers import check_line_in # Create a new "xxx" program project run_alr('init', '--bin', 'xxx') os.chdir('xxx') # Make it depend on libhello, it is auto-narrowed down to ^1 session_file = os.path.join('alire.toml') run_alr('with', 'libhello') check_line_in(session_file, 'libhello = "^1.0.0"') # Add the corresponding "with" line in xxx.gpr. # # TODO: maybe "alr with" should do that automatically? with open('xxx.gpr', 'r') as f: content = f.read() with open('xxx.gpr', 'w') as f: f.write('with "libhello";\n') f.write(content) # Pin the version of libhello and verify pin is there alr_pin('libhello', version='1.0') p = run_alr('pin') assert_eq('libhello 1.0.0\n', p.out) # Build and run "xxx" with open(os.path.join('src', 'xxx.adb'), 'w') as f: f.write(""" with Ada.Text_IO; with libhello; procedure XXX is begin Ada.Text_IO.Put_Line ("This is XXX..."); libhello.Hello_World; end XXX; """) p = run_alr('run') assert_eq('This is XXX...\nHello, world!\n', p.out) print('SUCCESS') alire-1.2.1/testsuite/tests/workflows/init-with-pin/test.yaml000066400000000000000000000000631430264165500244070ustar00rootroot00000000000000driver: python-script indexes: basic_index: {} alire-1.2.1/trash/000077500000000000000000000000001430264165500137365ustar00rootroot00000000000000alire-1.2.1/trash/changelog.txt000066400000000000000000000013201430264165500164220ustar00rootroot000000000000002018-03-09: Better expression requisites 2018-03-05: Chains of preferred dependencies 2018-03-03: Native packages per distro with autodetection of availability 2018-02-29: Conditional properties and their materialization 2018-02-28: Declaration of scenario variables, native packages a-la OPAM 2018-02-26: query policies, search by property 2018-02-25: licenses as properties 2018-02-22: alr test command 2018-02-20: get --info 2018-02-20: Named properties (Labels); e.g.: Maintainer, Website 2018-02-18: Recovery from backup executable if compilation interrupted 2018-02-14: Properties with arbitrary logical expressions 2018-02-11: Native packages as valid dependencies 2018-02-08: Captured output of spawned commands alire-1.2.1/trash/issues.txt000066400000000000000000000000751430264165500160140ustar00rootroot00000000000000Moved to Issues/Projects in https://github.com/alire-project alire-1.2.1/trash/shipcommon000066400000000000000000000000501430264165500160300ustar00rootroot00000000000000#!/usr/bin/env bash cratedir=cratetest alire-1.2.1/trash/shippable.yml000066400000000000000000000013521430264165500164310ustar00rootroot00000000000000language: none # Ada integrations: notifications: - integrationName: email type: email on_success: change on_failure: change on_cancel: never branches: only: - master - stable - testing env: global: - IMAGE_NAME="alire/gnat" matrix: - IMAGE_TAG="centos-latest-community-2019" - IMAGE_TAG="community-current" - IMAGE_TAG="debian-stable" - IMAGE_TAG="ubuntu-lts" build: pre_ci_boot: image_name: $IMAGE_NAME image_tag: $IMAGE_TAG pull: true ci: - pip install git+https://github.com/AdaCore/e3-testsuite.git@1c751b82 - scripts/shiptest.sh alire-1.2.1/trash/shippable/000077500000000000000000000000001430264165500157055ustar00rootroot00000000000000alire-1.2.1/trash/shippable/samples/000077500000000000000000000000001430264165500173515ustar00rootroot00000000000000alire-1.2.1/trash/shippable/samples/alr.bad000066400000000000000000000112041430264165500205750ustar00rootroot00000000000000 0 0 0 0 release : ada_lua=0.0.0-5.3 release : adayaml=0.2.0 release : adayaml=0.3.0 release : adayaml.server=0.3.0 release : alire=0.1.2 release : alire=0.2.0 release : alr=0.1.2 release : alr=0.2.0 release : apq=3.2.0 release : aunit=2017.0.0 release : globe_3d=20180111.0.0 release : glut=2.8.1-3 release : hangman=1.0.0 release : hello=1.0.0 release : hello=1.0.1 release : libadacrypt=0.8.7 release : libglfw3=3.0.0 release : libgnutls=3.5.8 release : libhello=1.0.0 release : liblua=5.3.0 release : libsdl2=2.0.0 release : libsdl2.image=2.0.0 release : libsdl2.ttf=2.0.0 release : libx11=2.0.0 release : make=0.0.0 release : mathpaqs=20180114.0.0 release : openglada=0.6.0 release : pragmarc=2011.1995.0 release : pragmarc=2017.2007.0 release : rxada=0.1.0 release : sdlada=2.3.1 release : semantic_versioning=0.1.2 release : semantic_versioning=0.2.0 release : semantic_versioning=0.3.0 release : simple_components.connections=4.27.0 release : simple_components.connections.ntp=4.27.0 release : simple_components.connections.secure=4.27.0 release : simple_components.core=4.27.0 release : simple_components.odbc=4.27.0 release : simple_components.sqlite=4.27.0 release : simple_components.strings_edit=4.27.0 release : simple_components.tables=4.27.0 release : simple_logging=1.0.0 release : unixodbc=2.3.0 release : whitakers_words=2017.9.10 alire-1.2.1/trash/shippable/samples/alr.xml000066400000000000000000000012551430264165500206540ustar00rootroot00000000000000 error output fail output alire-1.2.1/trash/shippable/samples/sample.ok000066400000000000000000000002241430264165500211630ustar00rootroot00000000000000 alire-1.2.1/trash/shippable/testresults/000077500000000000000000000000001430264165500203065ustar00rootroot00000000000000alire-1.2.1/trash/shippable/testresults/.emptydir000066400000000000000000000000001430264165500221320ustar00rootroot00000000000000alire-1.2.1/trash/shiptest.sh000077500000000000000000000016011430264165500161360ustar00rootroot00000000000000#!/usr/bin/env bash trap 'echo "ERROR at line ${LINENO} (code: $?)" >&2' ERR trap 'echo "Interrupted" >&2 ; exit 1' INT set -o errexit set -o nounset # For the record echo ENVIRONMENT: env | sort echo ............................ # Ensure subrepos are there git submodule update --init --recursive # Check compilation in all cases gprbuild -j0 -p -P alr_env # Check installer in stable branch if [ "$BRANCH" == "stable" ] || [ "$BASE_BRANCH" == "stable" ]; then echo -e '\n\n/bin\ny' | ./install/alr-bootstrap.sh fi export PATH+=:`pwd`/bin echo GNAT VERSION: gnatls -v echo ............................ echo ALR VERSION: alr version echo ............................ # List releases for the record alr search -d --list --native # Run e3.testsuite echo cd testsuite ./run.py --xunit-output ../shippable/testresults/e3-output.xml || echo Test suite failures, unstable build! cd .. alire-1.2.1/trash/shiptrigci.sh000077500000000000000000000012211430264165500164360ustar00rootroot00000000000000#!/usr/bin/env bash trap 'echo "ERROR at line ${LINENO} (code: $?)" >&2' ERR trap 'echo "Interrupted" >&2 ; exit 1' INT set -o errexit set -o nounset function crate_test() { git clone https://github.com/alire-project/alire-crates-ci pushd alire-crates-ci date -u > last-run git add last-run git commit -m "Crate check triggered from alire" git push popd } # Check crates if commiting to master or stable if [ "$IS_PULL_REQUEST" == false ]; then if [ "$BRANCH" == "master" ] || [ "$BRANCH" == "stable" ]; then echo Triggering downstream crate CI test... fi fi # do it always until tested working crate_test alire-1.2.1/trash/stress/000077500000000000000000000000001430264165500152615ustar00rootroot00000000000000alire-1.2.1/trash/stress/alire-index-template01.ads000066400000000000000000000010071430264165500221230ustar00rootroot00000000000000with Alire.Index.Libhello; package Alire.Index.Template is Name : constant Project_Name := "Template"; Repo : constant URL := "https://bitbucket.org/aleteolabs/hello.git"; V_1_0_0 : constant Release := Register_Git (Name, V ("1.0.0"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); end Alire.Index.Template; alire-1.2.1/trash/stress/alire-index-template10.ads000066400000000000000000000063551430264165500221360ustar00rootroot00000000000000with Alire.Index.Libhello; package Alire.Index.Template is Name : constant Project_Name := "Template"; Repo : constant URL := "https://bitbucket.org/aleteolabs/hello.git"; V_1_0_0 : constant Release := Register_Git (Name, V ("1.0.0"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_1 : constant Release := Register_Git (Name, V ("1.0.1"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_2 : constant Release := Register_Git (Name, V ("1.0.2"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_3 : constant Release := Register_Git (Name, V ("1.0.3"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_4 : constant Release := Register_Git (Name, V ("1.0.4"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_5 : constant Release := Register_Git (Name, V ("1.0.5"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_6 : constant Release := Register_Git (Name, V ("1.0.6"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_7 : constant Release := Register_Git (Name, V ("1.0.7"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_8 : constant Release := Register_Git (Name, V ("1.0.8"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); V_1_0_9 : constant Release := Register_Git (Name, V ("1.0.9"), Repo, "8cac0afddc505794ae3e5634745ce0830129d241", Depends_On => At_Least_Within_Major (Libhello.V_1_0_0)); end Alire.Index.Template; alire-1.2.1/trash/stress/avg.sh000077500000000000000000000000751430264165500163770ustar00rootroot00000000000000awk '{ total += $1 ; count++ } END { print total/count }' $1 alire-1.2.1/trash/stress/gen.sh000077500000000000000000000004521430264165500163720ustar00rootroot00000000000000#!/bin/bash echo Use: $0 " " num=${1} src=${2} dst=${3} [[ -f $src ]] || { echo "No src"; exit 1; } [[ -d $dst ]] || { echo "No dst"; exit 1; } for i in `seq -w 1 $num`; do file=$dst/alire-index-test$i.ads cp -fv $src $file sed -i "s/Template/Test$i/" $file done alire-1.2.1/trash/stress/selftest.sh000077500000000000000000000047031430264165500174550ustar00rootroot00000000000000#!/bin/bash repo="https://github.com/alire-project/alr" set -o errexit set -o nounset trap 'echo "ERROR at line ${LINENO} (code: $?)" >&2; ln -sf ~/local/alr/bin/alr;' ERR trap 'echo "Interrupted" >&2 ; exit 1; ln -sf ~/local/alr/bin/alr;' INT mkdir -p ~/.config/alire version=${1:-working} if [[ "$version" == "working" ]]; then echo Testing WORKING version, press enter current=`pwd` # pushd ~/opt/bin ln -sf "$current"/bin/alr popd read elif [[ "$version" == "docker" ]]; then echo Testing DOCKER version export PATH+=:`pwd`/bin elif [[ "$version" == "release" ]]; then echo Testing RELEASE version, press enter pushd ~/opt/bin ln -sf ~/.config/alire/alr/bin/alr popd read else # Let's presume it's a testing branch: echo About to test branch $version as release candidate, press enter read rm -rf ~/.config/alire mkdir -p ~/.config/alire git clone --recurse-submodules -n $repo ~/.config/alire/alr pushd ~/.config/alire/alr git checkout $version git submodule update --init --recursive gprbuild -p -P alr_env popd pushd ~/opt/bin ln -sf ~/.config/alire/alr/bin/alr popd fi workspace=/tmp/alrtest rm -rf ~/.cache/alire rm -rf $workspace mkdir $workspace pushd $workspace # BUILD test echo BUILD alr get hello pushd hello* alr build popd # CLEAN test pushd hello* echo CLEAN alr clean popd # COMPILE echo COMPILE pushd hello* alr compile popd rm -rf hello* alr get hello pushd hello* alr compile popd rm -rf hello* alr get --compile libhello rm -rf libhello # GET echo GET alr get --compile hello rm -rf hello* # HELP echo HELP alr help build | grep -q online # INIT echo INIT alr init --bin xxx rm -rf xxx alr init --lib xxx rm -rf xxx #alr init --bin -b xxx #rm -rf xxx #alr init --lib -b xxx #rm -rf xxx # PIN echo PIN alr init --bin xxx cd xxx alr with libhello grep -q -i 'libhello = "any"' alire/xxx.toml alr pin grep -q -i 'libhello = "1.0.0"' alire/xxx.toml cd .. rm -rf xxx # RUN echo RUN alr get hello cd hello* # Next should fail since there's no exec, hence not failing the test alr run -s >/dev/null && { echo FAIL ; exit 1; } || echo Run without exec PASSED alr run | grep -q -i hello cd .. rm -rf hello* # SEARCH echo SEARCH alr search --list | grep -q -i hello alr search hell | grep -q -i hello # UPDATE echo UPDATE # outisde alr update # inside alr init --bin xxx cd xxx alr update cd .. rm -rf xxx # END echo ' ' echo PASSED with crawling colors alire-1.2.1/trash/stress/tester.sh000077500000000000000000000007621430264165500171330ustar00rootroot00000000000000#!/bin/bash echo "use: $0 " echo Requires x0 and x1, alr projects in current folder echo Times will be output to times-`date`.txt now=`date -Is` result=`pwd`/times-$now.txt trace=`pwd`/trace-$now.txt for i in `seq 1 $1`; do rm -rf ~/.cache/alire/sessions rm -rf ~/local/alr/bin/alr # Gnat seems to not detect changes below the second mark pushd x$(($i % 2)) pwd ( /usr/bin/time -f %e alr dev -v --self ) 2>> "$result" | tee -a "$trace" popd done echo DONE alire-1.2.1/trash/stress/times10000x1000066400000000000000000000002641430264165500171610ustar00rootroot0000000000000032.04 36.63 63.47 32.63 32.81 36.99 31.87 32.27 33.27 32.28 33.46 31.97 32.81 33.04 33.36 31.93 32.36 32.72 32.68 32.39 33.28 33.79 32.89 34.06 32.44 33.17 32.37 32.46 32.56 34.75 alire-1.2.1/trash/stress/times10000x10000066400000000000000000000011221430264165500172330ustar00rootroot0000000000000043.00 42.75 66.64 42.55 43.72 57.58 43.43 42.68 42.94 43.52 59.57 42.59 42.96 42.49 42.99 42.88 43.55 42.67 43.23 42.74 43.55 43.50 44.64 44.36 43.15 43.07 42.82 43.08 44.33 43.14 43.54 42.24 42.98 44.52 42.72 42.96 43.06 50.49 43.31 42.66 43.34 42.72 43.18 42.35 44.01 48.78 48.65 45.78 43.94 43.07 42.77 48.98 42.89 43.30 42.51 43.06 43.17 49.14 42.72 46.93 53.15 43.98 42.68 51.43 51.07 43.94 53.26 44.85 44.17 43.11 43.46 43.49 44.02 44.09 49.39 43.37 42.99 43.05 57.31 42.60 43.18 42.82 42.92 47.93 43.03 42.98 43.11 43.72 48.81 43.63 44.44 43.92 42.98 43.49 42.83 43.19 43.11 44.17 42.82 alire-1.2.1/trash/stress/times1000x1000066400000000000000000000007571430264165500171100ustar00rootroot000000000000003.57 3.44 3.60 3.54 3.47 3.55 3.60 3.64 3.51 3.53 4.44 4.29 3.62 3.77 4.14 3.56 3.54 3.44 3.86 3.61 3.53 3.53 3.56 3.76 3.56 3.60 3.52 3.71 3.70 3.59 3.50 3.51 3.57 3.48 3.88 3.94 3.60 3.62 3.49 3.92 3.81 3.70 3.53 3.60 3.68 3.67 3.62 3.56 3.81 3.74 3.67 3.63 3.59 3.65 3.76 4.57 3.56 3.64 3.57 3.67 3.60 3.73 3.99 3.56 3.54 3.58 3.50 3.55 3.67 3.86 4.10 4.41 3.98 3.63 3.83 3.59 3.66 3.74 4.02 8.07 3.57 3.61 3.60 3.46 3.81 3.64 3.66 3.48 3.61 3.63 3.68 3.94 3.45 3.64 3.94 3.74 3.50 3.85 3.47 alire-1.2.1/trash/stress/times1000x10000066400000000000000000000007571430264165500171700ustar00rootroot000000000000004.48 4.43 4.47 4.45 4.69 4.55 4.32 4.40 4.53 4.36 4.51 5.22 5.04 4.37 4.39 4.39 4.45 4.50 4.38 4.47 4.39 4.73 4.46 4.48 4.38 4.39 4.39 4.51 4.44 4.46 4.60 4.54 4.50 4.46 4.48 4.91 4.83 4.88 4.86 4.66 4.47 4.63 4.91 4.45 4.46 4.47 4.48 4.56 4.42 4.43 4.49 4.40 4.88 4.76 4.54 4.49 4.47 4.55 4.61 5.24 4.87 4.62 4.66 4.39 4.55 4.41 4.56 4.38 4.53 4.47 4.41 4.44 4.29 4.59 4.41 4.40 4.50 4.45 4.41 4.35 4.35 4.33 4.52 4.78 4.51 4.45 4.60 4.34 4.42 4.40 4.44 4.46 4.45 4.62 4.40 4.43 4.44 4.38 4.39 alire-1.2.1/trash/stress/times100x1000066400000000000000000000007641430264165500170260ustar00rootroot000000000000001.78 1.65 1.84 1.79 1.92 1.65 1.91 1.87 1.65 1.90 1.84 1.67 1.90 1.92 1.66 1.84 1.85 1.64 1.89 1.71 1.82 1.66 1.93 1.82 1.79 1.94 1.66 1.92 1.72 1.86 1.69 1.90 1.66 1.91 1.80 2.11 1.73 1.87 1.91 1.65 1.87 1.87 1.66 1.87 1.85 1.66 1.88 1.68 1.87 1.73 1.91 1.65 1.86 1.72 1.83 1.69 1.88 1.65 1.92 2.09 2.10 1.74 2.23 1.97 1.93 1.75 2.00 1.70 2.08 1.87 1.88 1.95 2.06 1.98 2.32 1.99 2.03 1.72 1.82 2.18 1.68 1.83 1.76 1.84 1.66 1.88 1.65 1.82 1.69 1.86 1.66 1.96 1.91 1.67 1.87 1.83 1.66 1.91 1.91 1.66 alire-1.2.1/trash/stress/times100x10000066400000000000000000000007571430264165500171100ustar00rootroot000000000000001.72 1.99 2.17 1.77 1.90 1.84 2.09 1.77 2.06 1.77 1.90 2.05 1.91 2.11 1.84 2.25 1.95 2.10 1.74 1.99 1.74 1.88 1.80 2.26 2.07 2.28 1.82 2.17 2.45 2.00 1.97 1.72 1.87 1.88 1.89 1.88 1.78 1.92 1.90 1.84 1.95 1.71 1.92 2.04 1.85 1.89 1.88 1.92 1.71 2.04 2.05 1.70 1.93 1.88 2.32 2.03 2.42 2.36 1.82 1.90 1.75 2.06 1.74 1.94 2.04 1.81 2.27 1.77 1.95 1.73 1.99 2.05 1.74 1.90 1.82 2.04 1.72 1.91 2.06 1.72 1.92 1.82 1.90 1.70 1.95 1.72 1.88 3.41 1.88 1.93 1.88 1.81 1.98 1.72 1.94 1.91 1.71 1.90 1.96 pax_global_header00006660000000000000000000000064142662367650014533gustar00rootroot0000000000000052 comment=906d9eaf4fb8efabfbc3d8cfb34d04ceec340e13 alire-1.2.1/deps/aaa/000077500000000000000000000000001426623676500143055ustar00rootroot00000000000000alire-1.2.1/deps/aaa/.github/000077500000000000000000000000001426623676500156455ustar00rootroot00000000000000alire-1.2.1/deps/aaa/.github/workflows/000077500000000000000000000000001426623676500177025ustar00rootroot00000000000000alire-1.2.1/deps/aaa/.github/workflows/build.yml000066400000000000000000000014341426623676500215260ustar00rootroot00000000000000name: Build on: push: branches: [ master ] pull_request: workflow_dispatch: jobs: build: strategy: matrix: os: [macos-latest, windows-latest, ubuntu-latest] gnat_version: [^10, ^11] gprbuild_version: [^21] runs-on: ${{ matrix.os }} env: AAA_STYLE_CHECKS: enabled AAA_RUNTIME_CHECKS: enabled AAA_COMPILE_CHECKS: enabled AAA_CONTRACTS: enabled steps: - name: Checkout uses: actions/checkout@v2 - name: Set up Alire and toolchain uses: alire-project/setup-alire@v1 with: toolchain: gprbuild${{ matrix.gprbuild_version }} gnat_native${{ matrix.gnat_version }} --disable-assistant - name: Build run: alr -q build - name: Run tests run: cd tests && alr -q run alire-1.2.1/deps/aaa/.gitignore000066400000000000000000000001141426623676500162710ustar00rootroot00000000000000*.ali *.db *.o *-loc.xml alire/ alire.lock bin lib obj /obj/ /lib/ /alire/ alire-1.2.1/deps/aaa/LICENSE000066400000000000000000000167431426623676500153250ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. alire-1.2.1/deps/aaa/README.md000066400000000000000000000010441426623676500155630ustar00rootroot00000000000000# AAA [![Build](https://github.com/mosteo/aaa/workflows/Build/badge.svg)](https://github.com/mosteo/aaa/actions) [![Alire](https://img.shields.io/endpoint?url=https://alire.ada.dev/badges/aaa.json)](https://alire.ada.dev/crates/aaa.html) Alex's Ada Assortment of Utilities - Text formatting (paragraphs, tables). - Indefinite containers. - Enumeration validity/conversions of string images. - On-demand stack backtraces. - String containers and utilities. - Simple subprocess spawning. - Write-through minimal cache for objects stored in files alire-1.2.1/deps/aaa/aaa.gpr000066400000000000000000000015331426623676500155430ustar00rootroot00000000000000with "config/aaa_config.gpr"; project Aaa is for Library_Name use "aaa"; for Library_Version use Project'Library_Name & ".so." & Aaa_Config.Crate_Version; for Source_Dirs use ("src/", "config/"); for Object_Dir use "obj/" & Aaa_Config.Build_Profile; for Create_Missing_Dirs use "True"; for Library_Dir use "lib"; type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := external ("AAA_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); for Library_Kind use Library_Type; package Compiler is for Default_Switches ("Ada") use Aaa_Config.Ada_Compiler_Switches; end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; package Install is for Artifacts (".") use ("share"); end Install; end Aaa; alire-1.2.1/deps/aaa/aaa_demos.gpr000066400000000000000000000005771426623676500167410ustar00rootroot00000000000000with "aaa"; project AAA_Demos is for Source_Dirs use ("src/demos"); for Object_Dir use "obj"; for Exec_Dir use "bin"; for Main use ("aaa-demo-misc.adb"); package Builder renames AAA.Builder; package Compiler renames AAA.Compiler; package Binder renames AAA.Binder; package Linker is for Switches ("ada") use ("-g"); end Linker; end AAA_Demos; alire-1.2.1/deps/aaa/aaa_dev.gpr000066400000000000000000000001751426623676500164020ustar00rootroot00000000000000aggregate project AAA_Dev is for Project_Files use ("aaa.gpr", "aaa_demos.gpr"); end AAA_Dev; alire-1.2.1/deps/aaa/alire.toml000066400000000000000000000012061426623676500162750ustar00rootroot00000000000000name = "aaa" version = "0.2.7-dev" description = "Alex's Ada Assortment (of miscellaneous utilities)" long-description = """ Alex's Ada Assortment of Utilities - Text formatting (paragraphs, tables). - Indefinite containers. - Enumeration validity/conversions of string images. - On-demand stack backtraces. - String containers and utilities. - Simple subprocess spawning. - Write-through minimal cache for objects stored in files """ authors = ["Alejandro R. Mosteo"] licenses = "LGPL-3.0-only" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mosteo"] tags = ["miscellanea", "utility"] website = "https://github.com/mosteo/aaa" alire-1.2.1/deps/aaa/config/000077500000000000000000000000001426623676500155525ustar00rootroot00000000000000alire-1.2.1/deps/aaa/config/aaa_config.ads000066400000000000000000000010371426623676500203130ustar00rootroot00000000000000-- Configuration for aaa generated by Alire pragma Restrictions (No_Elaboration_Code); pragma Style_Checks (Off); package Aaa_Config is pragma Pure; Crate_Version : constant String := "0.2.6-dev"; Crate_Name : constant String := "aaa"; Alire_Host_OS : constant String := "linux"; Alire_Host_Arch : constant String := "x86_64"; Alire_Host_Distro : constant String := "ubuntu"; type Build_Profile_Kind is (release, validation, development); Build_Profile : constant Build_Profile_Kind := release; end Aaa_Config; alire-1.2.1/deps/aaa/config/aaa_config.gpr000066400000000000000000000012711426623676500203340ustar00rootroot00000000000000-- Configuration for aaa generated by Alire abstract project Aaa_Config is Crate_Version := "0.2.6-dev"; Crate_Name := "aaa"; Alire_Host_OS := "linux"; Alire_Host_Arch := "x86_64"; Alire_Host_Distro := "ubuntu"; Ada_Compiler_Switches := External_As_List ("ADAFLAGS", " ") & ( "-O3" -- Optimize for performance ,"-gnatn" -- Enable inlining ,"-ffunction-sections" -- Separate ELF section for each function ,"-fdata-sections" -- Separate ELF section for each variable ); type Build_Profile_Kind is ("release", "validation", "development"); Build_Profile : Build_Profile_Kind := "release"; end Aaa_Config; alire-1.2.1/deps/aaa/config/aaa_config.h000066400000000000000000000006041426623676500177720ustar00rootroot00000000000000/* Configuration for aaa generated by Alire */ #ifndef AAA_CONFIG_H #define AAA_CONFIG_H #define CRATE_VERSION "0.2.6-dev" #define CRATE_NAME "aaa" #define ALIRE_HOST_OS "linux" #define ALIRE_HOST_ARCH "x86_64" #define ALIRE_HOST_DISTRO "ubuntu" #define BUILD_PROFILE_RELEASE 1 #define BUILD_PROFILE_VALIDATION 2 #define BUILD_PROFILE_DEVELOPMENT 3 #define BUILD_PROFILE 1 #endif alire-1.2.1/deps/aaa/src/000077500000000000000000000000001426623676500150745ustar00rootroot00000000000000alire-1.2.1/deps/aaa/src/aaa-ansi.adb000066400000000000000000000021251426623676500172160ustar00rootroot00000000000000with Ada.Characters.Wide_Wide_Latin_1; with Ada.Strings.UTF_Encoding.Wide_Wide_Strings; package body AAA.ANSI is package Chars renames Ada.Characters.Wide_Wide_Latin_1; ----------- -- Count -- ----------- function Count_Extra (Text : Wide_Wide_String) return Natural is Counting : Boolean := False; Extra : Natural := 0; begin for Char of Text loop if Counting then Extra := Extra + 1; if Char = 'm' then Counting := False; end if; else if Char = Chars.ESC then Counting := True; Extra := Extra + 1; end if; end if; end loop; return Extra; end Count_Extra; ------------ -- Length -- ------------ function Length (Text : Wide_Wide_String) return Natural is begin return Text'Length - Count_Extra (Text); end Length; ------------ -- Length -- ------------ function Length (Text : UTF.UTF_String) return Natural is (Length (UTF.Wide_Wide_Strings.Decode (Text))); end AAA.ANSI; alire-1.2.1/deps/aaa/src/aaa-ansi.ads000066400000000000000000000010261426623676500172360ustar00rootroot00000000000000with Ada.Strings.UTF_Encoding; package AAA.ANSI with Preelaborate is package UTF renames Ada.Strings.UTF_Encoding; function Count_Extra (Text : Wide_Wide_String) return Natural; -- Compute how many characters in Text are actually ANSI control sequences function Length (Text : Wide_Wide_String) return Natural; -- Compute the real length of Text, without embedded ANSI control sequences function Length (Text : UTF.UTF_String) return Natural; -- Same, but expects latin-1 or UTF-8 encoding end AAA.ANSI; alire-1.2.1/deps/aaa/src/aaa-caches-files.adb000066400000000000000000000027221426623676500206150ustar00rootroot00000000000000package body AAA.Caches.Files is ------------- -- Discard -- ------------- overriding procedure Discard (This : in out Cache) is begin This.Data := (Valid => False); end Discard; ------------- -- Element -- ------------- function Element (This : in out Cache; Filename : String) return Cached is use type Ada.Calendar.Time; use type Ada.Directories.File_Size; function Unchanged return Boolean is (This.Data.Valid and then This.Data.Size = Ada.Directories.Size (Filename) and then This.Data.Time = Ada.Directories.Modification_Time (Filename)); begin if This.Has_Element and then Unchanged then return This.Data.Value; else This.Data := (Valid => True, Size => Ada.Directories.Size (Filename), Time => Ada.Directories.Modification_Time (Filename), Value => Load (Filename)); return This.Data.Value; end if; end Element; --------- -- Set -- --------- procedure Set (This : in out Cache; Value : Cached; Filename : String) is begin Write (Value, Filename); This.Data := (Valid => True, Size => Ada.Directories.Size (Filename), Time => Ada.Directories.Modification_Time (Filename), Value => Load (Filename)); end Set; end AAA.Caches.Files; alire-1.2.1/deps/aaa/src/aaa-caches-files.ads000066400000000000000000000026471426623676500206440ustar00rootroot00000000000000private with Ada.Calendar; private with Ada.Directories; generic type Cached is private; with function Load (Filename : String) return Cached; with procedure Write (Data : Cached; Filename : String); package AAA.Caches.Files is type Cache is new Caches.Cache with private; overriding procedure Discard (This : in out Cache); function Element (This : in out Cache; Filename : String) return Cached; overriding function Has_Element (This : Cache) return Boolean; procedure Set (This : in out Cache; Value : Cached; Filename : String); -- Store with write-through the cached value. To ensure consistency, the -- value is immediately reloaded. Hence, if there is any inconsistency -- between load/write, at least the value used will match the one on disk. private type Cache_Data (Valid : Boolean := False) is record case Valid is when False => null; when True => Size : Ada.Directories.File_Size; Time : Ada.Calendar.Time; Value : aliased Cached; end case; end record; type Cache is new Caches.Cache with record Data : Cache_Data; end record; ----------------- -- Has_Element -- ----------------- overriding function Has_Element (This : Cache) return Boolean is (This.Data.Valid); end AAA.Caches.Files; alire-1.2.1/deps/aaa/src/aaa-caches.ads000066400000000000000000000005551426623676500175400ustar00rootroot00000000000000package AAA.Caches with Preelaborate is type Cache is limited interface; procedure Discard (This : in out Cache) is abstract with Post'Class => not This.Has_Element; -- Discard the cached value and force a reload on next use function Has_Element (This : Cache) return Boolean is abstract; -- Say if there is a cached value end AAA.Caches; alire-1.2.1/deps/aaa/src/aaa-containers-indefinite_holders.adb000066400000000000000000000033641426623676500242730ustar00rootroot00000000000000with Ada.Unchecked_Deallocation; package body AAA.Containers.Indefinite_Holders is ----------- -- Clear -- ----------- procedure Clear (This : in out Holder) is begin This.Finalize; end Clear; --------- -- Get -- --------- function Get (This : Holder) return Const_Ref_Value is (Element => This.Item); ---------- -- Hold -- ---------- procedure Hold (This : in out Holder; Elem : Held) is begin This := To_Holder (Elem); end Hold; --------------- -- To_Holder -- --------------- function To_Holder (Elem : Held) return Holder is (Ada.Finalization.Controlled with Item => new Held'(Elem)); -------------- -- Is_Empty -- -------------- function Is_Empty (This : Holder) return Boolean is (This.Item = null); --------------- -- Reference -- --------------- function Reference (This : in out Holder) return Reference_Value is (Element => This.Item); ------------ -- Adjust -- ------------ overriding procedure Adjust (This : in out Holder) is begin if This.Item /= null then This.Item := new Held'(This.Item.all); end if; end Adjust; ------------- -- Element -- ------------- function Element (This : Holder) return Held is (This.Item.all); -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Holder) is procedure Free is new Ada.Unchecked_Deallocation (Held, Held_Access); begin Free (This.Item); end Finalize; ------------------------- -- Unchecked_Reference -- ------------------------- function Unchecked_Reference (This : Holder) return access Held is (This.Item); end AAA.Containers.Indefinite_Holders; alire-1.2.1/deps/aaa/src/aaa-containers-indefinite_holders.ads000066400000000000000000000034251426623676500243120ustar00rootroot00000000000000with Ada.Finalization; generic type Held (<>) is private; package AAA.Containers.Indefinite_Holders with Preelaborate is -- Simple holder to work around GNAT holders bug type Holder is tagged private; Empty_Holder : constant Holder; procedure Clear (This : in out Holder); procedure Hold (This : in out Holder; Elem : Held); function To_Holder (Elem : Held) return Holder with Post => To_Holder'Result.Is_Valid; function Is_Empty (This : Holder) return Boolean; function Is_Valid (This : Holder) return Boolean is (not This.Is_Empty); function Element (This : Holder) return Held with Pre => This.Is_Valid; type Reference_Value (Element : access Held) is limited null record with Implicit_Dereference => Element; function Reference (This : in out Holder) return Reference_Value with Pre => This.Is_Valid; function Ref (This : in out Holder) return Reference_Value renames Reference; function Unchecked_Reference (This : Holder) return access Held with Pre => This.Is_Valid; type Const_Ref_Value (Element : access constant Held) is limited null record with Implicit_Dereference => Element; function Get (This : Holder) return Const_Ref_Value with Pre => This.Is_Valid; function Constant_Reference (This : Holder) return Const_Ref_Value renames Get; private type Held_Access is access all Held; type Holder is new Ada.Finalization.Controlled with record Item : Held_Access; end record; overriding procedure Adjust (This : in out Holder); overriding procedure Finalize (This : in out Holder); Empty_Holder : constant Holder := (Ada.Finalization.Controlled with Item => null); end AAA.Containers.Indefinite_Holders; alire-1.2.1/deps/aaa/src/aaa-containers.ads000066400000000000000000000000711426623676500204500ustar00rootroot00000000000000package AAA.Containers with Pure is end AAA.Containers; alire-1.2.1/deps/aaa/src/aaa-debug.adb000066400000000000000000000023251426623676500173540ustar00rootroot00000000000000with GNAT.IO; package body AAA.Debug is ----------- -- Image -- ----------- function Image (E : Ada.Exceptions.Exception_Occurrence) return String is use Ada.Exceptions; use ASCII; begin return "EXCEPTION NAME" & LF & Exception_Name (E) & LF & "EXCEPTION MESSAGE" & LF & Exception_Message (E) & LF & "EXCEPTION INFORMATION" & LF & Exception_Information (E); end Image; ------------------- -- Put_Exception -- ------------------- procedure Put_Exception (E : Ada.Exceptions.Exception_Occurrence; Title : String := "AAA EXCEPTION DUMP:"; Stack_Trace : Boolean := True) is use GNAT.IO; begin Put_Line (Title & ASCII.LF & Image (E)); if Stack_Trace then Put_Line (Debug.Stack_Trace); end if; end Put_Exception; ----------------- -- Stack_Trace -- ----------------- function Stack_Trace return String is Debug_Exception : exception; begin raise Debug_Exception; exception when E : Debug_Exception => return Ada.Exceptions.Exception_Information (E); end Stack_Trace; end AAA.Debug; alire-1.2.1/deps/aaa/src/aaa-debug.ads000066400000000000000000000013661426623676500174010ustar00rootroot00000000000000with Ada.Exceptions; package AAA.Debug with Preelaborate is function Image (E : Ada.Exceptions.Exception_Occurrence) return String; -- Just concatenate the exception name, message and information procedure Put_Exception (E : Ada.Exceptions.Exception_Occurrence; Title : String := "AAA EXCEPTION DUMP:"; Stack_Trace : Boolean := True); -- Print Image and optionally Stack_Trace function Stack_Trace return String; -- Return a string containing the call stack. To keep things Preelaborable, -- a fake exception is generated and the exception information retrieved. -- Hence efficacy of this will be dependent on your compilation switches. end AAA.Debug; alire-1.2.1/deps/aaa/src/aaa-directories.ads000066400000000000000000000001021426623676500206120ustar00rootroot00000000000000with AAA.Filesystem; package AAA.Directories renames Filesystem; alire-1.2.1/deps/aaa/src/aaa-enum_tools.adb000066400000000000000000000005621426623676500204530ustar00rootroot00000000000000package body AAA.Enum_Tools is -------------- -- Is_Valid -- -------------- function Is_Valid (Str : String) return Boolean is begin declare E : constant Enum := Enum'Value (Str) with Unreferenced; begin return True; end; exception when others => return False; end Is_Valid; end AAA.Enum_Tools; alire-1.2.1/deps/aaa/src/aaa-enum_tools.ads000066400000000000000000000003261426623676500204720ustar00rootroot00000000000000package AAA.Enum_Tools with Preelaborate is generic type Enum is (<>); function Is_Valid (Str : String) return Boolean; -- Check if a string can be Enum'Value'd without error. end AAA.Enum_Tools; alire-1.2.1/deps/aaa/src/aaa-filesystem.adb000066400000000000000000000233701426623676500204550ustar00rootroot00000000000000with AAA.Debug; with AAA.Strings; with Ada.Numerics.Discrete_Random; with Ada.Unchecked_Deallocation; with GNAT.OS_Lib; package body AAA.Filesystem is ------------- -- Is_File -- ------------- function Is_File (Path : String) return Boolean is (GNAT.OS_Lib.Is_Regular_File (Path)); --------------- -- Is_Folder -- --------------- function Is_Folder (Path : String) return Boolean is (GNAT.OS_Lib.Is_Directory (Path)); ------------------------ -- Backup_If_Existing -- ------------------------ procedure Backup_If_Existing (File : String; Base_Dir : String := "") is use Ada.Directories; Dst : constant String := (if Base_Dir /= "" then Compose (Base_Dir, Simple_Name (File) & ".prev") else File & ".prev"); begin if Exists (File) then if not Exists (Base_Dir) then Create_Directory (Base_Dir); end if; Copy_File (File, Dst, "mode=overwrite"); end if; end Backup_If_Existing; ---------------------- -- Ensure_Deletable -- ---------------------- procedure Ensure_Deletable (Path : String) is use Ada.Directories; use GNAT; OK : Boolean := False; Args : OS_Lib.Argument_List_Access; begin if Exists (Path) and then Kind (Path) = Directory and then OS_Lib.Directory_Separator = '\' then Args := OS_Lib.Argument_String_To_List ("-R /D /S " & Path & "\*"); OS_Lib.Spawn ("attrib", Args.all, OK); OS_Lib.Free (Args); if not OK then raise Program_Error with "failed to change attributes of " & Path; end if; end if; end Ensure_Deletable; ------------------- -- Relative_Path -- ------------------- function Relative_Path (From, Into : String) return String is package Adirs renames Ada.Directories; package OS renames GNAT.OS_Lib; Sep : constant Character := OS.Directory_Separator; begin if not OS.Is_Absolute_Path (From) or else not OS.Is_Absolute_Path (Into) then return Relative_Path (Adirs.Full_Name (From), Adirs.Full_Name (Into)); end if; -- We have absolute paths to deal with from here on -- If there is not even the first char in common, these are in different -- drives (Windows). Cannot happen in UNIX-like systems. if From (From'First) /= Into (Into'First) then return Into; end if; -- If from is not a folder, this does not make sense either if not OS.Is_Directory (From) then return Into; end if; declare use type Strings.Vector; From_Parts : Strings.Vector := Strings.Split (From, Sep); Into_Parts : Strings.Vector := Strings.Split (Into, Sep); begin -- Remove spurious final segments in case Full_Name gives "this/" if From_Parts.Last_Element = "" then From_Parts.Delete_Last; end if; if Into_Parts.Last_Element = "" then Into_Parts.Delete_Last; end if; -- Remove common prefix while not From_Parts.Is_Empty and then not Into_Parts.Is_Empty and then From_Parts.First_Element = Into_Parts.First_Element loop From_Parts.Delete_First; Into_Parts.Delete_First; end loop; if From_Parts = Into_Parts then -- They're the same return "."; else -- Now the parts are rooted at a common ancestor. We go up if -- necessary and then down. declare Result : Strings.Vector; begin -- Up for I in 1 .. From_Parts.Length loop Result.Append (".."); end loop; -- And down! Result.Append (Into_Parts); -- May be empty, it'd be OK return Result.Flatten (Sep); end; end if; end; end Relative_Path; ---------------------------- -- Remove_Folder_If_Empty -- ---------------------------- procedure Remove_Folder_If_Empty (Path : String) is use Ada.Directories; begin Ada.Directories.Delete_Directory (Path); exception when Name_Error | Use_Error => null; end Remove_Folder_If_Empty; ------------------- -- Traverse_Tree -- ------------------- procedure Traverse_Tree (Start : String; Doing : access procedure (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean); Recurse : Boolean := False) is use Ada.Directories; procedure Go_Down (Item : Directory_Entry_Type) is Stop : Boolean := False; begin if Simple_Name (Item) /= "." and then Simple_Name (Item) /= ".." then Doing (Item, Stop); if Stop then return; end if; if Recurse and then Kind (Item) = Directory then Traverse_Tree (Compose (Start, Simple_Name (Item)), Doing, Recurse); end if; end if; end Go_Down; begin Search (Start, "", (Directory => True, Ordinary_File => True, others => False), Go_Down'Access); end Traverse_Tree; -------------- -- New_Name -- -------------- function New_Name (In_Folder : String := ".") return Temp_File is subtype Valid_Character is Character range 'a' .. 'z'; package Char_Random is new Ada.Numerics.Discrete_Random (Valid_Character); Gen : Char_Random.Generator; begin return Result : Temp_File := (Ada.Finalization.Limited_Controlled with Name_Len => 12, Folder_Len => In_Folder'Length, Keep => <>, Name => "aaa-XXXX.tmp", Folder => In_Folder) do Char_Random.Reset (Gen); for I in 5 .. 8 loop Result.Name (I) := Char_Random.Random (Gen); end loop; end return; end New_Name; -------------- -- Filename -- -------------- function Filename (This : Temp_File) return String is (Ada.Directories.Compose (Ada.Directories.Full_Name (This.Folder), This.Name)); ---------- -- Keep -- ---------- procedure Keep (This : in out Temp_File) is begin This.Keep := True; end Keep; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Temp_File) is use Ada.Directories; begin if This.Keep then return; end if; -- Force writability of folder when in Windows, as some tools (e.g. git) -- that create read-only files will cause a Use_Error Ensure_Deletable (This.Filename); if Exists (This.Filename) then if Kind (This.Filename) = Ordinary_File then Delete_File (This.Filename); elsif Kind (This.Filename) = Directory then Delete_Tree (This.Filename); end if; end if; exception when E : others => Debug.Put_Exception (E); end Finalize; --------------- -- With_Name -- --------------- function With_Name (Name : String) return Temp_File is (Temp_File' (Ada.Finalization.Limited_Controlled with Name_Len => Name'Length, Name => Name, Folder_Len => 1, Folder => ".", Keep => <>)); -------------- -- REPLACER -- -------------- ------------------- -- Editable_Name -- ------------------- function Editable_Name (This : Replacer) return String is (This.Temp_Copy.Filename); --------------------- -- New_Replacement -- --------------------- function New_Replacement (File : String; Backup : Boolean := True; Backup_Dir : String := ""; Allow_No_Original : Boolean := False) return Replacer is Backup_To : constant String := (if Backup_Dir /= "" then Backup_Dir else Ada.Directories.Containing_Directory (File)); begin return This : constant Replacer := (Ada.Finalization.Limited_Controlled with Length => File'Length, Backup_Len => Backup_To'Length, Original => File, Backup => Backup, Backup_Dir => Backup_To, Temp_Copy => new Temp_File'(New_Name (In_Folder => Backup_To))) do if Is_File (File) then Ada.Directories.Copy_File (File, This.Temp_Copy.Filename); elsif not Allow_No_Original then raise Program_Error with "Invalid original file for replacement: " & File; end if; end return; end New_Replacement; ------------- -- Replace -- ------------- procedure Replace (This : in out Replacer) is begin if This.Backup then Backup_If_Existing (This.Original, This.Backup_Dir); end if; Ada.Directories.Copy_File (This.Editable_Name, This.Original); -- The temporary copy will be cleaned up by This.Temp_Copy finalization end Replace; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Replacer) is procedure Free is new Ada.Unchecked_Deallocation (Temp_File, Temp_File_Access); begin Free (This.Temp_Copy); exception when E : others => Debug.Put_Exception (E); end Finalize; end AAA.Filesystem; alire-1.2.1/deps/aaa/src/aaa-filesystem.ads000066400000000000000000000114671426623676500205020ustar00rootroot00000000000000with Ada.Directories; private with Ada.Finalization; package AAA.Filesystem is function Is_File (Path : String) return Boolean; function Is_Folder (Path : String) return Boolean; function Relative_Path (From, Into : String) return String with Pre => From'Length > 0 and then Into'Length > 0; -- Returns the shortest relative path going From --> Into. If these don't -- belong to the same drive (Windows only), the absolute path equivalent to -- Into is returned, even if Into was a relative path initially (in which -- case the current directory is used to resolve it). -- TODO/WARNING: consider whether the filesystem is case-insensitive or -- case-preserving. Currently no case transformations will be applied -- and case-sensitive will be presumed. procedure Traverse_Tree (Start : String; Doing : access procedure (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean); Recurse : Boolean := False); procedure Backup_If_Existing (File : String; Base_Dir : String := ""); -- If File exists, copy to file.prev. If Base_Dir /= "", it is instead -- copied to Base_Dir / Simple_Name (file) & ".prev" procedure Remove_Folder_If_Empty (Path : String); -- Attempt to remove a folder, but do not complain if unable (because not -- empty or not existing). -- TEMP_FILE: obtain a temporary name with optional cleanup type Temp_File (<>) is tagged limited private; -- A RAII scoped type to manage a temporary file name. -- Creates an instance with a unique file name. This does nothing on disk. -- The user is responsible for using the temp file name as they see fit. -- The file is deleted once an object of this type goes out of scope. -- If the file/folder was never created on disk nothing will happen. function New_Name (In_Folder : String := ".") return Temp_File with Pre => In_Folder /= ""; -- This finds a new random name; it does not create anything. function Filename (This : Temp_File) return String; -- The filename is a random sequence of 8 characters + ".tmp" procedure Keep (This : in out Temp_File); -- If Keep is called, the file/dir will not be erased on finalization. This -- allows creating a temporary that will be deleted in case of failure but -- kept in case of success. function With_Name (Name : String) return Temp_File; -- Allows initializing the tmp file with a desired name. -- REPLACER: Modify a file "in place" in a safe way (keeping old copy) type Replacer (<>) is tagged limited private; -- A scoped type to ensure that a file is updated and replaced without -- trouble. In case of failure, the original file remains untouched. So -- what happens is: 1) A copy to a temp file is made. 2) This file is -- modified and can be tested as the client sees fit. 3) If the new file is -- proper, the old one is renamed to .prev and the new one takes its place. function New_Replacement (File : String; Backup : Boolean := True; Backup_Dir : String := ""; Allow_No_Original : Boolean := False) return Replacer; -- Receives a file to be modified, and prepares a copy in a temporary. If -- Backup, once the replacement is performed, the original file is kept as -- ".prev". Backup_Dir is used for this ".prev" file. When backup dir is -- empty, the containing directory of File is used. If Allow_No_Original is -- True, the function will not fail when File is not a path to an existing -- file. function Editable_Name (This : Replacer) return String; -- Obtain the editable copy full name procedure Replace (This : in out Replacer); -- Replace the original file with the edited copy. If this procedure is not -- called, on going out of scope the Replacer will remove the temporary and -- the original file remains untouched. private type Temp_File (Name_Len, Folder_Len : Natural) is new Ada.Finalization.Limited_Controlled with record Keep : Boolean := False; Name : String (1 .. Name_Len); Folder : String (1 .. Folder_Len); end record; type Temp_File_Access is access Temp_File; overriding procedure Finalize (This : in out Temp_File); type Replacer (Length, Backup_Len : Natural) is new Ada.Finalization.Limited_Controlled with record Original : String (1 .. Length); Temp_Copy : Temp_File_Access; Backup : Boolean := True; Backup_Dir : String (1 .. Backup_Len); end record; overriding procedure Finalize (This : in out Replacer); end AAA.Filesystem; alire-1.2.1/deps/aaa/src/aaa-processes.adb000066400000000000000000000116371426623676500203020ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; with GNAT.Expect; package body AAA.Processes is package OS renames GNAT.OS_Lib; ------------- -- To_List -- ------------- function To_List (V : aliased Strings.Vector) return OS.Argument_List -- Reuse the strings in V for the argument list, so this V should -- outlive the result usage. is Pos : Positive := 1; begin return List : OS.Argument_List (1 .. V.Count) do for I in V.First_Index .. V.Last_Index loop List (Pos) := V.Constant_Reference (I).Element; Pos := Pos + 1; end loop; end return; end To_List; ----------------------- -- Spawn_And_Capture -- ----------------------- function Spawn_And_Capture (Output : in out Strings.Vector; Command : String; Arguments : Strings.Vector; Err_To_Out : Boolean := False) return Integer is use GNAT.OS_Lib; File : File_Descriptor; Name : String_Access; Arg_List : aliased constant Argument_List := To_List (Arguments); Outfile : File_Type; Exit_Code : Integer; ------------- -- Cleanup -- ------------- procedure Cleanup is Ok : Boolean; begin Delete_File (Name.all, Ok); if not Ok then Put_Line ("Failed to delete tmp file: " & Name.all); end if; Free (Name); end Cleanup; ----------------- -- Read_Output -- ----------------- procedure Read_Output is begin Open (Outfile, In_File, Name.all); while not End_Of_File (Outfile) loop Output.Append (Get_Line (Outfile)); end loop; Close (Outfile); end Read_Output; begin Create_Temp_Output_File (File, Name); -- Put_Line ("Spawning: " -- & Command & " " & Arguments.Flatten -- & " > " & Name.all); Spawn (Program_Name => Command, Args => Arg_List, Output_File_Descriptor => File, Return_Code => Exit_Code, Err_To_Out => Err_To_Out); Close (File); -- Can't raise Read_Output; Cleanup; return Exit_Code; end Spawn_And_Capture; ---------------- -- Get_Output -- ---------------- -- This shouldn't exist, but problems with Windows polling force us to -- do our own reimplementation. Offending call in GNAT.Expect:700 to -- Poll hangs. function Get_Output (Command_Line : Strings.Vector; Input : String := ""; Exit_Code : aliased out Integer; Err_To_Out : Boolean := False) return String is use GNAT.Expect; Arguments : aliased constant Strings.Vector := Command_Line.Tail; Output : Strings.Vector; begin if GNAT.OS_Lib.Directory_Separator = '\' then -- Windows -- For some unknown reason we get no output on Windows, no matter how -- the call to Expect is made. Falling back to plain Spawn without -- user input (!). if Input /= "" and then GNAT.OS_Lib.Directory_Separator = '\' then raise Unimplemented with "Spawning with user input is unuspported on Windows"; end if; Exit_Code := Spawn_And_Capture (Output => Output, Command => Command_Line.First_Element, Arguments => Command_Line.Tail, Err_To_Out => Err_To_Out); return Output.Flatten (ASCII.LF); else return Get_Command_Output (Command => Command_Line.First_Element, Arguments => To_List (Arguments), Input => Input, Status => Exit_Code'Access, Err_To_Out => Err_To_Out); end if; end Get_Output; --------- -- Run -- --------- function Run (Command_Line : Strings.Vector; Input : String := ""; Err_To_Out : Boolean := False; Raise_On_Error : Boolean := True) return Result is begin -- Put_Line ("RUNNING: " & Command_Line.Flatten); return R : Result do R.Output := Strings.Split (Strings.Replace (Get_Output (Command_Line => Command_Line, Input => Input, Exit_Code => R.Exit_Code, Err_To_Out => Err_To_Out), Match => ASCII.CR & ASCII.LF, Subst => (1 => ASCII.LF)), Separator => ASCII.LF); if R.Exit_Code /= 0 and then Raise_On_Error then raise Child_Error with "child exited with code " & Strings.Trim (R.Exit_Code'Image); end if; end return; end Run; end AAA.Processes; alire-1.2.1/deps/aaa/src/aaa-processes.ads000066400000000000000000000022311426623676500203110ustar00rootroot00000000000000with AAA.Strings; with GNAT.OS_Lib; package AAA.Processes is Child_Error : exception; type Result is record Exit_Code : aliased Integer; Output : Strings.Vector; end record; function Run (Command_Line : Strings.Vector; Input : String := ""; Err_To_Out : Boolean := False; Raise_On_Error : Boolean := True) return Result with Pre => Input = "" or else GNAT.OS_Lib.Directory_Separator /= '\' or else raise Unimplemented with "Spawning with user input is unuspported on Windows"; -- Run a command, giving optional Input to it, and capture its output, -- optionally including stderr output. If the child's process exit code is -- /= 0, Child_Error will be raised when Raise_On_Error. CR & LF sequences -- will be interpreted as plain LF sequences. NOTE: due to unresolved -- problems with Windows polling, on Windows Input *must* be "", and a -- temporary file will be created on the current directory during process -- spawning. (Might affect git status and the like, for example.) end AAA.Processes; alire-1.2.1/deps/aaa/src/aaa-strings.adb000066400000000000000000000334531426623676500177650ustar00rootroot00000000000000with Ada.Streams.Stream_IO; with Ada.Strings.Fixed; with Ada.Strings.Maps; with Ada.Containers.Bounded_Vectors; with GNAT.Case_Util; package body AAA.Strings is ------------ -- Append -- ------------ function Append (V : Vector; S : String) return Vector is begin return R : Vector := V do R.Append (S); end return; end Append; ------------ -- Append -- ------------ function Append (L, R : Vector) return Vector is begin return Result : Vector := L do Result.Append (R); end return; end Append; --------- -- "=" -- --------- overriding function "=" (L : Vector; R : Vector) return Boolean is begin if L.Count /= R.Count then return False; end if; for Index in L.First_Index .. L.Last_Index loop if L.Element (Index) /= R.Element (Index) then return False; end if; end loop; return True; end "="; ------------------------- -- Append_To_Last_Line -- ------------------------- procedure Append_To_Last_Line (V : in out Vector; S : String) is begin if V.Is_Empty then V.Append (S); else declare Last : constant String := V.Last_Element; begin V.Delete_Last; V.Append_Line (Last & S); end; end if; end Append_To_Last_Line; ------------------------- -- Append_To_Last_Line -- ------------------------- function Append_To_Last_Line (V : Vector; S : String) return Vector is begin return R : Vector := V do R.Append_To_Last_Line (S); end return; end Append_To_Last_Line; -------------------- -- Camel_To_Mixed -- -------------------- function Camel_To_Mixed (S : String) return String is begin for I in S'First + 1 .. S'Last loop if Ada.Characters.Handling.Is_Upper (S (I)) then return S (S'First .. I - 1) & "_" & Camel_To_Mixed (S (I .. S'Last)); end if; end loop; return S; end Camel_To_Mixed; ----------- -- Count -- ----------- function Count (V : Vector) return Natural is (Natural (Vectors.Vector (V).Length)); ------------- -- Flatten -- ------------- function Flatten (V : Vector; Separator : String := " ") return String is function Flatten (Pos : Positive; V : Vector) return String; ------------- -- Flatten -- ------------- function Flatten (Pos : Positive; V : Vector) return String is (if Pos = V.Count then V (Pos) else V (Pos) & Separator & Flatten (Pos + 1, V)); begin if V.Is_Empty then return ""; else return Flatten (1, V); end if; end Flatten; ------------- -- Flatten -- ------------- function Flatten (V : Vector; Separator : Character) return String is (V.Flatten ((1 => Separator))); ---------- -- Head -- ---------- function Head (S : String; Separator : Character) return String is begin for I in S'Range loop if S (I) = Separator then return S (S'First .. I - 1); end if; end loop; return S; end Head; ---------- -- Head -- ---------- function Head (S : String; Separator : String) return String is begin for I in S'Range loop if I + Separator'Length - 1 in S'Range and then S (I .. I + Separator'Length - 1) = Separator then return S (S'First .. I - 1); end if; end loop; return S; end Head; ------------ -- Indent -- ------------ function Indent (V : Vector; Spaces : String := " ") return Vector is begin return R : Vector do for Line of V loop R.Append (String'(Spaces & Line)); end loop; end return; end Indent; -------------- -- New_Line -- -------------- function New_Line (V : Vector) return Vector is (V.Append ("")); -------------- -- New_Line -- -------------- procedure New_Line (V : in out Vector) is begin V.Append (""); end New_Line; ------------- -- Prepend -- ------------- procedure Prepend (V : in out Vector; S : Set'Class) is begin for Str of reverse S loop V.Prepend (Str); end loop; end Prepend; ------------- -- Replace -- ------------- function Replace (Text : String; Match : String; Subst : String) return String is use Ada.Strings.Fixed; First : Natural; begin First := Index (Text, Match); if First = 0 then return Text; else return Text (Text'First .. First - 1) & Subst & Replace (Text (First + Match'Length .. Text'Last), Match, Subst); end if; end Replace; ----------- -- Split -- ----------- function Split (Text : String; Separator : Character; Side : Halves := Head; From : Halves := Head; Count : Positive := 1; Raises : Boolean := True) return String is Seen : Natural := 0; Pos : Integer := (if From = Head then Text'First else Text'Last); Inc : constant Integer := (if From = Head then 1 else -1); begin loop if Text (Pos) = Separator then Seen := Seen + 1; if Seen = Count then if Side = Head then return Text (Text'First .. Pos - 1); else return Text (Pos + 1 .. Text'Last); end if; end if; end if; Pos := Pos + Inc; exit when Pos not in Text'Range; end loop; if Raises then raise Constraint_Error with "Not enought separators found"; else return Text; end if; end Split; ------------- -- Shorten -- ------------- function Shorten (Text : String; Max_Length : Natural; Trim_Side : Halves := Head) return String is Ellipsis : constant String := "(...)"; begin if Text'Length <= Max_Length then return Text; elsif Trim_Side = Head then return Ellipsis & Ada.Strings.Fixed.Tail (Text, Max_Length - Ellipsis'Length); else return Ada.Strings.Fixed.Head (Text, Max_Length - Ellipsis'Length) & Ellipsis; end if; end Shorten; ----------- -- Split -- ----------- function Split (S : String; Separator : Character; Trim : Boolean := False) return Vector is function Do_Trim (S : String) return String is (if Trim then AAA.Strings.Trim (S) else S); Prev : Integer := S'First - 1; begin return V : Vector do for I in S'Range loop if S (I) = Separator then V.Append (Do_Trim (S (Prev + 1 .. I - 1))); Prev := I; end if; end loop; V.Append (Do_Trim (S (Prev + 1 .. S'Last))); end return; end Split; ---------- -- Tail -- ---------- function Tail (S : String; Separator : Character) return String is begin for I in S'Range loop if S (I) = Separator then return S (I + 1 .. S'Last); end if; end loop; return ""; end Tail; ---------- -- Tail -- ---------- function Tail (S : String; Separator : String) return String is begin for I in S'Range loop if I + Separator'Length - 1 in S'Range and then S (I .. I + Separator'Length - 1) = Separator then return S (I + Separator'Length .. S'Last); end if; end loop; return ""; end Tail; ---------- -- Tail -- ---------- function Tail (V : Vector; Allow_Empty : Boolean := False) return Vector is begin if V.Is_Empty then if Allow_Empty then return Empty_Vector; else raise Constraint_Error with "Cannot take tail of empty vector"; end if; end if; return Result : Vector := V do Result.Delete_First; end return; end Tail; ------------------- -- To_Mixed_Case -- ------------------- function To_Mixed_Case (S : String) return String is begin return R : String := S do GNAT.Case_Util.To_Mixed (R); -- Also change to upper characters after a dot for I in R'Range loop if I /= R'First and then R (I - 1) = '.' then R (I) := GNAT.Case_Util.To_Upper (R (I)); end if; end loop; end return; end To_Mixed_Case; --------------- -- To_Vector -- --------------- function To_Vector (S : String) return Vector is begin return V : Vector do V.Append (S); end return; end To_Vector; ---------- -- Trim -- ---------- function Trim (S : String; Target : Character := ' ') return String is (Ada.Strings.Fixed.Trim (S, Left => Ada.Strings.Maps.To_Set (Target), Right => Ada.Strings.Maps.To_Set (Target))); ------------ -- Crunch -- ------------ function Crunch (Text : String) return String is Result : String (Text'Range); Src : Natural := Text'First; Dst : Natural := Result'First; begin -- Trim initial spaces: while Src <= Text'Last and then Text (Src) = ' ' loop Src := Src + 1; end loop; -- Remove excess spaces: while Src <= Text'Last loop if Src = Text'First or else Text (Src) /= ' ' or else Text (Src - 1) /= ' ' then Result (Dst) := Text (Src); Dst := Dst + 1; end if; Src := Src + 1; end loop; return Result (Result'First .. Dst - 1); end Crunch; ----------- -- Write -- ----------- procedure Write (V : Vector; Filename : String; Separator : String := ASCII.LF & "") is use Ada.Streams.Stream_IO; F : File_Type; begin Create (F, Out_File, Filename); for Line of V loop String'Write (Stream (F), Line); String'Write (Stream (F), Separator); end loop; Close (F); exception when others => if Is_Open (F) then Close (F); end if; raise; end Write; ---------- -- Diff -- ---------- function Diff (A, B : AAA.Strings.Vector; A_Name : String := "A"; B_Name : String := "B"; Skip_Header : Boolean := False) return AAA.Strings.Vector is -- Tentative Myers diff implementation Max : constant Integer := A.Count + B.Count; type Action_Kind is (Keep, Insert, Remove); type Action is record Kind : Action_Kind; Index : Positive; end record; package Action_Vectors is new Ada.Containers.Bounded_Vectors (Positive, Action); subtype History_Vector is Action_Vectors.Vector (Ada.Containers.Count_Type (Max)); type Frontier is record X : Integer := 0; History : History_Vector; end record; V : array (-Max .. Max) of Frontier; K : Integer; X, Y : Integer := 0; Go_Down : Boolean; History : History_Vector; Result : AAA.Strings.Vector; begin if A.First_Index /= 1 then raise Program_Error; elsif B.First_Index /= 1 then raise Program_Error; end if; V (1).X := 0; Main_Loop : for D in 0 .. Max loop K := -D; while K <= D loop Go_Down := (K = -D) or else ((K /= D) and then (V (K - 1).X < V (K + 1).X)); if Go_Down then X := V (K + 1).X; History := V (K + 1).History; else X := V (K - 1).X + 1; History := V (K - 1).History; end if; Y := X - K; if Go_Down and then Y in 1 .. B.Count then History.Append (Action'(Insert, Y)); elsif X in 1 .. A.Count then History.Append (Action'(Remove, X)); end if; while X in 0 .. A.Count - 1 and then Y in 0 .. B.Count - 1 and then A.Element (X + 1) = B.Element (Y + 1) loop X := X + 1; Y := Y + 1; History.Append (Action'(Keep, X)); end loop; if X >= A.Count and then Y >= B.Count then exit Main_Loop; else V (K).X := X; V (K).History := History; end if; K := K + 2; end loop; end loop Main_Loop; if not Skip_Header then Result.Append (String'("--- " & A_Name)); Result.Append (String'("+++ " & B_Name)); end if; for Elt of History loop case Elt.Kind is when Keep => Result.Append (String'(" " & A.Element (Elt.Index))); when Remove => Result.Append (String'("- " & A.Element (Elt.Index))); when Insert => Result.Append (String'("+ " & B.Element (Elt.Index))); end case; end loop; return Result; end Diff; end AAA.Strings; alire-1.2.1/deps/aaa/src/aaa-strings.ads000066400000000000000000000167721426623676500200130ustar00rootroot00000000000000with Ada.Characters.Handling; with Ada.Containers.Indefinite_Ordered_Maps; with Ada.Containers.Indefinite_Ordered_Sets; with Ada.Containers.Indefinite_Vectors; package AAA.Strings with Preelaborate is function Camel_To_Mixed (S : String) return String; -- Converts ThisThing into This_Thing function Contains (Full : String; Sub : String) return Boolean; function Has_Prefix (Full : String; Prefix : String) return Boolean; function Has_Suffix (Full : String; Suffix : String) return Boolean; function Head (S : String; Separator : Character) return String; -- if S contains Separator, the lhs is returned. Otherwise Str is returned. function Head (S : String; Separator : String) return String; -- if S contains Separator, the lhs is returned. Otherwise Str is returned. function Tail (S : String; Separator : Character) return String; -- If S contains Separator, the rhs is returned. Otherwise "". function Tail (S : String; Separator : String) return String; -- If S contains Separator, the rhs is returned. Otherwise "". function To_Lower_Case (S : String) return String renames Ada.Characters.Handling.To_Lower; function To_Upper_Case (S : String) return String renames Ada.Characters.Handling.To_Upper; function To_Mixed_Case (S : String) return String; function Trim (S : String; Target : Character := ' ') return String; -- Remove Target at S extremes function Crunch (Text : String) return String; -- Remove consecutive spaces function Replace (Text : String; Match : String; Subst : String) return String; -- Replace every occurrence of Match in Text by Subst type Halves is (Head, Tail); function Split (Text : String; Separator : Character; Side : Halves := Head; From : Halves := Head; Count : Positive := 1; Raises : Boolean := True) return String; -- Split in two at seeing Count times the separator -- Start the search according to From, and return Side at that point -- If not enough separators are seen then raises or whole string function Shorten (Text : String; Max_Length : Natural; Trim_Side : Halves := Head) return String with Pre => Max_Length >= 5; -- Replaces the given end with "(...)" if the text is too long ---------- -- Maps -- ---------- package Maps is new Ada.Containers.Indefinite_Ordered_Maps (String, String); type Map is new Maps.Map with null record; Empty_Map : constant Map; ---------- -- Sets -- ---------- package Sets is new Ada.Containers.Indefinite_Ordered_Sets (String); type Set is new Sets.Set with null record; Empty_Set : constant Set; ------------- -- Vectors -- ------------- -- A standard vector of strings, for reuse across AAA where string arrays -- are needed. package Vectors is new Ada.Containers.Indefinite_Vectors (Positive, String); type Vector is new Vectors.Vector with null record; Empty_Vector : constant Vector; function Append (V : Vector; S : String) return Vector; -- Returns a copy of V with S appended at the end function Append (L, R : Vector) return Vector; -- Append R at the end of L. overriding function "&" (V : Vector; S : String) return Vector renames Append; overriding function "&" (L : Vector; R : Vector) return Vector renames Append; overriding function "&" (L : String; R : Vector) return Vector; overriding function "=" (L : Vector; R : Vector) return Boolean; procedure Append_Line (V : in out Vector; S : String; C : Ada.Containers.Count_Type := 1) renames Append; procedure Append_To_Last_Line (V : in out Vector; S : String); function Append_To_Last_Line (V : Vector; S : String) return Vector; -- Appends S to the last line in V. Does *not* add a new line. If V is -- empty, then a vector with a single line equal to S is returned. function Count (V : Vector) return Natural; -- FSM do I hate the Containers.Count_Type... function Flatten (V : Vector; Separator : String := " ") return String; -- Concatenate all elements function Flatten (V : Vector; Separator : Character) return String; -- Likewise, using a Character function Indent (V : Vector; Spaces : String := " ") return Vector; function New_Line (V : Vector) return Vector; -- Append an empty line to V and return it in a new vector procedure New_Line (V : in out Vector); -- Append new line to V procedure Prepend (V : in out Vector; S : Set'Class); function Split (S : String; Separator : Character; Trim : Boolean := False) return Vector; -- Split a string in substrings at Separator positions. A Separator at -- S'First or S'Last will result in an empty string also being included. -- If Trim, whitespace is removed around entries. function Tail (V : Vector; Allow_Empty : Boolean := False) return Vector with Pre => not V.Is_Empty or else Allow_Empty or else raise Constraint_Error with "Cannot take tail of empty vector"; -- Return V without its first element. If Allow_Empty, tail of an empty -- vector will be another empty vector. not overriding function To_Vector (S : String) return Vector; procedure Write (V : Vector; Filename : String; Separator : String := ASCII.LF & ""); -- Dump contents to a given file function Diff (A, B : AAA.Strings.Vector; A_Name : String := "A"; B_Name : String := "B"; Skip_Header : Boolean := False) return AAA.Strings.Vector; -- Return a vector containing a unified diff of A against B. -- -- The result contains an optional header: -- --- -- +++ private overriding function "&" (L : String; R : Vector) return Vector is (To_Vector (L) & R); function Contains (Full : String; Sub : String) return Boolean is (for some I in Full'Range => I + Sub'Length - 1 in Full'Range and then Full (I .. I + Sub'Length - 1) = Sub); Empty_Map : constant Map := (Maps.Empty_Map with null record); Empty_Set : constant Set := (Sets.Empty_Set with null record); Empty_Vector : constant Vector := (Vectors.Empty_Vector with null record); ---------------- -- Has_Prefix -- ---------------- function Has_Prefix (Full, Prefix : String) return Boolean is (Full'Length >= Prefix'Length and then Full (Full'First .. Full'First + Prefix'Length - 1) = Prefix); ---------------- -- Has_Suffix -- ---------------- function Has_Suffix (Full, Suffix : String) return Boolean is (Full'Length >= Suffix'Length and then Full (Full'Last - Suffix'Length + 1 .. Full'Last) = Suffix); end AAA.Strings; alire-1.2.1/deps/aaa/src/aaa-table_io.adb000066400000000000000000000072441426623676500200510ustar00rootroot00000000000000with AAA.ANSI; with Ada.Containers; with Ada.Strings.UTF_Encoding.Wide_Wide_Strings; with Ada.Strings.Wide_Wide_Fixed; with Ada.Strings.Wide_Wide_Unbounded; with GNAT.IO; package body AAA.Table_IO is package UTF renames Ada.Strings.UTF_Encoding; use all type Ada.Containers.Count_Type; ------------ -- Append -- ------------ procedure Append (T : in out Table; Cell : String) is begin declare Cell : constant Wide_Wide_String := UTF.Wide_Wide_Strings.Decode (Append.Cell); begin if T.Rows.Is_Empty then T.New_Row; end if; if Natural (T.Max_Widths.Length) < T.Next_Column then T.Max_Widths.Append (ANSI.Length (Cell)); else T.Max_Widths (T.Next_Column) := Natural'Max (ANSI.Length (Cell), T.Max_Widths (T.Next_Column)); end if; T.Rows (Natural (T.Rows.Length)).Append (Cell); T.Next_Column := T.Next_Column + 1; end; end Append; ------------ -- Append -- ------------ function Append (T : aliased in out Table; Cell : String) return Reference is begin T.Append (Cell); return Reference'(Table => T'Access); end Append; ------------- -- New_Row -- ------------- procedure New_Row (T : in out Table) is begin T.Next_Column := 1; T.Rows.Append (String_Vectors.Empty_Vector); end New_Row; ---------------- -- Put_Padded -- ---------------- function Prepare_Padded (T : Table; Col : Positive; Text : Wide_Wide_String; Align : Ada.Strings.Alignment) return Wide_Wide_String is Field : Wide_Wide_String (1 .. T.Max_Widths (Col) + ANSI.Count_Extra (Text)); begin Ada.Strings.Wide_Wide_Fixed.Move (Text, Field, Drop => Ada.Strings.Error, Justify => Align); return Field; end Prepare_Padded; ----------- -- Print -- ----------- procedure Print (T : Table; Separator : String := " "; Align : Alignments := (1 .. 0 => <>); Put_Line : access procedure (Line : String) := null) is use Ada.Strings.Wide_Wide_Unbounded; Wide_Separator : constant Wide_Wide_String := UTF.Wide_Wide_Strings.Decode (Separator); begin for Row of T.Rows loop declare Line : Unbounded_Wide_Wide_String; begin for I in 1 .. Natural (Row.Length) loop Append (Line, Prepare_Padded (T, I, Row (I), (if Align'Length >= I then Align (I) else Ada.Strings.Left))); if I < Natural (Row.Length) then Append (Line, Wide_Separator); else declare UTF8_Line : constant String := UTF.Wide_Wide_Strings.Encode (To_Wide_Wide_String (Line)); begin if Put_Line /= null then Put_Line (UTF8_Line); else GNAT.IO.Put_Line (UTF8_Line); end if; end; end if; end loop; end; end loop; end Print; end AAA.Table_IO; alire-1.2.1/deps/aaa/src/aaa-table_io.ads000066400000000000000000000034151426623676500200660ustar00rootroot00000000000000with Ada.Containers.Indefinite_Vectors; with Ada.Containers.Vectors; with Ada.Strings; package AAA.Table_IO with Preelaborate is -- A type to format tables according to the max length of fields. The table -- is ANSI-aware, so it will work properly for text with embedded ANSI -- control sequences. However, non-left-aligned text may not align -- properly. -- Text supplied to these tables is supposed to be ASCII or UTF-8; other -- encodings will either cause errors or break alignment. If any input -- requires UTF encoding, output will be conversely encoded. type Table is tagged private; type Reference (Table : access Table_IO.Table) is limited null record with Implicit_Dereference => Table; procedure Append (T : in out Table; Cell : String); function Append (T : aliased in out Table; Cell : String) return Reference; procedure New_Row (T : in out Table); type Alignments is array (Positive range <>) of Ada.Strings.Alignment; procedure Print (T : Table; Separator : String := " "; Align : Alignments := (1 .. 0 => <>); Put_Line : access procedure (Line : String) := null); -- Will print the table using GNAT.IO, unless Put_Line is supplied private package Natural_Vectors is new Ada.Containers.Vectors (Positive, Natural); package String_Vectors is new Ada.Containers.Indefinite_Vectors (Positive, Wide_Wide_String); subtype Row is String_Vectors.Vector; use all type Row; package Row_Vectors is new Ada.Containers.Vectors (Positive, Row); type Table is tagged record Next_Column : Positive := 1; Rows : Row_Vectors.Vector; Max_Widths : Natural_Vectors.Vector; end record; end AAA.Table_IO; alire-1.2.1/deps/aaa/src/aaa-tests.ads000066400000000000000000000000451426623676500174460ustar00rootroot00000000000000package AAA.Tests is end AAA.Tests; alire-1.2.1/deps/aaa/src/aaa-text_io.adb000066400000000000000000000146351426623676500177500ustar00rootroot00000000000000with AAA.ANSI; with AAA.Debug; with AAA.Filesystem; with Ada.Directories; with Ada.Strings.Unbounded; package body AAA.Text_IO is ------------------- -- Put_Paragraph -- ------------------- procedure Put_Paragraph (Text : String; Line_Width : Line_Widths := Default_Line_Width; Line_Prefix : String := ""; Filling : Filling_Modes := Greedy; File : Ada.Text_IO.File_Access := Ada.Text_IO.Standard_Output) is pragma Unreferenced (Filling); use Ada.Text_IO; Pos : Integer := Text'First; --------------- -- Next_Word -- --------------- function Next_Word return String is begin for I in Pos .. Text'Last loop if Text (I) = ' ' then return Text (Pos .. I - 1); elsif Text (I) = '-' then return Text (Pos .. I); end if; end loop; -- No breaker found... return Text (Pos .. Text'Last); end Next_Word; -------------- -- Put_Line -- -------------- procedure Put_Line is use Ada.Strings.Unbounded; Line : Unbounded_String; -- Doing this with fixed strings and ANSI unknown extra lengths is -- unnecessary trouble. ---------- -- Used -- ---------- function Used return Natural is (ANSI.Length (To_String (Line))); PPos : constant Integer := Pos; -- Initial Pos, to check we had some progress --------- -- Put -- --------- procedure Put (Word : String) is begin Append (Line, Word); end Put; begin -- Set prefix, if it fits if Line_Prefix'Length < Line_Width - 2 then Put (Line_Prefix); end if; -- Eat words until line is complete while Used + ANSI.Length (Next_Word) - 1 <= Line_Width loop Put (Next_Word); Pos := Pos + Next_Word'Length; exit when Used > Line_Width or else Pos > Text'Last; -- Advance on spaces if Text (Pos) = ' ' then Put (" "); Pos := Pos + 1; end if; end loop; -- Forcefully break a word if line is still empty. This won't work -- with ANSI codes... So don't have too short lines, I guess. if Pos = PPos then declare Remain : constant Positive := Line_Width - Used; -- Space for text (without counting the '-') begin Put (Text (Pos .. Pos + Remain - 1)); Pos := Pos + Remain; Put ("-"); end; end if; -- Final dump to file Put_Line (File.all, To_String (Line)); -- Eat spaces that would start the next line: while Pos <= Text'Last and then Text (Pos) = ' ' loop Pos := Pos + 1; end loop; end Put_Line; begin -- Trivial case of empty line: if Text = "" then New_Line (File.all); else -- Regular case: while Pos <= Text'Last loop Put_Line; end loop; end if; end Put_Paragraph; -------------------- -- Put_Paragraphs -- -------------------- procedure Put_Paragraphs (Text : Strings.Vector; Line_Width : Line_Widths := Default_Line_Width; Line_Prefix : String := ""; Filling : Filling_Modes := Greedy; File : Ada.Text_IO.File_Access := Ada.Text_IO.Standard_Output) is begin for Line of Text loop Put_Paragraph (Line, Line_Width, Line_Prefix, Filling, File); end loop; end Put_Paragraphs; ------------------ -- Append_Lines -- ------------------ procedure Append_Lines (File : String; Lines : Strings.Vector; Backup : Boolean := True; Backup_Dir : String := "") is F : AAA.Text_IO.File := Load (File, Backup, Backup_Dir); begin F.Lines.Append (Lines); end Append_Lines; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out File) is use Ada.Text_IO; use type Strings.Vector; File : File_Type; begin if This.Lines = This.Orig then return; end if; declare Replacer : Filesystem.Replacer := Filesystem.New_Replacement (This.Name, This.Backup, This.Backup_Dir); begin Open (File, Out_File, Replacer.Editable_Name); for Line of This.Lines loop Put_Line (File, Line); end loop; Close (File); Replacer.Replace; end; exception when E : others => Debug.Put_Exception (E); end Finalize; ----------- -- Lines -- ----------- function Lines (This : aliased in out File) return access Strings.Vector is (This.Lines'Access); ---------- -- Load -- ---------- function Load (From : String; Backup : Boolean := True; Backup_Dir : String := "") return File is use Ada.Text_IO; F : File_Type; Backup_To : constant String := (if Backup_Dir /= "" then Backup_Dir else Ada.Directories.Containing_Directory (From)); begin return This : File := (Ada.Finalization.Limited_Controlled with Length => From'Length, Backup_Len => Backup_To'Length, Name => From, Backup => Backup, Backup_Dir => Backup_To, Lines => <>, Orig => <>) do Open (F, In_File, From); while not End_Of_File (F) loop This.Orig.Append (Get_Line (F)); end loop; Close (F); This.Lines := This.Orig; end return; end Load; end AAA.Text_IO; alire-1.2.1/deps/aaa/src/aaa-text_io.ads000066400000000000000000000062141426623676500177630ustar00rootroot00000000000000private with Ada.Finalization; with Ada.Text_IO; with AAA.Strings; package AAA.Text_IO is subtype Line_Widths is Positive range 2 .. Positive'Last; -- We need to at least be able to -- w- -- r- -- i- -- t- -- e like this. Default_Line_Width : constant := 79; type Filling_Modes is (Greedy); -- Fancier modes exist, not implemented for now. procedure Put_Paragraph (Text : String; Line_Width : Line_Widths := Default_Line_Width; Line_Prefix : String := ""; Filling : Filling_Modes := Greedy; File : Ada.Text_IO.File_Access := Ada.Text_IO.Standard_Output); -- Reformat Text and write it to the given File. -- Lines will be broken at either spaces or '-'. -- If Line_Width is too short for a word or syllable, the word will be -- mercilessly broken wherever the line is completed. -- Line_Prefix is prepended to all lines, only if -- Line_Prefix'Length < Line_Width - 2. -- Caveat: at least one full line will be allocated. procedure Put_Paragraphs (Text : Strings.Vector; Line_Width : Line_Widths := Default_Line_Width; Line_Prefix : String := ""; Filling : Filling_Modes := Greedy; File : Ada.Text_IO.File_Access := Ada.Text_IO.Standard_Output); -- Call Put_Paragraph on every line of Text -- A convenience type to hold a complete text file in memory as a vector of -- lines. On destruction, changes to the contents are written back to disk. -- A backup ".prev" file is also created by default. type File (<>) is tagged limited private; function Load (From : String; -- path to file Backup : Boolean := True; Backup_Dir : String := "") return File; -- Load a text file into memory. If Backup, when saving takes place the -- original is renamed to ".prev". Backup_Dir optionally designates where -- the backup file will be moved. When backup dir is empty, the containing -- directory of File is used. function Lines (This : aliased in out File) return access Strings.Vector; procedure Append_Lines (File : String; Lines : Strings.Vector; Backup : Boolean := True; Backup_Dir : String := ""); -- Add the given lines to the end of the file. When backup dir is empty, -- the containing directory of File is used. private type File (Length, Backup_Len : Natural) is new Ada.Finalization.Limited_Controlled with record Name : String (1 .. Length); Lines : aliased Strings.Vector; -- The final contents Orig : Strings.Vector; -- The original contents Backup : Boolean := True; Backup_Dir : String (1 .. Backup_Len); end record; overriding procedure Finalize (This : in out File); end AAA.Text_IO; alire-1.2.1/deps/aaa/src/aaa-traits-containers.ads000066400000000000000000000024221426623676500217560ustar00rootroot00000000000000with Ada.Containers; generic pragma Warnings (Off); -- For the unreferenced entities type Container is private; type Element (<>) is private; with procedure Append (C : in out Container; E : Element; Count : Ada.Containers.Count_Type); type Cursor is private; with function First (C : Container) return Cursor; with function Next (Pos : Cursor) return Cursor; with function Has_Element (Pos : Cursor) return Boolean; -- type Reference_Type (E : not null access Element) is limited private; with function Reference (Col : aliased in out Container; Pos : Cursor) return not null access Element; -- type Constant_Reference_Type (E : not null access constant Element) -- is limited private; with function Constant_Reference (Col : aliased Container; Pos : Cursor) return not null access constant Element; pragma Warnings (On); package AAA.Traits.Containers with Preelaborate is -- Reuse the gist of standard containers -- The above reference types bug out during instatiations (E is not -- visible) That's the reason for the alternate Reference signatures end AAA.Traits.Containers; alire-1.2.1/deps/aaa/src/aaa-traits-types.ads000066400000000000000000000006251426623676500207600ustar00rootroot00000000000000generic type T (<>) is private; -- Some general type type D is private; -- A definite alternative for T storage with function To_Definite (V : T) return D is <>; with function To_Indefinite (V : D) return T is <>; package AAA.Traits.Types with Pure is function "+" (V : T) return D renames To_Definite; function "+" (V : D) return T renames To_Indefinite; end AAA.Traits.Types; alire-1.2.1/deps/aaa/src/aaa-traits.ads000066400000000000000000000000601426623676500176070ustar00rootroot00000000000000package AAA.Traits with Pure is end AAA.Traits; alire-1.2.1/deps/aaa/src/aaa.ads000066400000000000000000000001021426623676500163000ustar00rootroot00000000000000package AAA with Pure is Unimplemented : exception; end AAA; alire-1.2.1/deps/aaa/src/demos/000077500000000000000000000000001426623676500162035ustar00rootroot00000000000000alire-1.2.1/deps/aaa/src/demos/aaa-demo-misc.adb000066400000000000000000000000751426623676500212520ustar00rootroot00000000000000procedure AAA.Demo.Misc is begin null; end AAA.Demo.Misc; alire-1.2.1/deps/aaa/src/demos/aaa-demo.ads000066400000000000000000000000641426623676500203400ustar00rootroot00000000000000package AAA.Demo with Preelaborate is end AAA.Demo; alire-1.2.1/deps/aaa/tests/000077500000000000000000000000001426623676500154475ustar00rootroot00000000000000alire-1.2.1/deps/aaa/tests/.gitignore000066400000000000000000000000351426623676500174350ustar00rootroot00000000000000/obj/ /bin/ /alire/ /config/ alire-1.2.1/deps/aaa/tests/alire.toml000066400000000000000000000002721426623676500174410ustar00rootroot00000000000000name = "tests" description = "" version = "0.0.0" executables = ["tests"] [configuration] disabled = false [[depends-on]] aaa = "*" aunit = "^21" [[pins]] aaa = { path='../../aaa' } alire-1.2.1/deps/aaa/tests/src/000077500000000000000000000000001426623676500162365ustar00rootroot00000000000000alire-1.2.1/deps/aaa/tests/src/test_cases-strings-vector.adb000066400000000000000000000077011426623676500240370ustar00rootroot00000000000000with AUnit.Assertions; use AUnit.Assertions; with AAA.Strings; use AAA.Strings; package body Test_Cases.Strings.Vector is -------------------- -- Check_Equality -- -------------------- procedure Check_Equality (Unused : in out Null_Fixture) is A : constant AAA.Strings.Vector := Empty_Vector.Append ("A").Append("B").Append ("C"); B : constant AAA.Strings.Vector := Empty_Vector.Append ("A").Append("B").Append ("C").Append ("D"); C : constant AAA.Strings.Vector := Empty_Vector.Append ("B").Append ("C"); D : constant AAA.Strings.Vector := Empty_Vector.Append ("A").Append("B").Append ("C"); begin Assert (Empty_Vector = Empty_Vector, "Empty_Vector = Empty_Vector"); Assert (A /= Empty_Vector, "A /= Empty_Vector"); Assert (B /= Empty_Vector, "B /= Empty_Vector"); Assert (C /= Empty_Vector, "C /= Empty_Vector"); Assert (D /= Empty_Vector, "D /= Empty_Vector"); Assert (A = A, "A = A"); Assert (B = B, "B = B"); Assert (C = C, "C = C"); Assert (D = D, "D = D"); Assert (A /= B, "A /= B"); Assert (B /= A, "B /= A"); Assert (A /= C, "A /= C"); Assert (C /= A, "C /= A"); Assert (B /= C, "B /= C"); Assert (C /= B, "C /= B"); Assert (A = D, "A = D"); end Check_Equality; ---------------- -- Check_Diff -- ---------------- procedure Check_Diff (Unused : in out Null_Fixture) is procedure Check (V1, V2, Expected : AAA.Strings.Vector; Skip_Header : Boolean := True) is Result : constant AAA.Strings.Vector := Diff (V1, V2, Skip_Header => Skip_Header); begin if Result /= Expected then Assert (False, "Diff (V1, V2): " & ASCII.LF & "V1:" & ASCII.LF & V1.Flatten (ASCII.LF) & ASCII.LF & "V2:" & ASCII.LF & V2.Flatten (ASCII.LF) & ASCII.LF & "Expected:" & ASCII.LF & Expected.Flatten (ASCII.LF) & ASCII.LF & "Actual:" & ASCII.LF & Result.Flatten (ASCII.LF)); end if; end Check; A : constant AAA.Strings.Vector := Empty_Vector.Append ("1").Append ("2").Append ("3"); B : constant AAA.Strings.Vector := Empty_Vector.Append ("1").Append("2").Append ("3").Append ("4"); C : constant AAA.Strings.Vector := Empty_Vector.Append ("2").Append ("3"); D : constant AAA.Strings.Vector := Empty_Vector.Append ("5").Append("6").Append ("7"); begin Check (A, A, Empty_Vector .Append ("--- A") .Append ("+++ B") .Append (" 1") .Append (" 2") .Append (" 3"), Skip_Header => False ); Check (A, A, Empty_Vector .Append (" 1") .Append (" 2") .Append (" 3")); Check (A, B, Empty_Vector .Append (" 1") .Append (" 2") .Append (" 3") .Append ("+ 4") ); Check (B, A, Empty_Vector .Append (" 1") .Append (" 2") .Append (" 3") .Append ("- 4") ); Check (B, C, Empty_Vector .Append ("- 1") .Append (" 2") .Append (" 3") .Append ("- 4") ); Check (A, D, Empty_Vector .Append ("- 1") .Append ("- 2") .Append ("- 3") .Append ("+ 5") .Append ("+ 6") .Append ("+ 7") ); end Check_Diff; begin Suite.Add_Test (Null_Caller.Create ("Strings.Vector.Equality", Check_Equality'Access)); Suite.Add_Test (Null_Caller.Create ("Strings.Vector.Diff", Check_Diff'Access)); end Test_Cases.Strings.Vector; alire-1.2.1/deps/aaa/tests/src/test_cases-strings-vector.ads000066400000000000000000000001371426623676500240540ustar00rootroot00000000000000package Test_Cases.Strings.Vector is pragma Elaborate_Body; end Test_Cases.Strings.Vector; alire-1.2.1/deps/aaa/tests/src/test_cases-strings.ads000066400000000000000000000000661426623676500225550ustar00rootroot00000000000000package Test_Cases.Strings is end Test_Cases.Strings; alire-1.2.1/deps/aaa/tests/src/test_cases.adb000066400000000000000000000002761426623676500210500ustar00rootroot00000000000000package body Test_Cases is --------------- -- Get_Suite -- --------------- function Get_Suite return AUnit.Test_Suites.Access_Test_Suite is (Suite'Access); end Test_Cases; alire-1.2.1/deps/aaa/tests/src/test_cases.ads000066400000000000000000000006221426623676500210640ustar00rootroot00000000000000with AUnit.Test_Suites; private with AUnit.Test_Fixtures; private with AUnit.Test_Caller; package Test_Cases is function Get_Suite return AUnit.Test_Suites.Access_Test_Suite; private type Null_Fixture is new AUnit.Test_Fixtures.Test_Fixture with null record; package Null_Caller is new AUnit.Test_Caller (Null_Fixture); Suite : aliased AUnit.Test_Suites.Test_Suite; end Test_Cases; alire-1.2.1/deps/aaa/tests/src/tests.adb000066400000000000000000000011711426623676500200500ustar00rootroot00000000000000with AUnit; use AUnit; with AUnit.Run; with AUnit.Reporter.Text; with GNAT.OS_Lib; with Test_Cases; with Test_Cases.Strings; with Test_Cases.Strings.Vector; procedure Tests is function Runner is new AUnit.Run.Test_Runner_With_Status (Test_Cases.Get_Suite); Reporter : AUnit.Reporter.Text.Text_Reporter; begin Reporter.Set_Use_ANSI_Colors (True); if Runner (Reporter, (Global_Timer => True, Test_Case_Timer => True, Report_Successes => True, others => <>)) /= AUnit.Success then GNAT.OS_Lib.OS_Exit (1); end if; end Tests; alire-1.2.1/deps/aaa/tests/tests.gpr000066400000000000000000000051001426623676500173170ustar00rootroot00000000000000with "config/tests_config.gpr"; project Tests is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Exec_Dir use "bin"; for Main use ("tests.adb"); type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("TESTS_COMPILE_CHECKS", "disabled"); Runtime_Checks : Enabled_Kind := External ("TESTS_RUNTIME_CHECKS", "disabled"); Style_Checks : Enabled_Kind := External ("TESTS_STYLE_CHECKS", "disabled"); Contracts_Checks : Enabled_Kind := External ("TESTS_CONTRACTS", "disabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("TESTS_BUILD_MODE", "optimize"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Suppress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-d", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnatyO"); -- Overriding subprograms explicitly marked as such when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => null; end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnatw.X", -- Disable warnings for No_Exception_Propagation "-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Tests; pax_global_header00006660000000000000000000000064141164263470014522gustar00rootroot0000000000000052 comment=2a671ffb1039a036f2bb68bdc88afc8d3dc68c10 alire-1.2.1/deps/ada-toml/000077500000000000000000000000001411642634700152505ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/.github/000077500000000000000000000000001411642634700166105ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/.github/workflows/000077500000000000000000000000001411642634700206455ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/.github/workflows/main.yml000066400000000000000000000012621411642634700223150ustar00rootroot00000000000000name: Build and test on: [pull_request, push] jobs: build-n-test: name: Build and test runs-on: ubuntu-latest steps: - name: Checkout ada-toml uses: actions/checkout@v1 - name: Install GNAT Community 2020 uses: ada-actions/toolchain@ce2020 with: distrib: community - name: Build ada-toml run: gprbuild -Pada_toml -p -j0 - name: Build test programs run: gprbuild -Pcheckers -p -j0 - name: Install Python 3.x uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install e3-testsuite run: pip install e3-testsuite - name: Run the testsuite run: ./run-tests.py alire-1.2.1/deps/ada-toml/.gitignore000066400000000000000000000001631411642634700172400ustar00rootroot00000000000000lib obj obj-checkers out tmp tests/burntsushi-toml-test/ tests/iarna-toml-spec-tests/ toml-spec-tests/ toml-test/ alire-1.2.1/deps/ada-toml/CONTRIBUTING.rst000066400000000000000000000030131411642634700177060ustar00rootroot00000000000000Contributing to ada-toml ======================== Everyone is welcome to contribute to this project, provided that the following rules are respected. Where/how? ---------- Please report bugs and start any discussions about the project on `GitHub issues `_. If you report bug, make sure to provide enough information so that the bug can be investigated: for instance, provide the TOML file that triggers a parsing bug, or a compileable and executable set of sources for a memory corruption bug. If you want to submit patches, please open a pull request. `This blog post `_. provides nice guidelines for such contributions. Coding style ------------ This project follows `GNAT's coding style `_. Please use it when sending patches. Documentation ------------- Given how basic the API for ada-toml is right now, there is no standalone user's guide. Instead, care is taken to make the public API (``toml.ads``, ``toml-file_io.ads``, etc.) as much self-documented as possible, and a short tutorial is present in the `project README `_. Note that non trivial parts of the implementation, such as the parser, are required to be well self-documented. Licensing --------- ``ada-toml`` is distributed under the `3-Clause BSD License `_. When sending patches to ada-toml, you agree that your contributions will be licensed under that license. alire-1.2.1/deps/ada-toml/LICENSE000066400000000000000000000030021411642634700162500ustar00rootroot00000000000000Copyright (C) 2019, AdaCore Pierre-Marie de Rodat All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. alire-1.2.1/deps/ada-toml/Makefile000066400000000000000000000013601411642634700167100ustar00rootroot00000000000000prefix = /usr DESTDIR = $(prefix) LIBRARY_TYPES = static static-pic relocatable BUILD_MODE = prod PROCESSORS = 0 all: build build: build-static build-static-pic build-relocatable build-%: gprbuild -Pada_toml \ -XBUILD_MODE=$(BUILD_MODE) \ -XLIBRARY_TYPE=$* \ -p -j$(PROCESSORS) install: install-static install-static-pic install-relocatable install-%: build-% gprinstall -Pada_toml \ -XBUILD_MODE=$(BUILD_MODE) \ -XLIBRARY_TYPE=$* \ --sources-subdir=include/ada-toml \ --prefix="$(DESTDIR)" \ --build-name=$* \ --build-var=LIBRARY_TYPE \ --build-var=ADA_TOML_LIBRARY_TYPE \ -p clean: clean-static clean-static-pic clean-relocatable clean-%: gprclean -Pada_toml \ -XBUILD_MODE=$(BUILD_MODE) \ -XLIBRARY_TYPE=$* \ -p alire-1.2.1/deps/ada-toml/README.rst000066400000000000000000000073711411642634700167470ustar00rootroot00000000000000ada-toml: TOML parser for Ada ============================= ``ada-toml`` is a pure Ada library for parsing and creating `TOML `_ documents. It conforms to the `version 1.0.0 `_ of the format standard. Build and install ----------------- With an Ada 2012 compiler and GPRbuild, building and installing the library is as simple as running: .. code-block:: sh $ make $ sudo make install If you don't want to install in ``/usr``, you can replace the last command with: .. code-block:: sh $ sudo make install prefix=/where/to/install Note that the ``Makefile`` is just a wrapper around ``gprbuild`` and ``gprinstall`` to make it easy for users and packagers. You can also run them manually: .. code-block:: sh gprbuild -Pada_toml.gpr -p This will build in debug mode and produce a static library. In order to build in production mode, add ``-XBUILD_MODE=prod``, and to build a dynamic library, add ``-XLIBRARY_TYPE=static``. Installation to ``$PREFIX`` is simply done using GPRinstall: .. code-block:: sh gprinstall -Pada_toml.gpr --prefix=$PREFIX See `TESTING.rst `_ to run the testsuite. Quick tutorial -------------- All basic types and subprograms are in the ``TOML`` package. All "nodes" in a TOML documents are materialized using the ``TOML.TOML_Value`` type. Since TOML values make up a tree, this type has reference semantics. This means that modifying a TOML node does not modify the corresponding ``TOML_Value`` value itself, but rather the TOML value that is referenced. Parsing a TOML file is as easy as using the ``TOML.File_IO.Load_File`` function: .. code-block:: ada declare Result : constant TOML.Read_Result := TOML.File_IO.Load_File ("config.toml"); begin if Result.Success then Ada.Text_IO.Put_Line ("config.toml loaded with success!"); else Ada.Text_IO.Put_Line ("error while loading config.toml:"); Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (Result.Message)); end if; end; Each TOML value has kind, defining which data it contains (a boolean, an integer, a string, a table, ...). To each kind, one or several primitives are associated to let one process the underlying data: .. code-block:: ada case Result.Kind is when TOML.TOML_Boolean => Ada.Text_IO.Put_Line ("Boolean: " & Result.As_Boolean'Image); when TOML.TOML_Integer => Ada.Text_IO.Put_Line ("Boolean: " & Result.As_Integer'Image); when TOML.TOML_String => Ada.Text_IO.Put_Line ("Boolean: " & Result.As_String); when TOML.TOML_Array => Ada.Text_IO.Put_Line ("Array of " & Result.Length & " elements"); when others => null; end case; There are also primitives to build TOML values: .. code-block:: ada declare Bool : constant TOML.TOML_Value := TOML.Create_Boolean (False); Int : constant TOML.TOML_Value := TOML.Create_Integer (10); Str : constant TOML.TOML_Value := TOML.Create_String ("Hello, world"); Table : constant TOML.TOML_Value := TOML.Create_Table; begin Table.Set ("bool_field", Bool); Table.Set ("int_field", Int); Table.Set ("str_field", Str); end; And finally one can turn a tree of TOML nodes back in text form: .. code-block:: ada Ada.Text_IO.Put_Line ("TOML document:"); Ada.Text_IO.Put_Line (Table.Dump_As_String); Contributing ------------ The development of ``ada-toml`` happens on `GitHub `_. Everyone is welcome to contribute to this project: please read our `contribution rules `_ if you consider doing so. alire-1.2.1/deps/ada-toml/TESTING.rst000066400000000000000000000027231411642634700171230ustar00rootroot00000000000000Running ada-toml's testsuite ============================ Running the testsuite requires: * A Python interpreter and the `e3-testsuite `_ library (for the testsuite framework). See the Python setup section below for a quick guide. Make sure to build the library and the checkers first: .. code-block:: sh $ gprbuild -Pada_toml -p $ gprbuild -Pcheckers -p And then execute the ``run-tests.py`` script: .. code-block:: sh $ ./run-tests.py This script accept several arguments (see ``--help``). The most useful ones are: * ``-j`` (for instance ``-j8``) to run tests in parallel; * ``-E`` to show logs in case of test failures. When the testsuite finishes, various logs can be found in the ``out/new`` directory. Python setup ------------ The first step is to install a Python2 interpreter and ``virtualenv``. For instance, on Debian-based GNU/Linux distributions, you just have to install the ``python-virtualenv`` package. You can then run the following commands: .. code-block:: sh # Create a virtualenv (prefix to install packages). The exact command varies # from one Linux distribution to another: virtualenv, virtualenv2, # virtualenv-2.7, ... $ virtualenv2 my-virtual-env # Update your environment to use it $ source my-virtual-env/bin/activate # Install e3-testsuite and all its dependencies $ pip install e3-testsuite # You should now be able to run the testsuite: $ ./run-tests.py alire-1.2.1/deps/ada-toml/ada_toml.gpr000066400000000000000000000015401411642634700175420ustar00rootroot00000000000000library project Ada_TOML is type Any_Build_Mode is ("dev", "prod"); Build_Mode : Any_Build_Mode := external("ADA_TOML_BUILD_MODE", "dev"); type Any_Library_Type is ("static", "relocatable", "static-pic"); Library_Type : Any_Library_Type := external("LIBRARY_TYPE", "static"); Subdir := Library_Type & "/" & Build_Mode; for Languages use ("Ada"); for Source_Dirs use ("src"); for Object_Dir use "obj/" & Subdir; for Library_Name use "ada_toml"; for Library_Kind use Library_Type; for Library_Dir use "lib/" & Subdir; Ada_Switches := (); case Build_Mode is when "dev" => Ada_Switches := ("-g", "-O0", "-gnatwae", "-gnata"); when "prod" => Ada_Switches := ("-g", "-O2"); end case; package Compiler is for Default_Switches ("Ada") use Ada_Switches; end Compiler; end Ada_TOML; alire-1.2.1/deps/ada-toml/checkers.gpr000066400000000000000000000004061411642634700175510ustar00rootroot00000000000000with "ada_toml"; with "gnatcoll"; project Checkers is for Source_Dirs use ("src-checkers"); for Object_Dir use "obj-checkers"; for Main use ("ada_toml_decode.adb", "ada_toml_encode.adb"); package Compiler renames Ada_TOML.Compiler; end Checkers; alire-1.2.1/deps/ada-toml/run-tests.py000077500000000000000000000345521411642634700176020ustar00rootroot00000000000000#! /usr/bin/env python """ e3.testsuite-based testsuite for Ada_TOML. Just execute this script as a main to run the testsuite. """ from __future__ import absolute_import, print_function import difflib import json import os.path import pprint import subprocess import sys from e3.fs import sync_tree from e3.os.process import Run from e3.testsuite import Testsuite from e3.testsuite.driver.classic import ( ClassicTestDriver, TestAbortWithError, TestAbortWithFailure) from e3.testsuite.result import Log, binary_repr class TestDriver(ClassicTestDriver): """ Common code for test drivers. """ def fail_if_diff(self, error_label, expected, actual, expected_file, actual_file): """ Shortcut to stop the test with a failure if "expected" and "actual" are different. :param str error_label: Label to include in the log in case of non-empty diff. :param list[str] expected: List of expected lines. :param list[str] actual: List of actual lines. :param str expected_file: Name of the file for expected lines. This is for display purposes only: the file name does not need to exist. :param str actual_file: Like "expected_file", but for actual lines. """ diff = list(difflib.unified_diff( a=expected, b=actual, fromfile=expected_file, tofile=actual_file, lineterm='')) if diff: self.result.expected = Log('\n'.join(expected)) self.result.out = Log('\n'.join(actual)) self.result.diff = Log('\n'.join(diff)) self.result.log += 'Diff:\n{}\n'.format(self.result.diff.log) raise TestAbortWithFailure(error_label) class DecoderTestDriver(TestDriver): """ Test driver to run the "ada_toml_decode" program. This test driver runs the "ada_toml_decode" program on the test-provided "input.toml" input file and checks that its output is equivalent to the "output" entry in the test.yaml file. If the test.yaml file contains an "error" entry, expect that "ada_toml_decode" exits with a non-zero status code. If "error" is not True, it must be a string: this checks that t it emits the provided error message. """ decoder_program = 'obj-checkers/ada_toml_decode' encoder_program = 'obj-checkers/ada_toml_encode' input_file = 'input.toml' def _run_subprocess(self, args, input_file): self.result.log += "Running: {}\n".format(" ".join(args)) result = subprocess.run( args, stdin=input_file, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) self.result.log += "Status code: {}\n".format(result.returncode) try: result.decoded_stdout = result.stdout.decode('utf-8') except UnicodeDecodeError as exc: self.result.log += "Output:\n{}\n".format( binary_repr(result.stdout)) raise TestAbortWithFailure( "Cannot decode UTF-8 output: {}".format(exc)) self.result.log += "Output:\n{}\n".format(result.decoded_stdout) return result def _run_decoder(self, filename): with open(filename, 'rb') as f: return self._run_subprocess( [os.path.join(self.env.root_dir, self.decoder_program)], f, ) def _run_encoder(self, filename): with open(filename, 'rb') as f: return self._run_subprocess( [os.path.join(self.env.root_dir, self.encoder_program)], f, ) def fail_if_json_mismatch( self, error_label, expected, actual, expected_file, actual_file ): """ Compare two JSON dumps and stop the test with a failure if "a" and "b" don't match. See "fail_if_diff" for arguments semantic. The only difference is that expected and actual are JSON objects. """ def canonicalize(value): if isinstance(value, list): return {'type': 'array', 'value': value} elif isinstance(value, dict) and set(value) != {'type', 'value'}: return {'type': 'dict', 'value': value} else: return value def is_valid(value): if ( not isinstance(value, dict) or set(value) != {'type', 'value'} ): return False t, v = value['type'], value['value'] return ( (t == 'dict' and isinstance(v, dict)) or (t == 'array' and isinstance(v, list)) or (t in ('string', 'float', 'integer', 'bool', 'datetime', 'datetime-local', 'date-local', 'time-local') and isinstance(v, str)) ) def helper(path, expected, actual): path_label = 'root' if path is None else path path_prefix = path or '' expected = canonicalize(expected) actual = canonicalize(actual) if not is_valid(expected): raise TestAbortWithError( "expected:{}: invalid object description" .format(path_label) ) if not is_valid(actual): raise TestAbortWithFailure( "actual:{}: invalid object description".format(path_label) ) def error(label): self.fail_if_diff( '{}: {}'.format(path_label, label), pprint.pformat(expected).splitlines(), pprint.pformat(actual).splitlines(), expected_file, actual_file ) t = expected['type'] exp_v = expected['value'] act_v = actual['value'] if t != actual['type']: error('type mismatch') elif t == 'dict': # First check keys equivalence, then check the inner values if set(exp_v) != set(act_v): error('unexpected dict keys') for k in sorted(exp_v): helper('{}[{}]'.format(path_label, repr(k)), exp_v[k], act_v[k]) elif t == 'array': # First check array length, then check the inner values if len(exp_v) != len(act_v): error('unexpected array length') for i, (e, a) in enumerate(zip(exp_v, act_v)): helper('{}[{}]'.format(path_label, i), e, a) elif t == 'float': # First, check "special values" if ( # The standard isn't very clear about the semantics of the # various NaN's, so accept when "nan" is expected whereas # while ada_toml writes "-nan" (it happens in the # BurntSushi testsuite). (exp_v == 'nan' and act_v not in ('nan', '+nan', '-nan')) or (exp_v == '+nan' and act_v not in ('nan', '+nan')) or (exp_v == '-nan' and act_v != '-nan') or (exp_v in ('inf', '+inf') and act_v not in ('inf', '+inf')) or (exp_v == '-inf' and act_v != '-inf') ): error('value mismatch') # We cannot expect exact string representation matches for # floats. Just try to make sure both designated values are # "almost equal": check the precision for 10 decimals # (arbitrary, but deemed good enough for now). e = float(exp_v) a = float(act_v) abs_e = abs(e) abs_a = abs(a) epsilon = max(abs_a, abs_e) / 10**10 if a < e - epsilon or a > e + epsilon: error('value mismatch') elif t in ("datetime", "datetime-local", "time-local"): # Mandatory precision for the time part is millisecond: # truncate it so that we don't check further. def truncate_sub_second(value): if "." in value: prefix, sub_second = value.split(".") return f"{prefix}.{sub_second[:3]}" return value exp_v = truncate_sub_second(exp_v) act_v = truncate_sub_second(act_v) if exp_v != act_v: error("value mismatch") elif exp_v != act_v: error('value mismatch') helper(None, expected, actual) def run(self): # Get the expected JSON document, or the expected error message expected_error = None try: expected_json = self.test_env['output'] except KeyError: expected_json = None expected_error = self.test_env['error'] # Run the decoder with the TOML content on the standard input p = self._run_decoder(self.working_dir(self.input_file)) # If we expected an error, make sure we have the expected one if expected_error: out = p.stdout.decode('utf-8') if p.returncode == 0: raise TestAbortWithFailure( 'Error expected, but parsing succeeded') elif ( expected_error is not True and out.strip() != expected_error ): raise TestAbortWithFailure('Unexpected error') else: return # Otherwise, make sure the decoder succeeded and produced the expected # result. if p.returncode != 0: raise TestAbortWithFailure( 'Decoder exitted with error status ({})'.format(p.returncode)) json_text_output = p.decoded_stdout try: p_output_json = json.loads(json_text_output) except (UnicodeDecodeError, ValueError) as exc: raise TestAbortWithFailure('Cannot parse the output JSON document') self.fail_if_json_mismatch( 'Unexpected JSON output for the decoder', expected_json, p_output_json, 'expected output', 'decode output', ) # Now, try to reformat a TOML document from the JSON output and make # sure it produces something that the decoder can re-parse the same # way. # Put the JSON input in a file (to ease post-mortem analysis) input_json_file = self.working_dir('input.json') with open(input_json_file, 'wb') as f: f.write(p.stdout) # Run the encoder on it p = self._run_encoder(input_json_file) if p.returncode != 0: raise TestAbortWithFailure('Encoder failed: {}'.format(p.stdout)) # Put the resulting TOML document in a file input_toml_file = self.working_dir('second-input.toml') with open(input_toml_file, 'wb') as f: f.write(p.stdout) # Run the decoder on it p = self._run_decoder(input_toml_file) if p.returncode != 0: raise TestAbortWithFailure( 'Second decoder exitted with error status ({})' .format(p.returncode) ) try: new_json_text_output = p.decoded_stdout except UnicodeDecodeError as exc: raise TestAbortWithFailure( 'Cannot decode the output JSON document: {}'.format(exc)) if json_text_output != new_json_text_output: self.fail_if_diff('Unexpected second decoder output', p.out.splitlines(), json_text_output.splitlines(), 'second decoder output', 'first decoder output') class RunProgramTestDriver(TestDriver): """ Test driver to build and run a program that uses the Ada_TOML project. This test driver builds the test-provided "main.adb" program and then run it, checking that its status code is 0 and that its output matches the content of the test-provided "test.out" file. """ main_file = 'main.adb' expected_output_file = 'test.out' def run(self): # Create a project file to build the test program and build it project_file = self.working_dir('p.gpr') with open(project_file, 'w') as f: f.write(""" with "ada_toml"; project P is for Main use ("main.adb"); for Object_Dir use "obj"; package Compiler is for Default_Switches ("Ada") use ("-g"); end Compiler; end P; """) self.shell(['gprbuild', '-P', project_file, '-p']) # Run the test program p = self.shell(['obj/main']) # Check that its output matches expectations with open(self.test_dir(self.expected_output_file), 'r') as f: expected_output = f.read().splitlines() p_output = p.out.splitlines() self.fail_if_diff( 'Unexpected test program output', p.out.splitlines(), expected_output, '{} output'.format(self.main_file), self.expected_output_file) class ADATomlTestsuite(Testsuite): tests_subdir = 'tests' test_driver_map = {'decoder': DecoderTestDriver, 'run-program': RunProgramTestDriver} @property def default_driver(self): return 'decoder' def add_options(self, parser): parser.add_argument( '--no-auto-path', action='store_true', help='Do not automatically add this repository to' ' GPR_PROJECT_PATH. Adding it is the default for developer' ' convenience.') def set_up(self): if not self.main.args.no_auto_path: old_value = os.environ.get('GPR_PROJECT_PATH', '') if old_value: new_value = '{}{}{}'.format(self.root_dir, os.path.pathsep, old_value) else: new_value = self.root_dir os.environ['GPR_PROJECT_PATH'] = new_value if __name__ == '__main__': # Some test YAML documents create big recursions in the YAML parser sys.setrecursionlimit(10000) suite = ADATomlTestsuite() sys.exit(suite.testsuite_main()) alire-1.2.1/deps/ada-toml/src-checkers/000077500000000000000000000000001411642634700176245ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/src-checkers/ada_toml_decode.adb000066400000000000000000000264271411642634700233720ustar00rootroot00000000000000-- Test program. Read bytes on the standard input as a TOML document. -- -- If it's a valid TOML document, parse it and emit on the standard output a -- JSON representation of it. -- -- If it's not a valid TOML document, print an error message on the standard -- output. with Ada.Command_Line; with Ada.Strings.UTF_Encoding.Wide_Wide_Strings; with Ada.Strings.Unbounded; with Ada.Text_IO; with Interfaces; with TOML; with TOML.Generic_Parse; procedure Ada_TOML_Decode is use type TOML.Any_Value_Kind; package Cmd renames Ada.Command_Line; package IO renames Ada.Text_IO; type Stdin_Stream is null record; procedure Get (Stream : in out Stdin_Stream; EOF : out Boolean; Byte : out Character); -- Callback for TOML.Generic_Parse subtype Wrapped_Kind is TOML.Any_Value_Kind with Static_Predicate => Wrapped_Kind in TOML.TOML_Array .. TOML.TOML_Boolean | TOML.TOML_Offset_Datetime | TOML.TOML_Local_Datetime | TOML.TOML_Local_Date | TOML.TOML_Local_Time | TOML.TOML_Float; function Kind_Name (Kind : Wrapped_Kind) return String; -- Return the name expected in the JSON output for the given kind function Strip_Number (Image : String) return String; -- If the first character in Image is a space, return the rest of Image function Pad_Number (Image : String; Digit_Count : Positive) return String; -- Return Strip_Number (Image) left-padded with 0 so that the result is -- Digit_Count long. procedure Dump_String (Value : TOML.Unbounded_UTF8_String); -- Dump the given string as a JSON string literal procedure Dump_Array (Value : TOML.TOML_Value) with Pre => TOML."=" (Value.Kind, TOML.TOML_Array); -- Dump the given TOML array as a JSON array procedure Dump (Value : TOML.TOML_Value); -- Dump the given TOML value using the expected JSON output format. -- Toplevel must be true for the root table, root table children and table -- arrays. --------------- -- Kind_Name -- --------------- function Kind_Name (Kind : Wrapped_Kind) return String is begin return (case Kind is when TOML.TOML_Array => "array", when TOML.TOML_String => "string", when TOML.TOML_Integer => "integer", when TOML.TOML_Float => "float", when TOML.TOML_Boolean => "bool", when TOML.TOML_Offset_Datetime => "datetime", when TOML.TOML_Local_Datetime => "datetime-local", when TOML.TOML_Local_Date => "date-local", when TOML.TOML_Local_Time => "time-local"); end Kind_Name; ------------------ -- Strip_Number -- ------------------ function Strip_Number (Image : String) return String is begin if Image'Length > 0 and then Image (Image'First) = ' ' then return Image (Image'First + 1 .. Image'Last); else return Image; end if; end Strip_Number; ---------------- -- Pad_Number -- ---------------- function Pad_Number (Image : String; Digit_Count : Positive) return String is Result : constant String := Strip_Number (Image); begin pragma Assert (Result'Length <= Digit_Count); return (Result'Length + 1 .. Digit_Count => '0') & Result; end Pad_Number; ----------------- -- Dump_String -- ----------------- procedure Dump_String (Value : TOML.Unbounded_UTF8_String) is use Ada.Strings.Unbounded; begin IO.Put (""""); declare S : constant Wide_Wide_String := Ada.Strings.UTF_Encoding.Wide_Wide_Strings.Decode (To_String (Value)); begin for C of S loop if C in '"' | '\' then IO.Put ("\" & Character'Val (Wide_Wide_Character'Pos (C))); elsif C in ' ' .. '~' then IO.Put ((1 => Character'Val (Wide_Wide_Character'Pos (C)))); else declare use type Interfaces.Unsigned_32; Codepoint : Interfaces.Unsigned_32 := Wide_Wide_Character'Pos (C); Digits_Count : constant Positive := (if Codepoint <= 16#FFFF# then 4 else 8); CP_Digits : String (1 .. Digits_Count); begin if Digits_Count = 4 then IO.Put ("\u"); else IO.Put ("\U"); end if; for D of reverse CP_Digits loop declare subtype Hex_Digit is Interfaces.Unsigned_32 range 0 .. 15; Digit : constant Hex_Digit := Codepoint mod 16; begin case Digit is when 0 .. 9 => D := Character'Val (Character'Pos ('0') + Digit); when 10 .. 15 => D := Character'Val (Character'Pos ('A') + Digit - 10); end case; Codepoint := Codepoint / 16; end; end loop; IO.Put (CP_Digits); end; end if; end loop; end; IO.Put (""""); end Dump_String; ---------------- -- Dump_Array -- ---------------- procedure Dump_Array (Value : TOML.TOML_Value) is begin IO.Put_Line ("["); for I in 1 .. Value.Length loop if I > 1 then IO.Put_Line (","); end if; Dump (Value.Item (I)); end loop; IO.Put_Line ("]"); end Dump_Array; ---------- -- Dump -- ---------- procedure Dump (Value : TOML.TOML_Value) is use all type TOML.Any_Value_Kind; procedure Put (Datetime : TOML.Any_Local_Datetime); procedure Put (Date : TOML.Any_Local_Date); procedure Put (Time : TOML.Any_Local_Time); --------- -- Put -- --------- procedure Put (Datetime : TOML.Any_Local_Datetime) is begin Put (Datetime.Date); IO.Put ("T"); Put (Datetime.Time); end Put; procedure Put (Date : TOML.Any_Local_Date) is begin IO.Put (Pad_Number (Date.Year'Image, 4) & "-" & Pad_Number (Date.Month'Image, 2) & "-" & Pad_Number (Date.Day'Image, 2)); end Put; procedure Put (Time : TOML.Any_Local_Time) is use type TOML.Any_Millisecond; begin IO.Put (Pad_Number (Time.Hour'Image, 2) & ":" & Pad_Number (Time.Minute'Image, 2) & ":" & Pad_Number (Time.Second'Image, 2)); if Time.Millisecond /= 0 then IO.Put ("." & Pad_Number (Time.Millisecond'Image, 3)); end if; end Put; begin if Value.Kind = TOML_Table then IO.Put_Line ("{"); declare Keys : constant TOML.Key_Array := Value.Keys; begin for I in Keys'Range loop if I > Keys'First then IO.Put_Line (","); end if; Dump_String (Keys (I)); IO.Put_Line (":"); Dump (Value.Get (Keys (I))); end loop; end; IO.Put_Line ("}"); elsif Value.Kind = TOML.TOML_Array and then (for all I in 1 .. Value.Length => Value.Item (I).Kind = TOML_Table) then Dump_Array (Value); else IO.Put_Line ("{""type"": """ & Kind_Name (Value.Kind) & """, ""value"":"); case Wrapped_Kind (Value.Kind) is when TOML_Array => Dump_Array (Value); when TOML_String => Dump_String (Value.As_Unbounded_String); IO.New_Line; when TOML_Integer => IO.Put_Line ("""" & Strip_Number (Value.As_Integer'Image) & """"); when TOML_Float => declare V : constant TOML.Any_Float := Value.As_Float; begin IO.Put (""""); case V.Kind is when TOML.Regular => IO.Put (Strip_Number (V.Value'Image)); when TOML.NaN => IO.Put (if V.Positive then "+" else "-"); IO.Put ("nan"); when TOML.Infinity => IO.Put (if V.Positive then "+" else "-"); IO.Put ("inf"); end case; IO.Put_Line (""""); end; when TOML_Boolean => if Value.As_Boolean then IO.Put_Line ("""true"""); else IO.Put_Line ("""false"""); end if; when TOML_Offset_Datetime => declare use type TOML.Any_Local_Offset; V : constant TOML.Any_Offset_Datetime := Value.As_Offset_Datetime; Absolute_Offset : constant TOML.Any_Local_Offset := (if V.Offset < 0 then -V.Offset else V.Offset); Hour_Offset : constant TOML.Any_Local_Offset := Absolute_Offset / 60; Minute_Offset : constant TOML.Any_Local_Offset := Absolute_Offset mod 60; begin IO.Put (""""); Put (V.Datetime); if V.Offset = 0 and then not V.Unknown_Offset then IO.Put ("Z"); else if V.Offset <= 0 then IO.Put ("-"); else IO.Put ("+"); end if; IO.Put (Pad_Number (Hour_Offset'Image, 2) & ":" & Pad_Number (Minute_Offset'Image, 2)); end if; IO.Put_Line (""""); end; when TOML_Local_Datetime => IO.Put (""""); Put (Value.As_Local_Datetime); IO.Put_Line (""""); when TOML_Local_Date => IO.Put (""""); Put (Value.As_Local_Date); IO.Put_Line (""""); when TOML_Local_Time => IO.Put (""""); Put (Value.As_Local_Time); IO.Put_Line (""""); end case; IO.Put_Line ("}"); end if; end Dump; --------- -- Get -- --------- procedure Get (Stream : in out Stdin_Stream; EOF : out Boolean; Byte : out Character) is pragma Unreferenced (Stream); Available : Boolean; begin IO.Get_Immediate (Byte, Available); EOF := not Available; exception when IO.End_Error => EOF := True; end Get; function Parse_File is new TOML.Generic_Parse (Stdin_Stream, Get); Stdin : Stdin_Stream := (null record); Result : constant TOML.Read_Result := Parse_File (Stdin); begin if Result.Success then Dump (Result.Value); else IO.Put_Line (TOML.Format_Error (Result)); Cmd.Set_Exit_Status (Cmd.Failure); end if; end Ada_TOML_Decode; alire-1.2.1/deps/ada-toml/src-checkers/ada_toml_encode.adb000066400000000000000000000317341411642634700234010ustar00rootroot00000000000000-- Test program. Read a valid toml-test compatible JSON description on the -- standard input and emit a corresponding TOML document on the standard -- output. with Ada.Containers.Generic_Array_Sort; with Ada.Strings.Unbounded; with Ada.Text_IO; with GNATCOLL.JSON; with TOML; with TOML.Generic_Dump; procedure Ada_TOML_Encode is use type Ada.Strings.Unbounded.Unbounded_String; use all type GNATCOLL.JSON.JSON_Value_Type; package US renames Ada.Strings.Unbounded; package IO renames Ada.Text_IO; package J renames GNATCOLL.JSON; type Stdout_Stream is null record; procedure Put (Stream : in out Stdout_Stream; Bytes : String); -- Callback for TOML.Generic_Dump function Interpret (Desc : J.JSON_Value) return TOML.TOML_Value; -- Interpret the given toml-test compatible JSON description (Value) and -- return the corresponding TOML value. type String_Array is array (Positive range <>) of US.Unbounded_String; procedure Sort_Strings is new Ada.Containers.Generic_Array_Sort (Index_Type => Positive, Element_Type => US.Unbounded_String, Array_Type => String_Array, "<" => US."<"); function Sorted_Keys (Desc : J.JSON_Value) return String_Array with Pre => Desc.Kind = JSON_Object_Type; -- Return a sorted array for all keys in the Desc object --------- -- Put -- --------- procedure Put (Stream : in out Stdout_Stream; Bytes : String) is pragma Unreferenced (Stream); begin IO.Put (Bytes); end Put; ----------------- -- Sorted_Keys -- ----------------- function Sorted_Keys (Desc : J.JSON_Value) return String_Array is Count : Natural := 0; procedure Count_CB (Dummy_Name : J.UTF8_String; Dummy_Value : J.JSON_Value); -------------- -- Count_CB -- -------------- procedure Count_CB (Dummy_Name : J.UTF8_String; Dummy_Value : J.JSON_Value) is begin Count := Count + 1; end Count_CB; begin Desc.Map_JSON_Object (Count_CB'Access); return Result : String_Array (1 .. Count) do declare I : Positive := Result'First; procedure Read_Entry (Name : J.UTF8_String; Dummy_Value : J.JSON_Value); ---------------- -- Read_Entry -- ---------------- procedure Read_Entry (Name : J.UTF8_String; Dummy_Value : J.JSON_Value) is begin Result (I) := US.To_Unbounded_String (Name); I := I + 1; end Read_Entry; begin Desc.Map_JSON_Object (Read_Entry'Access); Sort_Strings (Result); end; end return; end Sorted_Keys; --------------- -- Interpret -- --------------- function Interpret (Desc : J.JSON_Value) return TOML.TOML_Value is Time_Base_Length : constant := 8; Time_Milli_Length : constant := 4; Date_Length : constant := 10; Local_Datetime_Base_Length : constant := Date_Length + 1 + Time_Base_Length; Offset_Datetime_Base_Length : constant := Local_Datetime_Base_Length + 1; Offset_Full_Length : constant := 6; function Decode_Offset_Datetime (S : String) return TOML.Any_Offset_Datetime; function Decode_Local_Datetime (S : String) return TOML.Any_Local_Datetime; function Decode_Date (S : String) return TOML.Any_Local_Date; function Decode_Time (S : String) return TOML.Any_Local_Time; ---------------------------- -- Decode_Offset_Datetime -- ---------------------------- function Decode_Offset_Datetime (S : String) return TOML.Any_Offset_Datetime is use type TOML.Any_Local_Offset; pragma Assert (S'Length >= Offset_Datetime_Base_Length); Offset : TOML.Any_Local_Offset; Unknown_Offset : Boolean; I : constant Positive := S'First; Last : Positive := S'Last; begin if S (Last) = 'Z' then Last := Last - 1; Offset := 0; Unknown_Offset := False; else declare pragma Assert (S (Last - 2) = ':'); Offset_Sign : Character renames S (Last - 5); Hour_Offset : String renames S (Last - 4 .. Last - 3); Minute_Offset : String renames S (Last - 1 .. Last); begin Offset := 60 * TOML.Any_Local_Offset'Value (Hour_Offset) + TOML.Any_Local_Offset'Value (Minute_Offset); case Offset_Sign is when '-' => Offset := -Offset; when '+' => null; when others => raise Program_Error; end case; Unknown_Offset := Offset = 0 and then Offset_Sign = '-'; Last := Last - Offset_Full_Length; end; end if; declare Local_Datetime : constant TOML.Any_Local_Datetime := Decode_Local_Datetime (S (I .. Last)); begin return (Local_Datetime, Offset, Unknown_Offset); end; end Decode_Offset_Datetime; --------------------------- -- Decode_Local_Datetime -- --------------------------- function Decode_Local_Datetime (S : String) return TOML.Any_Local_Datetime is I : constant Positive := S'First; pragma Assert (S'Length >= Local_Datetime_Base_Length); pragma Assert (S (I + Date_Length) = 'T'); Date : constant TOML.Any_Local_Date := Decode_Date (S (I .. I + Date_Length - 1)); Time : constant TOML.Any_Local_Time := Decode_Time (S (I + Date_Length + 1 .. S'Last)); begin return (Date, Time); end Decode_Local_Datetime; ----------------- -- Decode_Date -- ----------------- function Decode_Date (S : String) return TOML.Any_Local_Date is I : constant Positive := S'First; pragma Assert (S'Length = Date_Length); pragma Assert (S (I + 4) = '-'); pragma Assert (S (I + 7) = '-'); Year : String renames S (I + 0 .. I + 3); Month : String renames S (I + 5 .. I + 6); Day : String renames S (I + 8 .. I + 9); begin return (TOML.Any_Year'Value (Year), TOML.Any_Month'Value (Month), TOML.Any_Day'Value (Day)); end Decode_Date; ----------------- -- Decode_Time -- ----------------- function Decode_Time (S : String) return TOML.Any_Local_Time is I : constant Positive := S'First; pragma Assert (S'Length in Time_Base_Length | Time_Base_Length + Time_Milli_Length); pragma Assert (S (I + 2) = ':'); pragma Assert (S (I + 5) = ':'); Hour : String renames S (I + 0 .. I + 1); Minute : String renames S (I + 3 .. I + 4); Second : String renames S (I + 6 .. I + 7); Millisecond : TOML.Any_Millisecond := 0; begin if S'Length /= Time_Base_Length then pragma Assert (S (I + Time_Base_Length) = '.'); Millisecond := TOML.Any_Millisecond'Value (S (I + Time_Base_Length + 1 .. S'Last)); end if; return (TOML.Any_Hour'Value (Hour), TOML.Any_Minute'Value (Minute), TOML.Any_Second'Value (Second), Millisecond); end Decode_Time; Result : TOML.TOML_Value; begin case Desc.Kind is when JSON_Object_Type => declare Keys : constant String_Array := Sorted_Keys (Desc); begin if Keys'Length = 2 and then Keys (1) = US.To_Unbounded_String ("type") and then Keys (2) = US.To_Unbounded_String ("value") then declare T : constant String := Desc.Get ("type"); V : constant J.JSON_Value := Desc.Get ("value"); begin if T = "string" then declare S : constant String := V.Get; begin Result := TOML.Create_String (S); end; elsif T = "float" then declare S : constant String := V.Get; I : Positive := S'First; Positive : Boolean := True; Value : TOML.Any_Float; begin if S (I) = '+' then I := I + 1; elsif S (I) = '-' then Positive := False; I := I + 1; end if; if S (I .. S'Last) = "nan" then Value := (Kind => TOML.NaN, Positive => Positive); elsif S (I .. S'Last) = "inf" then Value := (Kind => TOML.Infinity, Positive => Positive); else declare use type TOML.Valid_Float; VF : TOML.Valid_Float := TOML.Valid_Float'Value (S (I .. S'Last)); begin if not Positive then VF := -VF; end if; Value := (Kind => TOML.Regular, Value => VF); end; end if; Result := TOML.Create_Float (Value); end; elsif T = "integer" then declare S : constant String := V.Get; begin Result := TOML.Create_Integer (TOML.Any_Integer'Value (S)); end; elsif T = "bool" then declare S : constant String := V.Get; begin Result := TOML.Create_Boolean (Boolean'Value (S)); end; elsif T = "datetime" then Result := TOML.Create_Offset_Datetime (Decode_Offset_Datetime (V.Get)); elsif T = "datetime-local" then Result := TOML.Create_Local_Datetime (Decode_Local_Datetime (V.Get)); elsif T = "date-local" then Result := TOML.Create_Local_Date (Decode_Date (V.Get)); elsif T = "time-local" then Result := TOML.Create_Local_Time (Decode_Time (V.Get)); elsif T = "array" then Result := Interpret (V); else raise Program_Error with "unhandled value type: " & T; end if; end; else Result := TOML.Create_Table; for K of Keys loop declare Item : constant TOML.TOML_Value := Interpret (Desc.Get (US.To_String (K))); begin Result.Set (K, Item); end; end loop; end if; end; when JSON_Array_Type => declare Elements : constant J.JSON_Array := Desc.Get; begin Result := TOML.Create_Array; for I in 1 .. J.Length (Elements) loop Result.Append (Interpret (J.Get (Elements, I))); end loop; end; when others => raise Program_Error; end case; return Result; end Interpret; procedure Dump is new TOML.Generic_Dump (Stdout_Stream, Put); Input : US.Unbounded_String; Description : J.JSON_Value; Result : TOML.TOML_Value; Stdout : Stdout_Stream := (null record); begin -- Read the stdin until end of file and store its content in Input loop begin declare Line : constant String := IO.Get_Line; begin US.Append (Input, Line); end; exception when IO.End_Error => exit; end; end loop; -- Decode this input as JSON Description := J.Read (US.To_String (Input)); -- Build the TOML document from the JSON description and output it on the -- standard output. Result := Interpret (Description); Dump (Stdout, Result); end Ada_TOML_Encode; alire-1.2.1/deps/ada-toml/src/000077500000000000000000000000001411642634700160375ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/src/toml-file_io.adb000066400000000000000000000037361411642634700210770ustar00rootroot00000000000000with Ada.Exceptions; with TOML.Generic_Dump; with TOML.Generic_Parse; package body TOML.File_IO is procedure Get (Stream : in out Ada.Text_IO.File_Type; EOF : out Boolean; Byte : out Character); -- Callback for Parse_File function Parse_File is new TOML.Generic_Parse (Input_Stream => Ada.Text_IO.File_Type, Get => Get); procedure Put_To_File (File : in out Ada.Text_IO.File_Type; Bytes : String); -- Callback for TOML.Generic_Dump procedure Dump_To_File is new TOML.Generic_Dump (Output_Stream => Ada.Text_IO.File_Type, Put => Put_To_File); --------- -- Get -- --------- procedure Get (Stream : in out Ada.Text_IO.File_Type; EOF : out Boolean; Byte : out Character) is begin EOF := False; Ada.Text_IO.Get_Immediate (Stream, Byte); exception when Ada.Text_IO.End_Error => EOF := True; end Get; ----------------- -- Put_To_File -- ----------------- procedure Put_To_File (File : in out Ada.Text_IO.File_Type; Bytes : String) is begin Ada.Text_IO.Put (File, Bytes); end Put_To_File; --------------- -- Load_File -- --------------- function Load_File (Filename : String) return Read_Result is use Ada.Exceptions, Ada.Text_IO; File : File_Type; begin begin Open (File, In_File, Filename); exception when Exc : Name_Error | Use_Error => return Create_Error ("cannot open " & Filename & ": " & Exception_Message (Exc), No_Location); end; return Result : constant Read_Result := Parse_File (File) do Close (File); end return; end Load_File; ------------------ -- Dump_To_File -- ------------------ procedure Dump_To_File (Value : TOML_Value; File : in out Ada.Text_IO.File_Type) is begin Dump_To_File (File, Value); end Dump_To_File; end TOML.File_IO; alire-1.2.1/deps/ada-toml/src/toml-file_io.ads000066400000000000000000000010521411642634700211050ustar00rootroot00000000000000with Ada.Text_IO; package TOML.File_IO is -- Subprograms to load/save TOML files use all type Ada.Text_IO.File_Mode; function Load_File (Filename : String) return Read_Result; -- Read Filename and parse its content as a TOML document procedure Dump_To_File (Value : TOML_Value; File : in out Ada.Text_IO.File_Type) with Pre => Value.Kind = TOML_Table and then Ada.Text_IO.Mode (File) in Out_File | Append_File; -- Serialize Value and write the corresponding TOML document to File end TOML.File_IO; alire-1.2.1/deps/ada-toml/src/toml-generic_dump.adb000066400000000000000000000405621411642634700221300ustar00rootroot00000000000000with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; procedure TOML.Generic_Dump (Stream : in out Output_Stream; Value : TOML_Value) is procedure Put (Bytes : String); -- Shortcut for Put (Stream, Bytes) type Map_Pair is record Key : Unbounded_UTF8_String; Value : TOML_Value; end record; type Map_Pair_Array is array (Positive range <>) of Map_Pair; function Format_String (S : Unbounded_UTF8_String) return Unbounded_UTF8_String; -- Format a valid TOML representation of the given string (S) function Format_Key (Key : Unbounded_UTF8_String) return Unbounded_UTF8_String; -- Format a valid TOML representation of the given Key function Append_Key (Prefix, Suffix : Unbounded_UTF8_String) return Unbounded_UTF8_String; -- Return a key corresponding to "Prefix.Suffix" (if Prefix is not empty) -- or "Suffix" (if Prefix is empty). procedure Separate_Pairs (Pairs : in out Map_Pair_Array; Last_Table_Pair : out Natural; Last_Array_Pair : out Natural) with Pre => Pairs'First = 1; -- Shuffle Pairs so that, after the procedure returns: -- -- * Pairs (Pairs'First .. Last_Table_Pair) contains only table values; -- * Pairs (Last_Table_Pair + 1 .. Last_Array_Pair) contains only -- array-of-tables values; -- * Pairs (Last_Array_Pair + 1 .. Pairs'Last) contains remaining values. -- -- The three array sub-ranges are sorted by key. procedure Put_Table_Header (Prefix, Suffix : Unbounded_UTF8_String; Nested_Key : out Unbounded_UTF8_String); -- Set Nested_Key to Append_Key (Prefix, Suffix). Then write a table header -- for Nested_Key to Stream. procedure Put_Array_Header (Nested_Key : Unbounded_UTF8_String); -- Write an array of tables header for Nested_Key to Stream procedure Dump_Toplevel_Table (Key : Unbounded_UTF8_String; Value : TOML_Value) with Pre => Value.Kind = TOML_Table; -- Dump the given table (Value) as a top-level table, under the given key procedure Dump_Toplevel_Array (Parent_Key, Array_Key : Unbounded_UTF8_String; Array_Value : TOML_Value) with Pre => Array_Value.Kind = TOML_Array; -- Dump the given array (Array_Value) as a top-level array of tables, under -- the given keys (Parent_Key "." Array_Key). function Strip_Number (Image : String) return String; -- If the first character in Image is a space, return the rest of Image function Pad_Number (Image : String; Digit_Count : Positive) return String; -- Return Strip_Number (Image) left-padded with 0 so that the result is -- Digit_Count long. procedure Dump_Inline (Value : TOML_Value) with Pre => Value /= No_TOML_Value; -- Dump the given value using the inline format --------- -- Put -- --------- procedure Put (Bytes : String) is begin Put (Stream, Bytes); end Put; ------------------- -- Format_String -- ------------------- function Format_String (S : Unbounded_UTF8_String) return Unbounded_UTF8_String is Result : Unbounded_UTF8_String; begin Append (Result, """"); for I in 1 .. Length (S) loop -- Forward printable ASCII bytes (except quotes and backslashes) -- and non-ASCII bytes, but emit escapes for quotes and control -- characters. declare Char : constant Character := Element (S, I); begin case Char is -- The only way to represent the following control characters -- is to use the unicode escape (\uXXXX). when ASCII.NUL .. ASCII.BEL | ASCII.VT | ASCII.SO .. ASCII.US | ASCII.DEL => declare use type Interfaces.Unsigned_8; Byte : Interfaces.Unsigned_8 := Character'Pos (Char); Repr : String (1 .. 6) := "\u0000"; I : Natural range 3 .. 6 := 6; begin while Byte /= 0 loop declare Nibble : constant Interfaces.Unsigned_8 := Byte mod 16; Digit : Interfaces.Unsigned_8; begin if Nibble <= 9 then Digit := Character'Pos ('0') + Nibble; else Digit := Character'Pos ('a') - 10 + Nibble; end if; Repr (I) := Character'Val (Digit); Byte := Byte / 16; I := I - 1; end; end loop; Append (Result, Repr); end; -- The following control characters have dedicated escape -- sequences: when ASCII.BS => Append (Result, "\b"); when ASCII.HT => Append (Result, "\t"); when ASCII.LF => Append (Result, "\n"); when ASCII.FF => Append (Result, "\f"); when ASCII.CR => Append (Result, "\r"); -- Quotes and backslashes must be escaped when '"' => Append (Result, "\"""); when '\' => Append (Result, "\\"); -- All other bytes can be directly forwarded to the string -- literal. when ' ' | '!' | '#' .. '[' | ']' .. '~' | Character'Val (128) .. Character'Val(255) => Append (Result, Char); end case; end; end loop; Append (Result, """"); return Result; end Format_String; ---------------- -- Format_Key -- ---------------- function Format_Key (Key : Unbounded_UTF8_String) return Unbounded_UTF8_String is begin -- Determine if we need to quote Key, and if so, do it for I in 1 .. Length (Key) loop if Element (Key, I) not in '0' .. '9' | 'A' .. 'Z' | 'a' .. 'z' | '-' | '_' then return Format_String (Key); end if; end loop; if Length (Key) = 0 then return Format_String (Key); end if; -- Otherwise, we can return the key as-is (without quoting) return Key; end Format_Key; ---------------- -- Append_Key -- ---------------- function Append_Key (Prefix, Suffix : Unbounded_UTF8_String) return Unbounded_UTF8_String is Result : Unbounded_UTF8_String := Prefix; begin if Length (Result) > 0 then Append (Result, "."); end if; Append (Result, Format_Key (Suffix)); return Result; end Append_Key; -------------------- -- Separate_Pairs -- -------------------- procedure Separate_Pairs (Pairs : in out Map_Pair_Array; Last_Table_Pair : out Natural; Last_Array_Pair : out Natural) is type Pair_List is record Pairs : Map_Pair_Array (Separate_Pairs.Pairs'Range); Last : Natural := 0; end record; procedure Append (Pair : Map_Pair; List : in out Pair_List); -- Append Pair to the given List procedure Append (List : Pair_List; First_Pair : Positive; Last_Pair : out Natural); -- Append all pairs in List to Pairs. The first one goes to: -- -- Pairs (First_Pair) -- -- and the last one is copied to: -- -- Pairs (Last_Pair) ------------ -- Append -- ------------ procedure Append (Pair : Map_Pair; List : in out Pair_List) is begin List.Last := List.Last + 1; List.Pairs (List.Last) := Pair; end Append; ------------ -- Append -- ------------ procedure Append (List : Pair_List; First_Pair : Positive; Last_Pair : out Natural) is begin Last_Pair := First_Pair - 1; for P of List.Pairs (1 .. List.Last) loop Last_Pair := Last_Pair + 1; Pairs (Last_Pair) := P; end loop; end Append; Table_Pairs, Array_Pairs, Other_Pairs : Pair_List; Last : Natural; begin -- Put pairs in separate lists. Note that this preserves sorting. for P of Pairs loop case P.Value.Kind is when TOML_Table => Append (P, Table_Pairs); when TOML_Array => if (for all I in 1 .. P.Value.Length => P.Value.Item (I).Kind = TOML_Table) then Append (P, Array_Pairs); else Append (P, Other_Pairs); end if; when others => Append (P, Other_Pairs); end case; end loop; -- Then put back each category of pairs to Pairs Append (Table_Pairs, Pairs'First, Last_Table_Pair); Append (Array_Pairs, Last_Table_Pair + 1, Last_Array_Pair); Append (Other_Pairs, Last_Array_Pair + 1, Last); pragma Assert (Last = Pairs'Last); end Separate_Pairs; ---------------------- -- Put_Table_Header -- ---------------------- procedure Put_Table_Header (Prefix, Suffix : Unbounded_UTF8_String; Nested_Key : out Unbounded_UTF8_String) is begin Nested_Key := Append_Key (Prefix, Suffix); Put ("[" & To_String (Nested_Key) & "]" & ASCII.LF); end Put_Table_Header; ---------------------- -- Put_Array_Header -- ---------------------- procedure Put_Array_Header (Nested_Key : Unbounded_UTF8_String) is begin Put ("[[" & To_String (Nested_Key) & "]]" & ASCII.LF); end Put_Array_Header; ------------------------- -- Dump_Toplevel_Table -- ------------------------- procedure Dump_Toplevel_Table (Key : Unbounded_UTF8_String; Value : TOML_Value) is Keys : constant Key_Array := Value.Keys; Pairs : Map_Pair_Array (Keys'Range); Last_Table_Pair, Last_Array_Pair : Natural; Nested_Key : Unbounded_UTF8_String; begin -- Initialize Pairs from Keys and Value and split pairs by value kind for I in Keys'Range loop Pairs (I) := (Key => Keys (I), Value => Value.Get (Keys (I))); end loop; Separate_Pairs (Pairs, Last_Table_Pair, Last_Array_Pair); declare Table_Pairs : Map_Pair_Array renames Pairs (Pairs'First .. Last_Table_Pair); Array_Pairs : Map_Pair_Array renames Pairs (Last_Table_Pair + 1 .. Last_Array_Pair); Other_Pairs : Map_Pair_Array renames Pairs (Last_Array_Pair + 1 .. Pairs'Last); begin -- Dump non-table and non-array map pairs with inline style: -- key = value for Pair of Other_Pairs loop Put (To_String (Format_Key (Pair.Key))); Put (" = "); Dump_Inline (Pair.Value); Put ((1 => ASCII.LF)); end loop; -- Dump tables as top-level ones: [section] for Pair of Table_Pairs loop Put_Table_Header (Key, Pair.Key, Nested_Key); Dump_Toplevel_Table (Nested_Key, Pair.Value); end loop; -- Dump arrays as top-level ones: [[section]] for Pair of Array_Pairs loop Dump_Toplevel_Array (Key, Pair.Key, Pair.Value); end loop; end; end Dump_Toplevel_Table; ------------------------- -- Dump_Toplevel_Array -- ------------------------- procedure Dump_Toplevel_Array (Parent_Key, Array_Key : Unbounded_UTF8_String; Array_Value : TOML_Value) is Nested_Key : constant Unbounded_UTF8_String := Append_Key (Parent_Key, Array_Key); begin for I in 1 .. Array_Value.Length loop Put_Array_Header (Nested_Key); Dump_Toplevel_Table (Nested_Key, Array_Value.Item (I)); end loop; end Dump_Toplevel_Array; ------------------ -- Strip_Number -- ------------------ function Strip_Number (Image : String) return String is begin if Image'Length > 0 and then Image (Image'First) = ' ' then return Image (Image'First + 1 .. Image'Last); else return Image; end if; end Strip_Number; ---------------- -- Pad_Number -- ---------------- function Pad_Number (Image : String; Digit_Count : Positive) return String is Result : constant String := Strip_Number (Image); begin pragma Assert (Result'Length <= Digit_Count); return (Result'Length + 1 .. Digit_Count => '0') & Result; end Pad_Number; ----------------- -- Dump_Inline -- ----------------- procedure Dump_Inline (Value : TOML_Value) is procedure Put (Datetime : TOML.Any_Local_Datetime); procedure Put (Date : TOML.Any_Local_Date); procedure Put (Time : TOML.Any_Local_Time); --------- -- Put -- --------- procedure Put (Datetime : TOML.Any_Local_Datetime) is begin Put (Datetime.Date); Put ("T"); Put (Datetime.Time); end Put; procedure Put (Date : TOML.Any_Local_Date) is begin Put (Pad_Number (Date.Year'Image, 4) & "-" & Pad_Number (Date.Month'Image, 2) & "-" & Pad_Number (Date.Day'Image, 2)); end Put; procedure Put (Time : TOML.Any_Local_Time) is begin Put (Pad_Number (Time.Hour'Image, 2) & ":" & Pad_Number (Time.Minute'Image, 2) & ":" & Pad_Number (Time.Second'Image, 2) & "." & Pad_Number (Time.Millisecond'Image, 3)); end Put; begin case Value.Kind is when TOML_Boolean => Put ((if Value.As_Boolean then "true" else "false")); when TOML_Integer => Put (Strip_Number (Any_Integer'Image (Value.As_Integer))); when TOML_Float => declare V : constant Any_Float := Value.As_Float; begin case V.Kind is when Regular => Put (Strip_Number (V.Value'Image)); when NaN | Infinity => Put (if V.Positive then "" else "-"); Put (if V.Kind = NaN then "nan" else "inf"); end case; end; when TOML_String => -- TODO: escape strings when needed Put (To_String (Format_String (Value.As_Unbounded_String))); when TOML_Offset_Datetime => declare V : constant Any_Offset_Datetime := Value.As_Offset_Datetime; Absolute_Offset : constant Any_Local_Offset := (if V.Offset < 0 then -V.Offset else V.Offset); Hour_Offset : constant Any_Local_Offset := Absolute_Offset / 60; Minute_Offset : constant Any_Local_Offset := Absolute_Offset mod 60; begin Put (V.Datetime); if V.Offset < 0 or else V.Unknown_Offset then Put ("-"); else Put ("+"); end if; Put (Pad_Number (Hour_Offset'Image, 2) & ":" & Pad_Number (Minute_Offset'Image, 2)); end; when TOML_Local_Datetime => Put (Value.As_Local_Datetime); when TOML_Local_Date => Put (Value.As_Local_Date); when TOML_Local_Time => Put (Value.As_Local_Time); when TOML_Array => Put ("[" & ASCII.LF); for I in 1 .. Value.Length loop Dump_Inline (Value.Item (I)); Put ("," & ASCII.LF); end loop; Put ("]"); when TOML_Table => Put ("{"); declare First : Boolean := True; begin for E of Value.Iterate_On_Table loop if not First then Put (", "); end if; Put (To_String (Format_String (E.Key))); Put (" = "); Dump_Inline (E.Value); First := False; end loop; end; Put ("}"); end case; end Dump_Inline; begin Dump_Toplevel_Table (Null_Unbounded_String, Value); end TOML.Generic_Dump; alire-1.2.1/deps/ada-toml/src/toml-generic_dump.ads000066400000000000000000000006251411642634700221450ustar00rootroot00000000000000generic type Output_Stream (<>) is limited private; -- Stream of bytes with procedure Put (Stream : in out Output_Stream; Bytes : String) is <>; -- Write all Bytes in Stream procedure TOML.Generic_Dump (Stream : in out Output_Stream; Value : TOML_Value) with Preelaborate, Pre => Value.Kind = TOML_Table; -- Turn the given Value into a valid TOML document and write it to Stream alire-1.2.1/deps/ada-toml/src/toml-generic_parse.adb000066400000000000000000002607351411642634700223030ustar00rootroot00000000000000with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Interfaces; function TOML.Generic_Parse (Stream : in out Input_Stream) return TOML.Read_Result is ---------------------------- -- Lexical analysis state -- ---------------------------- WW_Backspace : constant Wide_Wide_Character := Wide_Wide_Character'Val (Character'Pos (ASCII.BS)); WW_Linefeed : constant Wide_Wide_Character := Wide_Wide_Character'Val (Character'Pos (ASCII.LF)); WW_Form_Feed : constant Wide_Wide_Character := Wide_Wide_Character'Val (Character'Pos (ASCII.FF)); WW_Carriage_Return : constant Wide_Wide_Character := Wide_Wide_Character'Val (Character'Pos (ASCII.CR)); WW_Tab : constant Wide_Wide_Character := Wide_Wide_Character'Val (Character'Pos (ASCII.HT)); subtype WW_Control_Characters is Wide_Wide_Character with Static_Predicate => WW_Control_Characters in Wide_Wide_Character'Val (16#00#) .. Wide_Wide_Character'Val (16#1F#) | Wide_Wide_Character'Val (16#7F#); subtype WW_Non_ASCII is Wide_Wide_Character range Wide_Wide_Character'Val (16#80#) .. Wide_Wide_Character'Last; subtype WW_Surrogates is Wide_Wide_Character range Wide_Wide_Character'Val (16#D800#) .. Wide_Wide_Character'Val (16#DFFF#); type Codepoint_Buffer_Type (EOF : Boolean := False) is record To_Reemit : Boolean; -- If true, the next call to Read_Codepoint should do nothing, except -- resetting this to component to false. Location : Source_Location; case EOF is when True => null; when False => Codepoint : Wide_Wide_Character; end case; end record; Codepoint_Buffer : Codepoint_Buffer_Type := (EOF => False, To_Reemit => False, Location => No_Location, Codepoint => <>); -- Buffer used to temporarily store information read from Stream type Any_String_Format is (Bare_Key, Basic_String, Multiline_Basic_String, Literal_String, Multiline_Literal_String); subtype Valid_Key_Format is Any_String_Format with Static_Predicate => Valid_Key_Format in Bare_Key | Basic_String | Literal_String; type Token_Kind is (Newline, Equal, Dot, Comma, Curly_Bracket_Open, Curly_Bracket_Close, Square_Bracket_Open, Square_Bracket_Close, Double_Square_Bracket_Open, Double_Square_Bracket_Close, Boolean_Literal, Integer_Literal, Float_Literal, String_Literal, Offset_Datetime_Literal, Local_Datetime_Literal, Local_Date_Literal, Local_Time_Literal); subtype No_Text_Token is Token_Kind range Newline .. Double_Square_Bracket_Close; -- Tokens whose text does not matter: the kind itself holds enough -- information to describe the token. type Any_Token (Kind : Token_Kind := Token_Kind'First) is record case Kind is when No_Text_Token => null; when Boolean_Literal => Boolean_Value : Boolean; when Integer_Literal => Integer_Value : Any_Integer; when Float_Literal => Float_Value : Any_Float; when String_Literal => String_Value : Unbounded_UTF8_String; String_Format : Any_String_Format; when Offset_Datetime_Literal => Offset_Datetime_Value : Any_Offset_Datetime; when Local_Datetime_Literal => Local_Datetime_Value : Any_Local_Datetime; when Local_Date_Literal => Local_Date_Value : Any_Local_Date; when Local_Time_Literal => Local_Time_Value : Any_Local_Time; end case; end record; True_Keyword : constant Any_Token := (Kind => Boolean_Literal, Boolean_Value => True); False_Keyword : constant Any_Token := (Kind => Boolean_Literal, Boolean_Value => False); type Token_Buffer_Type (EOF : Boolean := False) is record To_Reemit : Boolean; -- If true, the next call to Read_Token should do nothing, except -- resetting this to component to false. case EOF is when True => null; when False => Token : Any_Token; Location : Source_Location; end case; end record; Token_Buffer : Token_Buffer_Type := (EOF => False, To_Reemit => False, Location => No_Location, Token => <>); ------------------------------ -- Syntactic analysis state -- ------------------------------ Root_Table : constant TOML_Value := Create_Table; Result : Read_Result := (Success => True, Value => Root_Table); Current_Table : TOML_Value := Root_Table; -- Table that the next key/value pair node will update function Create_Error (Message : String; Location : Source_Location := No_Location) return Boolean with Post => not Create_Error'Result; -- Put in Result an unsuccessful Read_Result value with the provided error -- information. If no source location is passed, use -- Codepoint_Buffer.Location. -- -- This is a function that always return False for convenience in parsing -- helpers, which are all functions that return False on error. function Create_Lexing_Error (Message : String := "invalid token") return Boolean with Post => not Create_Lexing_Error'Result; -- Like Create_Error, but use Token_Buffer.Location as the source location -- for the error. function Create_Syntax_Error (Message : String := "invalid syntax") return Boolean with Post => not Create_Syntax_Error'Result; -- Like Create_Error, but use Token_Buffer.Location as the source location -- for the error. ----------------------- -- Codepoint reading -- ----------------------- function Read_Codepoint return Boolean with Pre => not Codepoint_Buffer.EOF or else Codepoint_Buffer.To_Reemit; -- Read a UTF-8 codepoint from Stream. If EOF is reached or a codepoint -- could be read, return True and update Codepoint_Buffer accordingly -- (location included). Otherwise, return False and put an error in Result. -- -- Note that this automatically discards carriage returns codepoints when -- they are immediately followed by a linefeed. When they are not followed -- by a linefeed, this creates an error. procedure Reemit_Codepoint with Pre => not Codepoint_Buffer.To_Reemit; -- Re-emit the same codepoint the next time that Read_Codepoint is called -------------------- -- Token decoding -- -------------------- function Read_Token (Key_Expected : Boolean) return Boolean with Pre => not Token_Buffer.EOF or else Token_Buffer.To_Reemit; -- Read a token from Stream. If EOF is reached or a token could be read, -- return True and update Token_Buffer accordingly (location included). -- Otherwise, return False and put an error in Result. -- -- If Key_Expected is true: -- -- * parse tokens that could be integer literals as string literals; -- * parse "[["/"]]" as double square bracket tokens instead of two -- consecutive square bracket tokens. procedure Reemit_Token with Pre => not Token_Buffer.To_Reemit; -- Re-emit the same token the next time that Read_Token is called procedure Append_As_UTF8 (Codepoint : Wide_Wide_Character) with Pre => not Token_Buffer.EOF and then Token_Buffer.Token.Kind = String_Literal; -- Append the given codepoint to Token_Buffer.Token.String_Value (a UTF-8 -- encoded string). function Digit_Value (Codepoint : Wide_Wide_Character) return Interfaces.Unsigned_64 with Pre => Codepoint in '0' .. '9' | 'a' .. 'f' | 'A' .. 'F'; -- Assuming that Codepoint is a valid hexadecimal digit, return the -- corresponding number value. function Read_Unicode_Escape_Sequence (Location : Source_Location) return Boolean; -- Helper for Read_Quoted_String. Assuming that string parsing just read a -- "\u" or "\U" prefix, parse the rest of the Unicode escape sequence and -- append the denoted codepoint using Append_As_UTF8. If successful, return -- True, otherwise put an error in Result and return False. function Read_Quoted_String return Boolean; -- Helper for Read_Token. Read a string literal, whose first quote is in -- Codepoint_Buffer. Return whether successful, updating Token_Buffer -- accordingly. function Read_Number_Like return Boolean; -- Helper for Read_Token. Read an integer literal or a local date, whose -- first digit (or sign) is in Codepoint_Buffer. Return whether successful, -- updating Token_Buffer accordingly. function Read_Datetime_Field (What : String; Digit_Count : Positive; Base_Value : Interfaces.Unsigned_64; Base_Digits : Natural; Value : out Interfaces.Unsigned_64) return Boolean; -- Helper to read dates and times. Read a specific date/time field: What is -- the name of the field to read. Considering that we already read -- Base_Digits number of digits and that the decoded value so far is -- Base_Value, continue consuming digits until we have a total of -- Digit_Count digits. Put the decoded value in Value and return True if -- successful. Create a lexing error and return False otherwise. function Read_Date (Base_Value : Interfaces.Unsigned_64; Base_Digits : Natural) return Boolean; -- Helper for Read_Number_Like. Read a local date, local datetime or an -- offset datetime, considering that we already consumed Base_Digits -- digits, whose value is Base_Value. Return whether successful, updating -- Token_Buffer accordingly. function Read_Local_Time (Base_Value : Interfaces.Unsigned_64; Base_Digits : Natural; Read_Timezone : Boolean) return Boolean; -- Helper for Read_Number_Like and Read_Date. Read a local time, -- considering that we already consumed Base_Digits digits, whose value -- is Base_Value. Return whether successful, updating Token_Buffer -- accordingly (Local_Time_Literal). -- -- If Read_Timezone is true, attempt to read the timezone information. In -- this mode, assume that Token_Buffer already contains a date -- (Local_Date_Literal) and update it to contain either an -- Offset_Datetime_Literal variant (if there is a timezone) or a -- Local_Datetime_Literal variant. function Read_Float (Positive : Boolean; Integer_Value : Interfaces.Unsigned_64) return Boolean; -- Helper for Read_Number_Like. Read a floating point number considering -- that we already consumed its sign (Positive) and its integer part -- (Integer_Part): the codepoint buffer must contain one of '.' | 'e' | -- 'E'. Return whether successful, updating Token_Buffer accordingly. function Read_Special_Float (Name : Wide_Wide_String; Kind : Special_Float_Kind; Positive : Boolean) return Boolean; -- Helper for Read_Number_Like. Read the name of a special floating point -- number. Return whether successful, updating Token_Buffer accordingly. function Read_Bare_Key return Boolean; -- Helper for Read_Token. Read a bare key, whose first character is in -- Codepoint_Buffer. Return whether successful, updating Token_Buffer -- accordingly. function Read_Keyword (Text : Wide_Wide_String; Token : Any_Token) return Boolean; -- Helper for Read_Token. Try to read the given Text, whose first character -- is in Codepoint_Buffer. Return whether successful, updating Token_Buffer -- accordingly. -------------------- -- Syntax parsing -- -------------------- function Parse_Line return Boolean; -- Read and parse the next line in Stream. Update Result accordingly. ------------------------ -- Table construction -- ------------------------ function Get_Table (Key : Unbounded_UTF8_String; Table : in out TOML_Value; Traverse_Arrays : Boolean := False) return Boolean; -- Look for a sub-table in Table correspondig to Key. On success, store it -- in Table and return True. Otherwise, return False and put an error in -- Result. -- -- If there is no Key entry in Table, create one and register it. -- -- If this entry is an array, then assuming all the following hold: -- -- * Traverse_Arrays is true; -- * Table contains a Key entry that is an array of tables; -- * this array contains at least one element. -- -- then this gets the last table that was added to this array. Otherwise, -- this fails. function Parse_Section (Array_Of_Table : Boolean) return Boolean; -- Parse the name of a section ([my.table]) and update Current_Table -- accordingly. This assumes that the opening bracket is already in -- Token_Buffer. When this returns, the Newline token (or EOF) is in -- Token_Buffer. -- -- If Array_Of_Table is false, expect the section name to designate a -- table. Otherwise, expect it to designate an array of tables. -- -- Return whether parsing and interpretation was successful. function Parse_Dotted_Keys (Table : in out TOML_Value; Key : out Unbounded_UTF8_String; Traverse_Arrays : Boolean := False) return Boolean; -- Parse a sequence of dotted keys and interpret it as a reference into -- Table. Put the last key in Key, and update Table to the referenced table -- (i.e. the one in which Key will reference/create an entry). -- -- This assumes that the first token that constitutes the dotted keys is in -- Token_Buffer. When this returns, the token just passed the dotted keys -- will be in Token_Buffer. -- -- Return whether parsing and interpretation was successful. function Parse_Value (Value : out TOML_Value) return Boolean; -- Parse an inline value (boolean/integer literal, inline table, inline -- array, ...) and put it in Value. -- -- The first token that constitutes the value is expected to be read during -- the call. When this returns, Token_Buffer contains the last token that -- was used to parse the value. function Parse_Array (Value : out TOML_Value) return Boolean; -- Parse an inline array and put it in Value. -- -- This assumes that the first token that constitutes the array (i.e. '[') -- is in Token_Buffer. When this returns, Token_Buffer contains the last -- token that was used to parse the value (i.e. ']'). function Parse_Table (Value : out TOML_Value) return Boolean; -- Parse an inline table and put it in Value. -- -- This assumes that the first token that constitutes the table (i.e. '{') -- is in Token_Buffer. When this returns, Token_Buffer contains the last -- token that was used to parse the value (i.e. '}'). ------------------ -- Create_Error -- ------------------ function Create_Error (Message : String; Location : Source_Location := No_Location) return Boolean is begin Result := (Success => False, Message => To_Unbounded_String (Message), Location => (if Location = No_Location then Codepoint_Buffer.Location else Location)); return False; end Create_Error; ------------------------- -- Create_Lexing_Error -- ------------------------- function Create_Lexing_Error (Message : String := "invalid token") return Boolean is begin return Create_Error (Message, Token_Buffer.Location); end Create_Lexing_Error; ------------------------- -- Create_Syntax_Error -- ------------------------- function Create_Syntax_Error (Message : String := "invalid syntax") return Boolean is begin return Create_Error (Message, Token_Buffer.Location); end Create_Syntax_Error; -------------------- -- Read_Codepoint -- -------------------- function Read_Codepoint return Boolean is use type Interfaces.Unsigned_32; Error_Message : constant String := "invalid UTF-8 encoding"; EOF : Boolean; Char : Character; -- Holders for Get OUT formals Bytes_Count : Positive; -- Number of bytes that encode the codepoint to read Min_Codepoint : constant array (1 .. 4) of Interfaces.Unsigned_32 := (1 => 16#00#, 2 => 16#80#, 3 => 16#80_00#, 4 => 16#1_00_00#); -- For each Bytes_Count, smallest codepoint that is allowed Byte : Interfaces.Unsigned_32; -- Numeric view for Char Result : Interfaces.Unsigned_32 := 0; -- Numeric view for the Result begin -- If we are supposed to re-emit the previously read codepoint, do -- nothing more. if Codepoint_Buffer.To_Reemit then Codepoint_Buffer.To_Reemit := False; return True; end if; -- Try to read the first byte Get (Stream, EOF, Char); if EOF then Codepoint_Buffer := (EOF => True, To_Reemit => False, Location => (Codepoint_Buffer.Location.Line, Codepoint_Buffer.Location.Column + 1)); return True; else Byte := Character'Pos (Char); end if; -- ASCII characters are always one byte long, so we can handle them -- right now: process ASCII's control characters. case Char is when ASCII.NUL .. ASCII.BS | ASCII.VT | ASCII.FF | ASCII.SO .. ASCII.US | ASCII.DEL => return Create_Error ("invalid ASCII control character"); when ASCII.CR => -- If this is a carriage return, discarding after checking that it is -- followed by a linefeed. Get (Stream, EOF, Char); if EOF or else Char /= ASCII.LF then return Create_Error ("invalid stray carriage return"); end if; Byte := Character'Pos (Char); when others => null; end case; -- Special handling of source location update occurs only with pure -- ASCII characters, so we can handle it here, too. if Codepoint_Buffer.Location = No_Location then Codepoint_Buffer.Location := (1, 1); else case Char is when ASCII.LF => Codepoint_Buffer.Location := (Codepoint_Buffer.Location.Line + 1, 1); when ASCII.HT => declare Column : Natural := Codepoint_Buffer.Location.Column; Column_Mod : constant Natural := Column mod Tab_Stop; begin if Column_Mod = 0 then Column := Column + Tab_Stop; else Column := Column + Tab_Stop - Column_Mod; end if; Codepoint_Buffer.Location.Column := Column; end; when others => Codepoint_Buffer.Location.Column := Codepoint_Buffer.Location.Column + 1; end case; end if; -- Its leading bits tell us how many bytes are to be expected if (Byte and 2#1000_0000#) = 0 then Bytes_Count := 1; Result := Byte and 2#0111_1111#; elsif (Byte and 2#1110_0000#) = 2#1100_0000# then Bytes_Count := 2; Result := Byte and 2#0001_1111#; elsif (Byte and 2#1111_0000#) = 2#1110_0000# then Bytes_Count := 3; Result := Byte and 2#0000_1111#; elsif (Byte and 2#1111_1000#) = 2#1111_0000# then Bytes_Count := 4; Result := Byte and 2#0000_0111#; else return Create_Error (Error_Message); end if; -- Read the remaining bytes. We know how many we must read, so if we -- reach EOF in the process, we know it's an error. for I in 2 .. Bytes_Count loop Get (Stream, EOF, Char); Byte := Character'Pos (Char); if EOF or else (Byte and 2#1100_0000#) /= 2#1000_0000# then return Create_Error (Error_Message); end if; Result := 64 * Result + (Byte and 2#0011_1111#); end loop; -- Check that the codepoint is as big as the number of bytes allows if Result < Min_Codepoint (Bytes_Count) then return Create_Error (Error_Message); end if; Codepoint_Buffer.Codepoint := Wide_Wide_Character'Val (Result); -- Reject surrogate codepoints if Codepoint_Buffer.Codepoint in WW_Surrogates then return Create_Error ("surrogate codepoints are invalid"); end if; return True; end Read_Codepoint; ---------------------- -- Reemit_Codepoint -- ---------------------- procedure Reemit_Codepoint is begin Codepoint_Buffer.To_Reemit := True; end Reemit_Codepoint; ---------------- -- Read_Token -- ---------------- function Read_Token (Key_Expected : Boolean) return Boolean is begin -- If we are supposed to re-emit the previously read token, do nothing -- more. if Token_Buffer.To_Reemit then Token_Buffer.To_Reemit := False; return True; end if; loop -- The location for this token is the location of the codepoint -- cursor before reading it. Special case for the first token: -- codepoint location is not initialized yet, so use the actual first -- location. Token_Buffer.Location := Codepoint_Buffer.Location; if Token_Buffer.Location = No_Location then Token_Buffer.Location := (1, 1); end if; -- Try to read the first codepoint. If we reached the end of file, -- communicate this fact to the caller and stop there. if not Read_Codepoint then return False; end if; if Codepoint_Buffer.EOF then Token_Buffer := (EOF => True, To_Reemit => False); return True; end if; -- Otherwise, see what we can do with this codepoint case Codepoint_Buffer.Codepoint is -- If this is a newline (either LF or CR-LF), return the -- corresponding token. when WW_Linefeed => Token_Buffer.Location := Codepoint_Buffer.Location; Token_Buffer.Token := (Kind => Newline); return True; when WW_Carriage_Return => if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("trailing CR"); elsif Codepoint_Buffer.Codepoint /= WW_Linefeed then return Create_Lexing_Error ("stray CR"); end if; Token_Buffer.Token := (Kind => Newline); return True; -- Skip whitespaces when WW_Tab | ' ' => null; -- Skip comments. Note that the end of file is allowed to occur in -- a comment, i.e. without a newline at the end. when '#' => Comment_Loop : loop if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then Token_Buffer := (EOF => True, To_Reemit => False); return True; elsif Codepoint_Buffer.Codepoint = WW_Linefeed then -- Don't forget to re-emit the linefeed: it is not part -- of the comment itself Reemit_Codepoint; exit Comment_Loop; end if; end loop Comment_Loop; -- Parse no-text tokens that cannot be keys when '=' => Token_Buffer.Token := (Kind => Equal); return True; when '.' => Token_Buffer.Token := (Kind => Dot); return True; when ',' => Token_Buffer.Token := (Kind => Comma); return True; when '{' => Token_Buffer.Token := (Kind => Curly_Bracket_Open); return True; when '}' => Token_Buffer.Token := (Kind => Curly_Bracket_Close); return True; when '[' => if not Read_Codepoint then return False; elsif Key_Expected and then not Codepoint_Buffer.EOF and then Codepoint_Buffer.Codepoint = '[' then Token_Buffer.Token := (Kind => Double_Square_Bracket_Open); else Reemit_Codepoint; Token_Buffer.Token := (Kind => Square_Bracket_Open); end if; return True; when ']' => if not Read_Codepoint then return False; elsif Key_Expected and then not Codepoint_Buffer.EOF and then Codepoint_Buffer.Codepoint = ']' then Token_Buffer.Token := (Kind => Double_Square_Bracket_Close); else Reemit_Codepoint; Token_Buffer.Token := (Kind => Square_Bracket_Close); end if; return True; -- Parse string literals when '"' | ''' => return Read_Quoted_String; -- The rest is potential bare keys (bare keys, integer literals, -- boolean literals, ...). when '0' .. '9' => if Key_Expected then return Read_Bare_Key; else return Read_Number_Like; end if; when 'A' .. 'Z' | 'a' .. 'z' | '_' => if Key_Expected then return Read_Bare_Key; end if; -- Detect keywords: "false" or "true". TODO: handle "inf" and -- "nan". case Codepoint_Buffer.Codepoint is when 'f' => return Read_Keyword ("false", False_Keyword); when 't' => return Read_Keyword ("true", True_Keyword); when 'n' => return Read_Special_Float ("nan", NaN, True); when 'i' => return Read_Special_Float ("inf", Infinity, True); when others => return Create_Lexing_Error; end case; when '+' => return Read_Number_Like; when '-' => if Key_Expected then return Read_Bare_Key; else return Read_Number_Like; end if; when others => return Create_Lexing_Error; end case; end loop; end Read_Token; ------------------ -- Reemit_Token -- ------------------ procedure Reemit_Token is begin Token_Buffer.To_Reemit := True; end Reemit_Token; -------------------- -- Append_As_UTF8 -- -------------------- procedure Append_As_UTF8 (Codepoint : Wide_Wide_Character) is use Interfaces; Ordinal : constant Unsigned_32 := Wide_Wide_Character'Pos (Codepoint); function Bit_Slice (LSB, Width : Natural) return Unsigned_8; -- Return the slice of bits in Codepoint/Ordinal starting at the given -- 0-based index Least Significant Bit (LSB) and that contains Width -- bits. function Bit_Slice (LSB, Width : Natural) return Unsigned_8 is Shifted : constant Unsigned_32 := Shift_Right (Ordinal, LSB); Mask : constant Unsigned_32 := 2 ** Width - 1; begin return Unsigned_8 (Shifted and Mask); end Bit_Slice; Bytes : array (1 .. 4) of Unsigned_8; Last_Byte : Positive; begin case Ordinal is when 16#0000# .. 16#007F# => Bytes (1) := Bit_Slice (0, 7); Last_Byte := 1; when 16#0080# .. 16#07FF# => Bytes (1) := 2#1100_0000# or Bit_Slice (6, 5); Bytes (2) := 2#1000_0000# or Bit_Slice (0, 6); Last_Byte := 2; when 16#0800# .. 16#FFFF# => Bytes (1) := 2#1110_0000# or Bit_Slice (12, 4); Bytes (2) := 2#1000_0000# or Bit_Slice (6, 6); Bytes (3) := 2#1000_0000# or Bit_Slice (0, 6); Last_Byte := 3; when 16#1_0000# .. 16#10_FFFF# => Bytes (1) := 2#1111_0000# or Bit_Slice (18, 3); Bytes (2) := 2#1000_0000# or Bit_Slice (12, 6); Bytes (3) := 2#1000_0000# or Bit_Slice (6, 6); Bytes (4) := 2#1000_0000# or Bit_Slice (0, 6); Last_Byte := 4; when 16#11_0000# .. Unsigned_32'Last => -- Given that Codepoint comes from decoded UTF-8, this alternative -- should be unreachable. raise Program_Error; end case; declare Str : String (1 .. Last_Byte) with Import, Address => Bytes'Address; begin Append (Token_Buffer.Token.String_Value, Str); end; end Append_As_UTF8; ----------------- -- Digit_Value -- ----------------- function Digit_Value (Codepoint : Wide_Wide_Character) return Interfaces.Unsigned_64 is use Interfaces; CP : constant Unsigned_64 := Wide_Wide_Character'Pos (Codepoint_Buffer.Codepoint); begin case Codepoint is when '0' .. '9' => return CP - Wide_Wide_Character'Pos ('0'); when 'a' .. 'f' => return CP - Wide_Wide_Character'Pos ('a') + 10; when 'A' .. 'F' => return CP - Wide_Wide_Character'Pos ('A') + 10; when others => raise Program_Error; end case; end Digit_Value; ---------------------------------- -- Read_Unicode_Escape_Sequence -- ---------------------------------- function Read_Unicode_Escape_Sequence (Location : Source_Location) return Boolean is use Interfaces; Size : constant Positive := (if Codepoint_Buffer.Codepoint = 'u' then 4 else 8); -- Number of digits to read CP : Unsigned_32; -- Temporary buffer for the codepoint we just read Result : Unsigned_32 := 0; -- Denoted Unicode codepoint begin for I in 1 .. Size loop if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Error ("unterminated Unicode escape sequence", Location); end if; -- Turn the hexadecimal digit we just read into a number and add it -- to Result, or raise an error if this is not a valid digit. CP := Wide_Wide_Character'Pos (Codepoint_Buffer.Codepoint); declare Denoted_Digit : Unsigned_32; begin if Codepoint_Buffer.Codepoint in '0' .. '9' then Denoted_Digit := CP - Wide_Wide_Character'Pos ('0'); elsif Codepoint_Buffer.Codepoint in 'a' .. 'f' then Denoted_Digit := CP - Wide_Wide_Character'Pos ('a') + 10; elsif Codepoint_Buffer.Codepoint in 'A' .. 'F' then Denoted_Digit := CP - Wide_Wide_Character'Pos ('A') + 10; else return Create_Error ("invalid Unicode escape sequence", Location); end if; Result := 16 * Result + Denoted_Digit; end; end loop; declare Codepoint : constant Wide_Wide_Character := Wide_Wide_Character'Val (Result); begin -- Reject surrogate codepoints if Codepoint in WW_Surrogates then return Create_Error ("surrogate codepoints are invalid", Location); end if; Append_As_UTF8 (Codepoint); return True; end; end Read_Unicode_Escape_Sequence; ------------------------ -- Read_Quoted_String -- ------------------------ function Read_Quoted_String return Boolean is Delimiter : constant Wide_Wide_Character := Codepoint_Buffer.Codepoint; Is_Literal : constant Boolean := Delimiter = '''; Is_Multiline : Boolean := False; function Unterminated_String return Boolean is (Create_Error ("unterminated string")); function Skip_Line_Ending_Backslash return Boolean; -- Assuming that, in a multiline string, we just processed a backslash -- followed by a whitespace or a line feed (i.e. a line ending -- backslash), skip all the following whitespaces/line feeds/backslashes -- that should be ignored when processing the string. Return whether -- successful (i.e. if there is no syntax error). Location : Source_Location; -------------------------------- -- Skip_Line_Ending_Backslash -- -------------------------------- function Skip_Line_Ending_Backslash return Boolean is Line_Ended : Boolean := Codepoint_Buffer.Codepoint = WW_Linefeed; -- Whether we processed a line feed after the last backslash. We keep -- track of this to make sure that only whitespaces can follow line -- ending backslashes. begin loop if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Unterminated_String; elsif Codepoint_Buffer.Codepoint not in ' ' | WW_Tab | WW_Linefeed then -- We found something that must not be -- discarded: re-emit it so that the next -- loop iteration processes it. Reemit_Codepoint; exit; elsif Line_Ended and then Codepoint_Buffer.Codepoint = '\' then -- On a separate line, we found a new line ending backslash: -- skip it and only expect whitespaces before the next new -- line. Line_Ended := False; else Line_Ended := Line_Ended or else Codepoint_Buffer.Codepoint in WW_Linefeed; end if; end loop; -- There must be a line feed before the first non-whitespace -- codepoint that follows a line ending backslash. return (Line_Ended or else Create_Error ("invalid escape sequence", Location)); end Skip_Line_Ending_Backslash; begin -- Read the potential first character of this string. if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Error ("unterminated string"); end if; Token_Buffer.Token := (Kind => String_Literal, String_Format => (if Is_Literal then Literal_String else Basic_String), others => <>); -- If we have a second delimiter, then check if this is a multi-line -- string. if Codepoint_Buffer.Codepoint = Delimiter then if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= Delimiter then -- We found two delimiters not followed by a third one: this -- designates an empty string. Reemit_Codepoint; return True; else -- We have three consecutive delimiters: this is a multiline -- string. Is_Multiline := True; Token_Buffer.Token.String_Format := (if Is_Literal then Multiline_Literal_String else Multiline_Basic_String); end if; else -- Never mind: no second delimiter, so put this codepoint back to be -- read again in the scanning loop. Reemit_Codepoint; end if; -- Now, go through all codepoints until we find the closing -- delimiter(s). loop if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Error ("unterminated string"); end if; Location := Codepoint_Buffer.Location; case Codepoint_Buffer.Codepoint is when '"' | ''' => if Codepoint_Buffer.Codepoint /= Delimiter then -- If this character is not the string delimiter, include it -- as-is in the denoted string. Append_As_UTF8 (Codepoint_Buffer.Codepoint); elsif not Is_Multiline then -- Otherwise, if the string is not multi-line, it's the end -- of our string. return True; -- At this point, we know this string is multiline: look for -- the two next characters: if they are all delimiters, this -- is the end of our string. Otherwise, continue reading -- them... elsif not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Unterminated_String; elsif Codepoint_Buffer.Codepoint /= Delimiter then -- The second delimiter is missing: append the first one -- and schedule to re-examine the current codepoint in -- another loop iteration. Append_As_UTF8 (Delimiter); Reemit_Codepoint; -- Read the third character... elsif not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Unterminated_String; elsif Codepoint_Buffer.Codepoint /= Delimiter then -- The third delimiter is missing: append the first two ones -- and schedule to re-examine the current codepoint in -- another loop iteration. Append_As_UTF8 (Delimiter); Append_As_UTF8 (Delimiter); Reemit_Codepoint; -- We just got the third delimiter, but we can still have (a) -- one or (b) two more delimiters: in that case the first (a) -- one or (b) two are part of the string, and the last three -- are closing the string. So try reading a fourth delimiter... elsif not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= Delimiter then -- No fourth delimiter: put back the EOF/codepoint and -- return a successful multiline string parsing. Reemit_Codepoint; return True; else -- We got a fourth delimiter: append one to the denoted -- string and try to read the fifth one... Append_As_UTF8 (Delimiter); if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= Delimiter then -- Just like above, if we could not get one, just put the -- codepoint back and return success. Reemit_Codepoint; else -- We got a fifth delimiter: append yet another delimiter -- (the second one) to the denoted string and consider -- the read done. Append_As_UTF8 (Delimiter); end if; return True; end if; when '\' => -- If this is a literal string, we have a literal backslash. if Is_Literal then Append_As_UTF8 (Codepoint_Buffer.Codepoint); -- This starts an escape sequence: read the next character to -- find out which. elsif not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Unterminated_String; else case Codepoint_Buffer.Codepoint is when 'b' => Append_As_UTF8 (WW_Backspace); when 't' => Append_As_UTF8 (WW_Tab); when 'n' => Append_As_UTF8 (WW_Linefeed); when 'f' => Append_As_UTF8 (WW_Form_Feed); when 'r' => Append_As_UTF8 (WW_Carriage_Return); when '"' => Append_As_UTF8 ('"'); when '\' => Append_As_UTF8 ('\'); when 'u' | 'U' => if not Read_Unicode_Escape_Sequence (Location) then return False; end if; when ' ' | WW_Tab | WW_Linefeed => -- This is valid only for multi-line strings. If -- literal, just append these codepoints. Otherwise we -- we just found a "line ending backslash": discard -- all the whitespace characters we find next. if not Is_Multiline then return Unterminated_String; elsif Is_Literal then Append_As_UTF8 (WW_Linefeed); elsif not Skip_Line_Ending_Backslash then return False; end if; when others => return Create_Error ("invalid escape sequence", Location); end case; end if; when WW_Control_Characters => -- Linefeeds are allowed only for multi-line strings. if Codepoint_Buffer.Codepoint = WW_Linefeed and then Is_Multiline then -- When they are the first codepoint after the string -- delimiter, they are discarded. if Length (Token_Buffer.Token.String_Value) > 0 then Append_As_UTF8 (WW_Linefeed); end if; elsif Codepoint_Buffer.Codepoint = WW_Tab then -- Horizontal tabs are always allowed Append_As_UTF8 (WW_Tab); else return Create_Error ("invalid string", Location); end if; when others => Append_As_UTF8 (Codepoint_Buffer.Codepoint); end case; end loop; end Read_Quoted_String; ---------------------- -- Read_Number_Like -- ---------------------- function Read_Number_Like return Boolean is use Interfaces; type Any_Format is (Decimal, Hexadecimal, Binary, Octal); Format : Any_Format := Decimal; -- Format for the integer to parse Base : constant array (Any_Format) of Unsigned_64 := (Decimal => 10, Hexadecimal => 16, Binary => 2, Octal => 8); type Any_Sign is (None, Positive, Negative); Sign : Any_Sign := None; Sign_Explicit : Boolean := False; -- Sign for the integer to parse, and whether it was explicit Abs_Value : Interfaces.Unsigned_64 := 0; -- Absolute value for the integer that is parsed Digit_Count : Natural := 0; -- Number of digit codepoints consumed Had_Underscore : Boolean := False; -- Whether we found an underscore at all for this token Leading_Zero : Boolean := False; -- Whether this number starts with a zero Just_Passed_Underscore : Boolean := False; -- Whether the last codepoint processed was an underscore function Reject_Leading_Zero return Boolean; -- If Leading_Zero is true, create an error and return False. Return -- true otherwise. function Reject_Passed_Underscore return Boolean; -- If Just_Passed_Underscore is true, create an error and return False. -- Return true otherwise. ------------------------- -- Reject_Leading_Zero -- ------------------------- function Reject_Leading_Zero return Boolean is begin if Leading_Zero then return Create_Lexing_Error ("leading zeros are not allowed in decimals"); end if; return True; end Reject_Leading_Zero; ------------------------------ -- Reject_Passed_Underscore -- ------------------------------ function Reject_Passed_Underscore return Boolean is begin if Just_Passed_Underscore then return Create_Lexing_Error ("underscores must be surrounded by digits"); end if; return True; end Reject_Passed_Underscore; function Too_Large_Error return Boolean is (Create_Error ("too large integer", Token_Buffer.Location)); begin Token_Buffer.Token := (Kind => Integer_Literal, Integer_Value => 0); -- Decode the sign, if any if Codepoint_Buffer.Codepoint in '+' | '-' then Sign := (if Codepoint_Buffer.Codepoint = '+' then Positive else Negative); Sign_Explicit := True; if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error; end if; end if; -- If this token starts with 0, we have either: -- -- * just 0, i.e. the next character cannot be a digit as leading zeros -- are forbidden. -- -- * 'b' (for binary literals), 'x' (for hexadecimal) or 'o' (for -- octal). if Codepoint_Buffer.Codepoint = '0' then if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then Reemit_Codepoint; return True; end if; case Codepoint_Buffer.Codepoint is when '_' | '0' .. '9' => Digit_Count := Digit_Count + 1; Leading_Zero := True; when 'b' => Format := Binary; when 'o' => Format := Octal; when 'x' => Format := Hexadecimal; when '.' | 'e' | 'E' => return Read_Float (Sign /= Negative, Abs_Value); when others => -- Consider all other codepoints as token separators Reemit_Codepoint; return True; end case; -- Explicit signs are valid only for numbers in decimal form if Format /= Decimal and then Sign_Explicit then return Create_Lexing_Error ("explicit sign not allowed but for decimals"); end if; -- If we had a format specifier sequence, read the next codepoint, -- which will be the first digit of the number to read. if Format /= Decimal then if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then Reemit_Codepoint; return True; elsif Codepoint_Buffer.Codepoint = '_' then return Create_Lexing_Error ("underscores must be surrounded by digits"); end if; end if; -- Check for special float values ("nan" and "inf") elsif Codepoint_Buffer.Codepoint = 'n' then return Read_Special_Float ("nan", NaN, Sign /= Negative); elsif Codepoint_Buffer.Codepoint = 'i' then return Read_Special_Float ("inf", Infinity, Sign /= Negative); end if; -- Now read and decode all digits for this token loop declare Is_Digit : Boolean := False; Digit : Unsigned_64; begin -- See if we have a digit case Codepoint_Buffer.Codepoint is when '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' => if Format = Decimal and then Codepoint_Buffer.Codepoint in 'e' | 'E' then return Reject_Leading_Zero and then Reject_Passed_Underscore and then Read_Float (Sign /= Negative, Abs_Value); end if; Is_Digit := True; Digit := Digit_Value (Codepoint_Buffer.Codepoint); when '_' => Had_Underscore := True; if Just_Passed_Underscore then return Reject_Passed_Underscore; else Just_Passed_Underscore := True; end if; when 'g' .. 'z' | 'G' .. 'Z' | WW_Non_ASCII => -- These codepoints cannot start a new token and yet they -- are invalid elements for integer literals: this is an -- error. return Create_Lexing_Error; when '-' | ':' => -- If we had no sign, no underscore and no base specifier, -- we have a local date ('-') or local time (':'). if Sign /= None or else Format /= Decimal or else Had_Underscore then Reemit_Codepoint; exit; end if; if Codepoint_Buffer.Codepoint = '-' then return Read_Date (Abs_Value, Digit_Count); else return Read_Local_Time (Abs_Value, Digit_Count, Read_Timezone => False); end if; when '.' => -- If we had no base specifier, we have a floating point -- number. -- -- Floating point numbers can only use decimal digits, and -- there must be at least one digit before the dot. if Format /= Decimal or Digit_Count = 0 then return Create_Lexing_Error ("invalid float"); end if; return Reject_Leading_Zero and then Reject_Passed_Underscore and then Read_Float (Sign /= Negative, Abs_Value); when others => -- If we end up here, either we found the beginning of a new -- token, or a token separator: stop reading the integer -- right here. Reemit_Codepoint; exit; end case; -- Decode the digit (if we found one) if Is_Digit then Digit_Count := Digit_Count + 1; if Digit >= Base (Format) then return Create_Lexing_Error; end if; declare Next_Value : Unsigned_64; begin begin Next_Value := Base (Format) * Abs_Value + Digit; exception when Constraint_Error => return Too_Large_Error; end; Abs_Value := Next_Value; end; Just_Passed_Underscore := False; end if; -- Read the next digit. Consider this integer token done if we -- reached the end of stream. if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then Reemit_Codepoint; exit; end if; end; end loop; -- If we reach this point, we know that the token is an integer (it's -- not a date or something else). if not Reject_Leading_Zero or else not Reject_Passed_Underscore then return False; end if; -- Apply the sign, making sure that there is no overflow in the process declare Rel_Value : Integer_64; begin if Sign = Negative then if Abs_Value <= Unsigned_64 (Integer_64'Last) then Rel_Value := -Integer_64 (Abs_Value); elsif Abs_Value = Unsigned_64 (Integer_64'Last) + 1 then Rel_Value := Integer_64'First; else return Too_Large_Error; end if; else if Abs_Value <= Unsigned_64 (Integer_64'Last) then Rel_Value := Integer_64 (Abs_Value); else return Too_Large_Error; end if; end if; Token_Buffer.Token.Integer_Value := Any_Integer (Rel_Value); return True; end; end Read_Number_Like; ------------------------- -- Read_Datetime_Field -- ------------------------- function Read_Datetime_Field (What : String; Digit_Count : Positive; Base_Value : Interfaces.Unsigned_64; Base_Digits : Natural; Value : out Interfaces.Unsigned_64) return Boolean is use Interfaces; function Create_Error return Boolean is (Create_Lexing_Error ("invalid " & What)); begin if Base_Digits > Digit_Count then return Create_Error; end if; Value := Base_value; for DC in Base_Digits + 1 .. Digit_Count loop -- Decode the current digit and add it to the decoded value if Codepoint_Buffer.Codepoint not in '0' .. '9' then return Create_Error; end if; Value := 10 * Value + Digit_Value (Codepoint_Buffer.Codepoint); -- Read the next digit. We accept EOF only if we were able to read -- as many digits as requested. if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then exit when DC = Digit_Count; return Create_Error; end if; end loop; -- This check is not necessary for correctness. It improves user -- diagnostics: if a digit follows the last expected digit, we know -- there is an error. if not Codepoint_Buffer.EOF and then Codepoint_Buffer.Codepoint in '0' .. '9' then return Create_Error; end if; -- If we came across a codepoint, re-emit it so that the lexing loop -- can call Read_Token once more. if Codepoint_Buffer.EOF then Reemit_Codepoint; end if; return True; end Read_Datetime_Field; --------------- -- Read_Date -- --------------- function Read_Date (Base_Value : Interfaces.Unsigned_64; Base_Digits : Natural) return Boolean is use Interfaces; subtype Year_Range is Unsigned_64 range Unsigned_64 (Any_Year'First) .. Unsigned_64 (Any_Year'Last); subtype Month_Range is Unsigned_64 range Unsigned_64 (Any_Month'First) .. Unsigned_64 (Any_Month'Last); subtype Day_Range is Unsigned_64 range Unsigned_64 (Any_Day'First) .. Unsigned_64 (Any_Day'Last); Year, Month, Day : Unsigned_64 := Base_Value; Datetime : Any_Local_Datetime; begin -- Finish reading the year and consume the following dash if not Read_Datetime_Field ("year", 4, Base_Value, Base_Digits, Year) then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= '-' then return Create_Lexing_Error ("invalid year"); end if; -- Now read the month and consume the following dash if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("invalid month"); elsif not Read_Datetime_Field ("month", 2, 0, 0, Month) then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= '-' then return Create_Lexing_Error ("invalid month"); end if; -- Now read the day if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("invalid day"); elsif not Read_Datetime_Field ("day", 2, 0, 0, Day) then return False; end if; -- Check that all fields are in range. -- -- TODO: check that the date they represent is valid. This is not -- trivial as TOML can handle all years between 0 and 9999 while -- Ada.Calendar supports only 1901 through 2399. if Year not in Year_Range then return Create_Lexing_Error ("out of range year"); elsif Month not in Month_Range then return Create_Lexing_Error ("out of range month"); elsif Day not in Day_Range then return Create_Lexing_Error ("out of range day"); end if; Datetime.Date := (Year => Any_Year (Year), Month => Any_Month (Month), Day => Any_Day (Day)); Token_Buffer.Token := (Kind => Local_Date_Literal, Local_Date_Value => Datetime.Date); -- Now try to read a local time: if there is one, we can create a local -- datetime, otherwise it's just a local date. if not Codepoint_Buffer.EOF and then Codepoint_Buffer.Codepoint in 'T' | 't' then -- If the first codepoint after the date is 'T', then we know we have -- a local time ahead. if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("truncated datetime"); end if; elsif not Codepoint_Buffer.EOF and then Codepoint_Buffer.Codepoint = ' ' then -- If the first codepoint after the date is ' ', then we know we have -- a local time ahead iff a digit follows this space. Otherwise, just -- consider it's the beginning of another token. if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint not in '0' .. '9' then Reemit_Codepoint; return True; end if; else Reemit_Codepoint; return True; end if; -- At this point, we know there is a local time ahead, so try to read it return Read_Local_Time (0, 0, Read_Timezone => True); end Read_Date; --------------------- -- Read_Local_Time -- --------------------- function Read_Local_Time (Base_Value : Interfaces.Unsigned_64; Base_Digits : Natural; Read_Timezone : Boolean) return Boolean is use Interfaces; subtype Hour_Range is Unsigned_64 range Unsigned_64 (Any_Hour'First) .. Unsigned_64 (Any_Hour'Last); subtype Minute_Range is Unsigned_64 range Unsigned_64 (Any_Minute'First) .. Unsigned_64 (Any_Minute'Last); subtype Second_Range is Unsigned_64 range Unsigned_64 (Any_Second'First) .. Unsigned_64 (Any_Second'Last); subtype Millisecond_Range is Unsigned_64 range Unsigned_64 (Any_Millisecond'First) .. Unsigned_64 (Any_Millisecond'Last); Hour, Minute, Second, Millisecond : Unsigned_64 := Base_Value; Time : Any_Local_Time; begin -- Finish reading the hour and consume the following colon if not Read_Datetime_Field ("hour", 2, Base_Value, Base_Digits, Hour) then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= ':' then return Create_Lexing_Error ("invalid hour"); end if; -- Now read the minute and consume the following colon if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("invalid minute"); elsif not Read_Datetime_Field ("minute", 2, 0, 0, Minute) then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= ':' then return Create_Lexing_Error ("invalid minute"); end if; -- Now read the second if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("invalid second"); elsif not Read_Datetime_Field ("second", 2, 0, 0, Second) then return False; end if; -- If present, read a dot, and then read the millisecond Millisecond := 0; if Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= '.' then Reemit_Codepoint; elsif not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("truncated millisecond"); else -- Read at least 1 digit and at most 3 digits, then discard other -- digits. declare Digit_Count : Natural := 0; begin while not Codepoint_Buffer.EOF and then Codepoint_Buffer.Codepoint in '0' .. '9' loop if Digit_Count < 3 then Digit_Count := Digit_Count + 1; Millisecond := (10 * Millisecond + Digit_Value (Codepoint_Buffer.Codepoint)); end if; if not Read_Codepoint then return False; end if; end loop; -- Artificially append zeros so that what we really get is the -- number of milliseconds (".1" should give 100 milliseconds, not -- just 1). while Digit_Count < 3 loop Digit_Count := Digit_Count + 1; Millisecond := 10 * Millisecond; end loop; Reemit_Codepoint; end; end if; -- Check that all fields are in range if Hour not in Hour_Range then return Create_Lexing_Error ("out of range hour"); elsif Minute not in Minute_Range then return Create_Lexing_Error ("out of range minute"); elsif Second not in Second_Range then return Create_Lexing_Error ("out of range second"); end if; -- The millisecond is read with 3 digits, and that's exactly what the -- millisecond range allows so this should be always true. pragma Assert (Millisecond in Millisecond_Range); Time := (Hour => Any_Hour (Hour), Minute => Any_Minute (Minute), Second => Any_Second (Second), Millisecond => Any_Millisecond (Millisecond)); if not Read_Timezone then Token_Buffer.Token := (Kind => Local_Time_Literal, Local_Time_Value => Time); return True; end if; -- We were asked to read the timezone information: assume the token -- buffer contains a date and complete it with the time, and the -- timezone if present. declare Datetime : constant Any_Local_Datetime := (Date => Token_Buffer.Token.Local_Date_Value, Time => Time); -- Temporaries to build the local offset value that is read Positive_Offset : Boolean; -- Whether the offset is positive (starts with '+' or 'Z'). Note that -- RFC 3339 states that a negative offset with zero minutes means -- "unknown local offset". Hour_Offset : Unsigned_64 := 0; Minute_Offset : Unsigned_64 := 0; -- Individual temporaries for the amount of ours and of minutes for -- the local offset. begin Token_Buffer.Token := (Kind => Local_Datetime_Literal, Local_Datetime_Value => Datetime); if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint not in 'Z' | 'z' | '+' | '-' then Reemit_Codepoint; return True; end if; if Codepoint_Buffer.Codepoint in 'Z' | 'z' then Positive_Offset := True; else Positive_Offset := Codepoint_Buffer.Codepoint = '+'; -- Consume the hour offset and consume the colon if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("truncated hour offset"); elsif not Read_Datetime_Field ("hour offset", 2, 0, 0, Hour_Offset) then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= ':' then return Create_Lexing_Error ("invalid hour offset"); end if; -- Now consume the minute offset if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Create_Lexing_Error ("truncated minute offset"); elsif not Read_Datetime_Field ("minute offset", 2, 0, 0, Minute_Offset) then return False; end if; -- Reemit the last codepoint as Read_Datetime_Field consumes the -- one that appears right after the last codepoint that is part of -- the datetime field. Reemit_Codepoint; end if; -- Check ranges for hours/minutes if Hour_Offset not in Hour_Range then return Create_Lexing_Error ("out of range hour offset"); elsif Minute_Offset not in Minute_Range then return Create_Lexing_Error ("out of range minute offset"); end if; -- Gather all decoded data to format the result declare Absolute_Offset : constant Any_Local_Offset := Any_Local_Offset (60 * Hour_Offset + Minute_Offset); Offset : constant Any_Local_Offset := (if Positive_Offset then Absolute_Offset else -Absolute_Offset); Offset_Datetime : constant Any_Offset_Datetime := (Datetime => Datetime, Offset => Offset, Unknown_Offset => Offset = 0 and then not Positive_Offset); begin Token_Buffer.Token := (Kind => Offset_Datetime_Literal, Offset_Datetime_Value => Offset_Datetime); return True; end; end; end Read_Local_Time; ---------------- -- Read_Float -- ---------------- function Read_Float (Positive : Boolean; Integer_Value : Interfaces.Unsigned_64) return Boolean is function Invalid_Float return Boolean is (Create_Lexing_Error ("invalid float")); function Too_Large return Boolean is (Create_Lexing_Error ("too large float")); function Read_Simple_Integer (Value : out Interfaces.Unsigned_64) return Boolean with Pre => not Codepoint_Buffer.EOF; -- Helper to read a simple decimal integer, including underscores ------------------------- -- Read_Simple_Integer -- ------------------------- function Read_Simple_Integer (Value : out Interfaces.Unsigned_64) return Boolean is use type Interfaces.Unsigned_64; Empty : Boolean := True; -- Whether we read no digit so far Previous_Is_Underscore : Boolean := True; -- Given that it is forbidden to have a leading underscore, do as if -- we just had an underscore at the beginning so that we need to -- check only for consecutive underscores. begin Value := 0; -- Read and decode all digits that follow in the stream while not Codepoint_Buffer.EOF and then Codepoint_Buffer.Codepoint in '0' .. '9' | '_' loop -- Discard underscores, yet do not allow consecutive ones if Codepoint_Buffer.Codepoint = '_' then if Previous_Is_Underscore then return Invalid_Float; else Previous_Is_Underscore := True; end if; -- Decode digits to build Value as we go. Consider the number too -- large as soon as it is bigger than half the largest possible -- unsigned 64 value: bigger numbers are unlikely and this allows -- us to negate values safely later on. else begin Value := 10 * Value + Digit_Value (Codepoint_Buffer.Codepoint); if Value > Interfaces.Unsigned_64'Last / 2 then return Too_Large; end if; exception when Constraint_Error => return Too_Large; end; Empty := False; Previous_Is_Underscore := False; end if; if not Read_Codepoint then return Invalid_Float; end if; end loop; -- We expect at least one digit, and the last codepoint must not be -- an underscore. if Empty or else Previous_Is_Underscore then return Invalid_Float; else return True; end if; end Read_Simple_Integer; Fractional_Value : Interfaces.Unsigned_64 := 0; Exponent : Interfaces.Unsigned_64 := 0; Exponent_Positive : Boolean := True; Result : Any_Float := (Kind => Regular, Value => <>); begin -- Read the fractional part, if present if Codepoint_Buffer.Codepoint = '.' then if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Invalid_Float; elsif not Read_Simple_Integer (Fractional_Value) then return False; end if; end if; -- Read the exponent, if present if not Codepoint_Buffer.EOF and then Codepoint_Buffer.Codepoint in 'e' | 'E' then if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Invalid_Float; end if; -- First read the sign if Codepoint_Buffer.Codepoint in '+' | '-' then Exponent_Positive := Codepoint_Buffer.Codepoint /= '-'; if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF then return Invalid_Float; end if; end if; -- Then the exponent absolute value if not Read_Simple_Integer (Exponent) then return False; end if; end if; -- Reemit the last codepoint: it is not part of the float token and the -- next token reading iteration needs to read it. Reemit_Codepoint; -- Use all lexed parts to create a floating point value declare function Image (Positive : Boolean; Value : Interfaces.Unsigned_64) return String; ----------- -- Image -- ----------- function Image (Positive : Boolean; Value : Interfaces.Unsigned_64) return String is Result : constant String := Value'Image; Stripped : String renames Result (Result'First + 1 .. Result'Last); pragma Assert (Result (Result'First) = ' '); begin return (if Positive then Stripped else "-" & Stripped); end Image; Value_Image : constant String := Image (Positive, Integer_Value) & "." & Image (True, Fractional_Value) & "e" & Image (Exponent_Positive, Exponent); begin Result.Value := Valid_Float'Value (Value_Image); exception when Constraint_Error => return Too_Large; end; if not Result.Value'Valid then if Result.Value < Valid_Float'First then Result := (Kind => Infinity, Positive => False); elsif Result.Value > Valid_Float'Last then Result := (Kind => Infinity, Positive => True); else Result := (Kind => NaN, Positive => True); end if; end if; Token_Buffer.Token := (Kind => Float_Literal, Float_Value => Result); return True; end Read_Float; ------------------------ -- Read_Special_Float -- ------------------------ function Read_Special_Float (Name : Wide_Wide_String; Kind : Special_Float_Kind; Positive : Boolean) return Boolean is function Invalid_Float return Boolean is (Create_Lexing_Error ("invalid float")); begin pragma Assert (Codepoint_Buffer.Codepoint = Name (Name'First)); for C of Name (Name'First + 1 .. Name'Last) loop if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= C then return Invalid_Float; end if; end loop; declare Value : Any_Float (Kind); begin Value.Positive := Positive; Token_Buffer.Token := (Kind => Float_Literal, Float_Value => Value); end; return True; end Read_Special_Float; ------------------- -- Read_Bare_Key -- ------------------- function Read_Bare_Key return Boolean is begin Token_Buffer.Token := (Kind => String_Literal, String_Format => Bare_Key, others => <>); loop -- Add the previously read character to the key token Append_As_UTF8 (Codepoint_Buffer.Codepoint); -- Then check the next character: exit the loop as soon as we either -- reach the end of stream, or we find a non-key character. if not Read_Codepoint then return False; end if; exit when Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint not in '0' .. '9' | 'A' .. 'Z' | 'a' .. 'z' | '_' | '-'; end loop; -- Be sure to schedule the re-emission of the read event that made us -- stop reading characters so that callers can attempt to read one more -- token. Reemit_Codepoint; return True; end Read_Bare_Key; ------------------ -- Read_Keyword -- ------------------ function Read_Keyword (Text : Wide_Wide_String; Token : Any_Token) return Boolean is begin -- Read all codepoints that constitute the token (except the first one, -- as per the Read_Keyword contract) and make sure they match the -- expected text. for I in Text'First + 1 .. Text'Last loop if not Read_Codepoint then return False; elsif Codepoint_Buffer.EOF or else Codepoint_Buffer.Codepoint /= Text (I) then return Create_Lexing_Error ("invalid token"); end if; end loop; Token_Buffer.Token := Token; return True; end Read_Keyword; ---------------- -- Parse_Line -- ---------------- function Parse_Line return Boolean is begin if not Read_Token (Key_Expected => True) then return False; elsif Token_Buffer.EOF then return True; end if; case Token_Buffer.Token.Kind is when Newline => return True; when Square_Bracket_Open => -- Parse a [section] return Parse_Section (Array_Of_Table => False); when Double_Square_Bracket_Open => -- Parse a [[section]] return Parse_Section (Array_Of_Table => True); when String_Literal => -- Parse a key/value pair declare Table : TOML_Value := Current_Table; Key : Unbounded_UTF8_String; Value : TOML_Value; begin -- Parse the dotted key that identify the table entry to -- create. In particular, get the destination table (Table) and -- the key to insert (Key) and make sure there is no existing -- entry for Key. if not Parse_Dotted_Keys (Table, Key, Traverse_Arrays => False) then return False; elsif Table.Has (Key) then return Create_Syntax_Error ("duplicate key"); end if; if Token_Buffer.EOF or else Token_Buffer.Token.Kind /= Equal then return Create_Syntax_Error; end if; -- Now parse the value for the entry to insert. On success, do -- the insertion. if Parse_Value (Value) then Table.Set (Key, Value); else return False; end if; -- Expect either a new line, or the end of the file if not Read_Token (Key_Expected => True) then return False; elsif Token_Buffer.EOF then return True; elsif Token_Buffer.Token.Kind /= Newline then return Create_Syntax_Error ("missing newline"); end if; return True; end; when others => return Create_Syntax_Error; end case; end Parse_Line; --------------- -- Get_Table -- --------------- function Get_Table (Key : Unbounded_UTF8_String; Table : in out TOML_Value; Traverse_Arrays : Boolean := False) return Boolean is Next_Table : TOML_Value := Table.Get_Or_Null (Key); begin if Next_Table.Is_Null then Next_Table := Create_Table; Next_Table.Set_Implicitly_Created; Table.Set (Key, Next_Table); Table := Next_Table; return True; elsif Next_Table.Kind = TOML_Table then Table := Next_Table; return True; elsif Traverse_Arrays and then Next_Table.Kind = TOML_Array and then Next_Table.Length > 0 then Table := Next_Table.Item (Next_Table.Length); return True; else return Create_Syntax_Error ("invalid table key"); end if; end Get_Table; ------------------- -- Parse_Section -- ------------------- function Parse_Section (Array_Of_Table : Boolean) return Boolean is Opening_Bracket_Location : constant Source_Location := Token_Buffer.Location; Closing_Bracket : constant Token_Kind := (if Array_Of_Table then Double_Square_Bracket_Close else Square_Bracket_Close); Table : TOML_Value := Root_Table; Key : Unbounded_UTF8_String; begin -- Get the first token for the section name, as per Parse_Dotted_Keys's -- contract. if not Read_Token (Key_Expected => True) then return False; elsif Token_Buffer.EOF then return Create_Syntax_Error; elsif not Parse_Dotted_Keys (Table, Key, Traverse_Arrays => True) then return False; -- At this point, Parse_Dotted_Keys left the first non-key token in -- Token_Buffer: make sure we have the closing bracket. elsif Token_Buffer.EOF or else Token_Buffer.Token.Kind /= Closing_Bracket then return Create_Syntax_Error; -- And now, make sure that we have either EOF or a newline next elsif not Read_Token (Key_Expected => False) or else (not Token_Buffer.EOF and then Token_Buffer.Token.Kind /= Newline) then return Create_Syntax_Error; end if; -- Finally, create the requested table if Array_Of_Table then -- Key is supposed to refer to an array of tables: if there is no -- such entry in Table, create one, otherwise make sure it has the -- expected item type. declare Arr : TOML_Value := Table.Get_Or_Null (Key); begin if Arr.Is_Null then Arr := Create_Array; Arr.Set_Implicitly_Created; Table.Set (Key, Arr); elsif Arr.Kind /= TOML_Array then return Create_Error ("invalid array", Opening_Bracket_Location); elsif not Arr.Implicitly_Created then return Create_Error ("arrays of tables cannot complete inline arrays", Opening_Bracket_Location); end if; -- Create a new table and append it to this array Current_Table := Create_Table; Arr.Append (Current_Table); end; else -- If Key is already associated to a table, return it (it's an error -- if it is not a table or if it was already created explicitly). -- Create the destination table otherwise. if Table.Has (Key) then Current_Table := Table.Get (Key); if Current_Table.Kind /= TOML_Table then return Create_Error ("duplicate key", Opening_Bracket_Location); elsif Current_Table.Implicitly_Created then Current_Table.Set_Explicitly_Created; else return Create_Error ("cannot create tables twice", Opening_Bracket_Location); end if; else Current_Table := Create_Table; Table.Set (Key, Current_Table); end if; end if; return True; end Parse_Section; ----------------------- -- Parse_Dotted_Keys -- ----------------------- function Parse_Dotted_Keys (Table : in out TOML_Value; Key : out Unbounded_UTF8_String; Traverse_Arrays : Boolean := False) return Boolean is Has_Key : Boolean := False; -- Whether we parsed at least one key begin loop -- Process the current key, updating Table accordingly if Token_Buffer.EOF or else Token_Buffer.Token.Kind /= String_Literal or else Token_Buffer.Token.String_Format not in Valid_Key_Format then return Create_Syntax_Error; end if; -- We are about to parse a key. If we already parsed one, we need to -- fetch the corresponding table. if Has_Key and then not Get_Table (Key, Table, Traverse_Arrays) then return False; end if; Key := Token_Buffer.Token.String_Value; Has_Key := True; -- If the next token is a dot, expect another key. Otherwise, stop -- parsing keys. if not Read_Token (Key_Expected => True) then return False; elsif Token_Buffer.EOF or else Token_Buffer.Token.Kind /= Dot then return True; elsif not Read_Token (Key_Expected => True) then return False; end if; end loop; end Parse_Dotted_Keys; ----------------- -- Parse_Value -- ----------------- function Parse_Value (Value : out TOML_Value) return Boolean is begin -- Fetch the first token that encodes the value to parse... if not Read_Token (Key_Expected => False) then return False; elsif Token_Buffer.EOF then return Create_Syntax_Error; end if; case Token_Buffer.Token.Kind is when Boolean_Literal => Value := Create_Boolean (Token_Buffer.Token.Boolean_Value); when Integer_Literal => Value := Create_Integer (Token_Buffer.Token.Integer_Value); when Float_Literal => Value := Create_Float (Token_Buffer.Token.Float_Value); when String_Literal => Value := Create_String (Token_Buffer.Token.String_Value); when Offset_Datetime_Literal => Value := Create_Offset_Datetime (Token_Buffer.Token.Offset_Datetime_Value); when Local_Datetime_Literal => Value := Create_Local_Datetime (Token_Buffer.Token.Local_Datetime_Value); when Local_Date_Literal => Value := Create_Local_Date (Token_Buffer.Token.Local_Date_Value); when Local_Time_Literal => Value := Create_Local_Time (Token_Buffer.Token.Local_Time_Value); when Square_Bracket_Open => return Parse_Array (Value); when Curly_Bracket_Open => return Parse_Table (Value); when others => return Create_Syntax_Error ("invalid (or not supported yet) syntax"); end case; return True; end Parse_Value; ----------------- -- Parse_Array -- ----------------- function Parse_Array (Value : out TOML_Value) return Boolean is Comma_Allowed : Boolean := False; begin Value := Create_Array; loop -- Fetch the next token. We need one, so reaching end of stream is a -- parsing error. if not Read_Token (Key_Expected => False) then return False; elsif Token_Buffer.EOF then return Create_Syntax_Error; end if; case Token_Buffer.Token.Kind is when Square_Bracket_Close => return True; when Newline => -- Newlines are allowed anywhere between surrounding brackets, -- values and commas. null; when Comma => if Comma_Allowed then Comma_Allowed := False; else return Create_Syntax_Error; end if; when others => -- We are expecting a comma right after parsing a value, so if -- we have a potential value in this case, we know a comma is -- missing. if Comma_Allowed then return Create_Syntax_Error; end if; -- We already read the first token for this value, but -- Parse_Value expects it not to be read yet, so plan to -- re-emit it. Reemit_Token; declare Item : TOML_Value; begin -- Parse the item value and then append the item to the -- result. if not Parse_Value (Item) then return False; end if; Value.Append (Item); end; Comma_Allowed := True; end case; end loop; end Parse_Array; ----------------- -- Parse_Table -- ----------------- function Parse_Table (Value : out TOML_Value) return Boolean is Comma_Allowed : Boolean := False; Last_Was_Comma : Boolean := False; Key : Unbounded_UTF8_String; Table : TOML_Value; begin Value := Create_Table; loop -- Fetch the next token (a potential key for the next table entry, or -- a closing bracket). We need one, so reaching end of stream is a -- parsing error. if not Read_Token (Key_Expected => True) then return False; elsif Token_Buffer.EOF then return Create_Syntax_Error; end if; case Token_Buffer.Token.Kind is when Curly_Bracket_Close => if Last_Was_Comma then return Create_Error ("invalid trailing comma"); end if; return True; when Newline => return Create_Error ("newlines not allowed in inlined tables"); when Comma => Last_Was_Comma := True; if Comma_Allowed then Comma_Allowed := False; else return Create_Syntax_Error; end if; when String_Literal => -- We are expecting a comma right after parsing a value, so if -- we have a potential value in this case, we know a comma is -- missing. if Comma_Allowed then return Create_Syntax_Error; end if; -- Dotted keys are allowed in inline tables, so attempt to -- parse dotted keys (i.e. multiple tokens) and make sure it is -- followed by an equal token. Table := Value; if not Parse_Dotted_Keys (Table, Key, Traverse_Arrays => False) then return False; elsif Token_Buffer.EOF or else Token_Buffer.Token.Kind /= Equal then return Create_Syntax_Error; end if; -- Then try to create the table entry if Table.Has (Key) then return Create_Syntax_Error ("duplicate key"); end if; -- Now read the value declare Item : TOML_Value; begin -- Parse the item value, reject heterogeneous arrays, and -- then append the item to the result. if not Parse_Value (Item) then return False; end if; -- Finally register the table entry Table.Set (Key, Item); Comma_Allowed := True; Last_Was_Comma := False; end; when others => return Create_Syntax_Error; end case; end loop; end Parse_Table; begin while not Token_Buffer.EOF loop if not Parse_Line then return Result; end if; end loop; return Result; end TOML.Generic_Parse; alire-1.2.1/deps/ada-toml/src/toml-generic_parse.ads000066400000000000000000000013051411642634700223060ustar00rootroot00000000000000generic type Input_Stream (<>) is limited private; -- Stream of bytes with procedure Get (Stream : in out Input_Stream; EOF : out Boolean; Byte : out Character) is <>; -- Try to read a byte from Stream. If the end of Stream was reached before -- we could read such a byte, just set EOF to True. Otherwise, set it to -- False and put the read character to Byte. Tab_Stop : Positive := 8; -- Maximal number of columns that tab characters (0x09) skip function TOML.Generic_Parse (Stream : in out Input_Stream) return TOML.Read_Result with Preelaborate; -- Read a TOML document from Stream and return the corresponding value alire-1.2.1/deps/ada-toml/src/toml.adb000066400000000000000000000546201411642634700174710ustar00rootroot00000000000000with Ada.Containers.Generic_Array_Sort; with Ada.Containers.Hashed_Maps; with Ada.Containers.Vectors; with Ada.Strings.Unbounded.Hash; with Ada.Unchecked_Deallocation; with TOML.Generic_Dump; with TOML.Generic_Parse; package body TOML is use Ada.Strings.Unbounded; procedure Dump_To_String is new TOML.Generic_Dump (Output_Stream => Unbounded_UTF8_String, Put => Append); procedure Sort_Keys is new Ada.Containers.Generic_Array_Sort (Index_Type => Positive, Element_Type => Unbounded_UTF8_String, Array_Type => Key_Array); package TOML_Maps is new Ada.Containers.Hashed_Maps (Key_Type => Unbounded_String, Element_Type => TOML_Value, Hash => Hash, Equivalent_Keys => "="); package TOML_Vectors is new Ada.Containers.Vectors (Positive, TOML_Value); type TOML_Value_Record (Kind : Any_Value_Kind) is limited record Ref_Count : Natural; case Kind is when TOML_Table => Map_Value : TOML_Maps.Map; Table_Implicitly_Created : Boolean; -- Helper for parsing: true iff this table was created implictly -- when parsing a sub-table. For instance, this is true for the -- table "a" if we read "[a.b]" but not yet "[a]". when TOML_Array => Array_Value : TOML_Vectors.Vector; -- List of values for all items Array_Implicitly_Created : Boolean; -- Same as Table_Implicitly_Created when TOML_String => String_Value : Unbounded_String; when TOML_Integer => Integer_Value : Any_Integer; when TOML_Float => Float_Value : Any_Float; when TOML_Boolean => Boolean_Value : Boolean; when TOML_Offset_Datetime => Offset_Datetime_Value : Any_Offset_Datetime; when TOML_Local_Datetime => Local_Datetime_Value : Any_Local_Datetime; when TOML_Local_Date => Local_Date_Value : Any_Local_Date; when TOML_Local_Time => Local_Time_Value : Any_Local_Time; end case; end record; procedure Free is new Ada.Unchecked_Deallocation (TOML_Value_Record, TOML_Value_Record_Access); function Create_Value (Rec : TOML_Value_Record_Access) return TOML_Value; -- Wrap a value record in a value. This resets its ref-count to 1. ------------------ -- Create_Value -- ------------------ function Create_Value (Rec : TOML_Value_Record_Access) return TOML_Value is begin return Result : TOML_Value do Rec.Ref_Count := 1; Result.Value := Rec; end return; end Create_Value; ------------------ -- Create_Error -- ------------------ function Create_Error (Message : String; Location : Source_Location) return Read_Result is begin return (Success => False, Message => To_Unbounded_String (Message), Location => Location); end Create_Error; ------------- -- Is_Null -- ------------- function Is_Null (Value : TOML_Value) return Boolean is begin return Value.Value = null; end Is_Null; ---------- -- Kind -- ---------- function Kind (Value : TOML_Value) return Any_Value_Kind is begin return Value.Value.Kind; end Kind; ------------ -- Equals -- ------------ function Equals (Left, Right : TOML_Value) return Boolean is begin -- If Left and Right refer to the same document, they are obviously -- equivalent (X is equivalent to X). If they don't have the same kind, -- they are obviously not equivalent. if Left = Right then return True; elsif Left.Kind /= Right.Kind then return False; end if; case Left.Kind is when TOML_Table => declare Left_Keys : constant Key_Array := Left.Keys; Right_Keys : constant Key_Array := Right.Keys; begin if Left_Keys /= Right_Keys then return False; end if; for K of Left_Keys loop if not Equals (Left.Get (K), Right.Get (K)) then return False; end if; end loop; end; when TOML_Array => if Left.Length /= Right.Length then return False; end if; for I in 1 .. Left.Length loop if not Equals (Left.Item (I), Right.Item (I)) then return False; end if; end loop; when TOML_String => return Left.Value.String_Value = Right.Value.String_Value; when TOML_Integer => return Left.Value.Integer_Value = Right.Value.Integer_Value; when TOML_Boolean => return Left.Value.Boolean_Value = Right.Value.Boolean_Value; when TOML_Offset_Datetime => return Left.Value.Offset_Datetime_Value = Right.Value.Offset_Datetime_Value; when TOML_Local_Datetime => return Left.Value.Local_Datetime_Value = Right.Value.Local_Datetime_Value; when TOML_Local_Date => return Left.Value.Local_Date_Value = Right.Value.Local_Date_Value; when TOML_Local_Time => return Left.Value.Local_Time_Value = Right.Value.Local_Time_Value; when TOML_Float => return Left.Value.Float_Value = Right.Value.Float_Value; end case; return True; end Equals; ----------- -- Clone -- ----------- function Clone (Value : TOML_Value) return TOML_Value is Result : TOML_Value; begin case Value.Kind is when TOML_Table => Result := Create_Table; for Key of Value.Keys loop Result.Set (Key, Value.Get (Key).Clone); end loop; when TOML_Array => Result := Create_Array; for I in 1 .. Value.Length loop Result.Append (Value.Item (I)); end loop; when TOML_String => Result := Create_String (Value.Value.String_Value); when TOML_Integer => Result := Create_Integer (Value.Value.Integer_Value); when TOML_Boolean => Result := Create_Boolean (Value.Value.Boolean_Value); when TOML_Offset_Datetime => Result := Create_Offset_Datetime (Value.Value.Offset_Datetime_Value); when TOML_Local_Datetime => Result := Create_Local_Datetime (Value.Value.Local_Datetime_Value); when TOML_Local_Date => Result := Create_Local_Date (Value.Value.Local_Date_Value); when TOML_Local_Time => Result := Create_Local_Time (Value.Value.Local_Time_Value); when TOML_Float => Result := Create_Float (Value.Value.Float_Value); end case; return Result; end Clone; ---------------- -- As_Boolean -- ---------------- function As_Boolean (Value : TOML_Value) return Boolean is begin return Value.Value.Boolean_Value; end As_Boolean; ---------------- -- As_Integer -- ---------------- function As_Integer (Value : TOML_Value) return Any_Integer is begin return Value.Value.Integer_Value; end As_Integer; -------------- -- As_Float -- -------------- function As_Float (Value : TOML_Value) return Any_Float is begin return Value.Value.Float_Value; end As_Float; --------------- -- As_String -- --------------- function As_String (Value : TOML_Value) return String is begin return To_String (Value.As_Unbounded_String); end As_String; ------------------------- -- As_Unbounded_String -- ------------------------- function As_Unbounded_String (Value : TOML_Value) return Ada.Strings.Unbounded.Unbounded_String is begin return Value.Value.String_Value; end As_Unbounded_String; ------------------------ -- As_Offset_Datetime -- ------------------------ function As_Offset_Datetime (Value : TOML_Value) return Any_Offset_Datetime is begin return Value.Value.Offset_Datetime_Value; end As_Offset_Datetime; ----------------------- -- As_Local_Datetime -- ----------------------- function As_Local_Datetime (Value : TOML_Value) return Any_Local_Datetime is begin return Value.Value.Local_Datetime_Value; end As_Local_Datetime; ------------------- -- As_Local_Date -- ------------------- function As_Local_Date (Value : TOML_Value) return Any_Local_Date is begin return Value.Value.Local_Date_Value; end As_Local_Date; ------------------- -- As_Local_Time -- ------------------- function As_Local_Time (Value : TOML_Value) return Any_Local_Time is begin return Value.Value.Local_Time_Value; end As_Local_Time; --------- -- Has -- --------- function Has (Value : TOML_Value; Key : String) return Boolean is begin return Value.Has (To_Unbounded_String (Key)); end Has; --------- -- Has -- --------- function Has (Value : TOML_Value; Key : Unbounded_UTF8_String) return Boolean is begin return Value.Value.Map_Value.Contains (Key); end Has; ---------- -- Keys -- ---------- function Keys (Value : TOML_Value) return Key_Array is use TOML_Maps; Map : TOML_Maps.Map renames Value.Value.Map_Value; I : Positive := 1; begin return Result : Key_Array (1 .. Natural (Map.Length)) do for Position in Map.Iterate loop Result (I) := Key (Position); I := I + 1; end loop; Sort_Keys (Result); end return; end Keys; --------- -- Get -- --------- function Get (Value : TOML_Value; Key : String) return TOML_Value is begin return Value.Get (To_Unbounded_String (Key)); end Get; --------- -- Get -- --------- function Get (Value : TOML_Value; Key : Unbounded_UTF8_String) return TOML_Value is begin return Value.Value.Map_Value.Element (Key); end Get; ----------------- -- Get_Or_Null -- ----------------- function Get_Or_Null (Value : TOML_Value; Key : String) return TOML_Value is begin return Value.Get_Or_Null (To_Unbounded_String (Key)); end Get_Or_Null; ----------------- -- Get_Or_Null -- ----------------- function Get_Or_Null (Value : TOML_Value; Key : Unbounded_UTF8_String) return TOML_Value is use TOML_Maps; Position : constant Cursor := Value.Value.Map_Value.Find (Key); begin return (if Has_Element (Position) then Element (Position) else No_TOML_Value); end Get_Or_Null; ---------------------- -- Iterate_On_Table -- ---------------------- function Iterate_On_Table (Value : TOML_Value) return Table_Entry_Array is Keys : constant Key_Array := Value.Keys; begin return Result : Table_Entry_Array (Keys'Range) do for I In Keys'Range loop Result (I) := (Keys (I), Value.Get (Keys (I))); end loop; end return; end Iterate_On_Table; ------------ -- Length -- ------------ function Length (Value : TOML_Value) return Natural is begin return Natural (Value.Value.Array_Value.Length); end Length; ---------- -- Item -- ---------- function Item (Value : TOML_Value; Index : Positive) return TOML_Value is begin return Value.Value.Array_Value.Element (Index); end Item; -------------------- -- Create_Boolean -- -------------------- function Create_Boolean (Value : Boolean) return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Boolean, Ref_Count => 1, Boolean_Value => Value)); end Create_Boolean; -------------------- -- Create_Integer -- -------------------- function Create_Integer (Value : Any_Integer) return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Integer, Ref_Count => 1, Integer_Value => Value)); end Create_Integer; ------------------ -- Create_Float -- ------------------ function Create_Float (Value : Any_Float) return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Float, Ref_Count => 1, Float_Value => Value)); end Create_Float; ------------------- -- Create_String -- ------------------- function Create_String (Value : String) return TOML_Value is begin return Create_String (To_Unbounded_String (Value)); end Create_String; ------------------- -- Create_String -- ------------------- function Create_String (Value : Unbounded_UTF8_String) return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_String, Ref_Count => 1, String_Value => Value)); end Create_String; ---------------------------- -- Create_Offset_Datetime -- ---------------------------- function Create_Offset_Datetime (Value : Any_Offset_Datetime) return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Offset_Datetime, Ref_Count => 1, Offset_Datetime_Value => Value)); end Create_Offset_Datetime; --------------------------- -- Create_Local_Datetime -- --------------------------- function Create_Local_Datetime (Value : Any_Local_Datetime) return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Local_Datetime, Ref_Count => 1, Local_Datetime_Value => Value)); end Create_Local_Datetime; ----------------------- -- Create_Local_Date -- ----------------------- function Create_Local_Date (Value : Any_Local_Date) return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Local_Date, Ref_Count => 1, Local_Date_Value => Value)); end Create_Local_Date; ----------------------- -- Create_Local_Time -- ----------------------- function Create_Local_Time (Value : Any_Local_Time) return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Local_Time, Ref_Count => 1, Local_Time_Value => Value)); end Create_Local_Time; ------------------ -- Create_Table -- ------------------ function Create_Table return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Table, Ref_Count => 1, Map_Value => <>, Table_Implicitly_Created => False)); end Create_Table; --------- -- Set -- --------- procedure Set (Value : TOML_Value; Key : String; Entry_Value : TOML_Value) is begin Value.Set (To_Unbounded_String (Key), Entry_Value); end Set; --------- -- Set -- --------- procedure Set (Value : TOML_Value; Key : Unbounded_UTF8_String; Entry_Value : TOML_Value) is begin Value.Value.Map_Value.Include (Key, Entry_Value); end Set; ----------------- -- Set_Default -- ----------------- procedure Set_Default (Value : TOML_Value; Key : String; Entry_Value : TOML_Value) is begin Value.Set_Default (To_Unbounded_String (Key), Entry_Value); end Set_Default; ----------------- -- Set_Default -- ----------------- procedure Set_Default (Value : TOML_Value; Key : Unbounded_UTF8_String; Entry_Value : TOML_Value) is use TOML_Maps; Dummy_Position : Cursor; Dummy_Inserted : Boolean; begin Value.Value.Map_Value.Insert (Key, Entry_Value, Dummy_Position, Dummy_Inserted); end Set_Default; ----------- -- Unset -- ----------- procedure Unset (Value : TOML_Value; Key : String) is begin Value.Unset (To_Unbounded_String (Key)); end Unset; ----------- -- Unset -- ----------- procedure Unset (Value : TOML_Value; Key : Unbounded_UTF8_String) is begin Value.Value.Map_Value.Delete (Key); end Unset; ----------- -- Merge -- ----------- function Merge (L, R : TOML_Value) return TOML_Value is function Merge_Entries (Key : Unbounded_UTF8_String; Dummy_L, Dummy_R : TOML_Value) return TOML_Value is (raise Constraint_Error with "duplicate key: " & To_String (Key)); begin return Merge (L, R, Merge_Entries'Access); end Merge; ----------- -- Merge -- ----------- function Merge (L, R : TOML_Value; Merge_Entries : not null access function (Key : Unbounded_UTF8_String; L, R : TOML_Value) return TOML_Value) return TOML_Value is Table : constant TOML_Value := Create_Table; begin for Key of L.Keys loop Table.Set (Key, L.Get (Key)); end loop; for Key of R.Keys loop declare Value : TOML_Value := R.Get (Key); begin if Table.Has (Key) then Value := Merge_Entries (Key, Table.Get (Key), Value); end if; Table.Set (Key, Value); end; end loop; return Table; end Merge; ------------------ -- Create_Array -- ------------------ function Create_Array return TOML_Value is begin return Create_Value (new TOML_Value_Record' (Kind => TOML_Array, Ref_Count => 1, Array_Value => <>, Array_Implicitly_Created => False)); end Create_Array; --------- -- Set -- --------- procedure Set (Value : TOML_Value; Index : Positive; Item : TOML_Value) is begin Value.Value.Array_Value (Index) := Item; end Set; ------------ -- Append -- ------------ procedure Append (Value, Item : TOML_Value) is begin Value.Value.Array_Value.Append (Item); end Append; ------------------- -- Insert_Before -- ------------------- procedure Insert_Before (Value : TOML_Value; Index : Positive; Item : TOML_Value) is begin Value.Value.Array_Value.Insert (Index, Item); end Insert_Before; ----------------- -- Load_String -- ----------------- function Load_String (Content : String) return Read_Result is type Input_Stream is record Next_Character : Positive; -- Index of the next character in Content that Get must return end record; procedure Get (Stream : in out Input_Stream; EOF : out Boolean; Byte : out Character); -- Callback for Parse_String --------- -- Get -- --------- procedure Get (Stream : in out Input_Stream; EOF : out Boolean; Byte : out Character) is begin if Stream.Next_Character > Content'Length then EOF := True; else EOF := False; Byte := Content (Stream.Next_Character); Stream.Next_Character := Stream.Next_Character + 1; end if; end Get; function Parse_String is new TOML.Generic_Parse (Input_Stream, Get); Stream : Input_Stream := (Next_Character => Content'First); begin return Parse_String (Stream); end Load_String; -------------------- -- Dump_As_String -- -------------------- function Dump_As_String (Value : TOML_Value) return String is begin return To_String (Dump_As_Unbounded (Value)); end Dump_As_String; ----------------------- -- Dump_As_Unbounded -- ----------------------- function Dump_As_Unbounded (Value : TOML_Value) return Unbounded_UTF8_String is begin return Result : Unbounded_UTF8_String do Dump_To_String (Result, Value); end return; end Dump_As_Unbounded; ------------------ -- Format_Error -- ------------------ function Format_Error (Result : Read_Result) return String is Formatted : Unbounded_UTF8_String; begin if Result.Location.Line /= 0 then declare L : constant String := Result.Location.Line'Image; C : constant String := Result.Location.Column'Image; begin Append (Formatted, L (L'First + 1 .. L'Last)); Append (Formatted, ":"); Append (Formatted, C (C'First + 1 .. C'Last)); Append (Formatted, ": "); end; end if; Append (Formatted, Result.Message); return To_String (Formatted); end Format_Error; ------------ -- Adjust -- ------------ overriding procedure Adjust (Self : in out TOML_Value) is begin if Self.Value = null then return; end if; Self.Value.Ref_Count := Self.Value.Ref_Count + 1; end Adjust; -------------- -- Finalize -- -------------- overriding procedure Finalize (Self : in out TOML_Value) is begin if Self.Value = null then return; end if; declare V : TOML_Value_Record renames Self.Value.all; begin -- Decrement the ref-count. If no-one references V anymore, -- deallocate it. V.Ref_Count := V.Ref_Count - 1; if V.Ref_Count > 0 then return; end if; end; Free (Self.Value); end Finalize; ------------------------ -- Implicitly_Created -- ------------------------ function Implicitly_Created (Self : TOML_Value'Class) return Boolean is begin if Self.Kind = TOML_Table then return Self.Value.Table_Implicitly_Created; else return Self.Value.Array_Implicitly_Created; end if; end Implicitly_Created; ---------------------------- -- Set_Implicitly_Created -- ---------------------------- procedure Set_Implicitly_Created (Self : TOML_Value'Class) is begin if Self.Kind = TOML_Table then Self.Value.Table_Implicitly_Created := True; else Self.Value.Array_Implicitly_Created := True; end if; end Set_Implicitly_Created; ---------------------------- -- Set_Explicitly_Created -- ---------------------------- procedure Set_Explicitly_Created (Self : TOML_Value'Class) is begin if Self.Kind = TOML_Table then Self.Value.Table_Implicitly_Created := False; else Self.Value.Array_Implicitly_Created := False; end if; end Set_Explicitly_Created; end TOML; alire-1.2.1/deps/ada-toml/src/toml.ads000066400000000000000000000371041411642634700175100ustar00rootroot00000000000000with Ada.Finalization; with Ada.Strings.Unbounded; with Interfaces; package TOML with Preelaborate is pragma Warnings (Off); use type Ada.Strings.Unbounded.Unbounded_String; pragma Warnings (On); Version : constant String := "0.1"; -- Version for the ada-toml project subtype Unbounded_UTF8_String is Ada.Strings.Unbounded.Unbounded_String; type Any_Value_Kind is (TOML_Table, TOML_Array, TOML_String, TOML_Integer, TOML_Float, TOML_Boolean, TOML_Offset_Datetime, TOML_Local_Datetime, TOML_Local_Date, TOML_Local_Time); subtype Composite_Value_Kind is Any_Value_Kind range TOML_Table .. TOML_Array; subtype Atom_Value_Kind is Any_Value_Kind range TOML_String .. TOML_Local_Time; type TOML_Value is new Ada.Finalization.Controlled with private; No_TOML_Value : constant TOML_Value; -- TODO: create TOML_Value subtypes for the various kinds type Any_Integer is new Interfaces.Integer_64; -- TOML supports any integer that can be encoded in a 64-bit signed -- integer. type Valid_Float is new Interfaces.IEEE_Float_64; type Float_Kind is (Regular, NaN, Infinity); subtype Special_Float_Kind is Float_Kind range NaN .. Infinity; type Any_Float (Kind : Float_Kind := Regular) is record case Kind is when Regular => Value : Valid_Float; when Special_Float_Kind => Positive : Boolean; end case; end record; -- TOML advises to implement its float values as IEEE 754 binary64 values, -- however Ada does not provide a standard way to represent infinities and -- NaN (Not a Number), so fallback to a discriminated record to reliably -- represent TOML float. type Any_Year is range 1 .. 9999; type Any_Month is range 1 .. 12; type Any_Day is range 1 .. 31; type Any_Local_Date is record Year : Any_Year; Month : Any_Month; Day : Any_Day; end record; type Any_Hour is range 0 .. 23; type Any_Minute is range 0 .. 59; type Any_Second is range 0 .. 60; type Any_Millisecond is range 0 .. 999; type Any_Local_Offset is range -(23 * 60 + 59) .. 23 * 60 + 59; -- Offset between local time and UTC, in minutes. We allow from -23:59 to -- +23:59. type Any_Local_Time is record Hour : Any_Hour; Minute : Any_Minute; Second : Any_Second; Millisecond : Any_Millisecond; end record; type Any_Local_Datetime is record Date : Any_Local_Date; Time : Any_Local_Time; end record; type Any_Offset_Datetime is record Datetime : Any_Local_Datetime; Offset : Any_Local_Offset; Unknown_Offset : Boolean; end record with Dynamic_Predicate => not Any_Offset_Datetime.Unknown_Offset or else Any_Offset_Datetime.Offset = 0; ----------------------- -- Generic accessors -- ----------------------- function Is_Null (Value : TOML_Value) return Boolean; -- Return whether Value is a null reference function Is_Present (Value : TOML_Value) return Boolean is (not Value.Is_Null); function Kind (Value : TOML_Value) return Any_Value_Kind with Pre => Value.Is_Present; -- Return the kind of TOML node for the given Value function Equals (Left, Right : TOML_Value) return Boolean with Pre => Left.Is_Present and then Right.Is_Present; -- Return whether Left and Right refer to equivalent TOML documents. -- -- Note that this is very different from the built-in "=" operator: -- the TOML_Value type has by-reference meaning, so "=" compares identity, -- not structural equivalence. function Clone (Value : TOML_Value) return TOML_Value with Pre => Value.Is_Present; -- Return a reference to a deep copy for Value -------------------- -- Atom accessors -- -------------------- function As_Boolean (Value : TOML_Value) return Boolean with Pre => Value.Kind = TOML_Boolean; -- Return the boolean that Value represents function As_Integer (Value : TOML_Value) return Any_Integer with Pre => Value.Kind = TOML_Integer; -- Return the integer that Value represents function As_Float (Value : TOML_Value) return Any_Float with Pre => Value.Kind = TOML_Float; -- Return the float that Value represents function As_String (Value : TOML_Value) return String with Pre => Value.Kind = TOML_String; -- Return the string that Value represents function As_Unbounded_String (Value : TOML_Value) return Unbounded_UTF8_String with Pre => Value.Kind = TOML_String; -- Likewise, but return an unbounded string function As_Offset_Datetime (Value : TOML_Value) return Any_Offset_Datetime with Pre => Value.Kind = TOML_Offset_Datetime; -- Return the offset datetime that Value represents function As_Local_Datetime (Value : TOML_Value) return Any_Local_Datetime with Pre => Value.Kind = TOML_Local_Datetime; -- Return the local datetime that Value represents function As_Local_Date (Value : TOML_Value) return Any_Local_Date with Pre => Value.Kind = TOML_Local_Date; -- Return the local date that Value represents function As_Local_Time (Value : TOML_Value) return Any_Local_Time with Pre => Value.Kind = TOML_Local_Time; -- Return the local time that Value represents --------------------- -- Table accessors -- --------------------- function Has (Value : TOML_Value; Key : String) return Boolean with Pre => Value.Kind = TOML_Table; -- Return whether Value contains an entry for the given Key function Has (Value : TOML_Value; Key : Unbounded_UTF8_String) return Boolean with Pre => Value.Kind = TOML_Table; -- Likewise, but take an unbounded string type Key_Array is array (Positive range <>) of Unbounded_UTF8_String; function Keys (Value : TOML_Value) return Key_Array with Pre => Value.Kind = TOML_Table; -- Return a list for all keys in the given table. Note that the result is -- sorted. function Get (Value : TOML_Value; Key : String) return TOML_Value with Pre => Value.Has (Key); -- Return the value for the entry in Value corresponding to Key function Get (Value : TOML_Value; Key : Unbounded_UTF8_String) return TOML_Value with Pre => Value.Has (Key); -- Likewise, but take an unbounded string function Get_Or_Null (Value : TOML_Value; Key : String) return TOML_Value with Pre => Value.Kind = TOML_Table; -- If there is an entry in the Value table, return its value. Return -- No_TOML_Value otherwise. function Get_Or_Null (Value : TOML_Value; Key : Unbounded_UTF8_String) return TOML_Value with Pre => Value.Kind = TOML_Table; -- Likewise, but take an unbounded string -- The following types and primitive allow one to iterate on key/value -- entries conveniently in a simple FOR loop. type Table_Entry is record Key : Unbounded_UTF8_String; Value : TOML_Value; end record; type Table_Entry_Array is array (Positive range <>) of Table_Entry; function Iterate_On_Table (Value : TOML_Value) return Table_Entry_Array with Pre => Value.Kind = TOML_Table; -- Return an array of key/value pairs for all entries in Value. The result -- is sorted by key. --------------------- -- Array accessors -- --------------------- function Length (Value : TOML_Value) return Natural with Pre => Value.Kind = TOML_Array; -- Return the number of items in Value function Item (Value : TOML_Value; Index : Positive) return TOML_Value with Pre => Value.Kind = TOML_Array and then Index <= Value.Length; -- Return the item in Value at the given Index ------------------- -- Atom creators -- ------------------- function Create_Boolean (Value : Boolean) return TOML_Value with Post => Create_Boolean'Result.Kind = TOML_Boolean and then Create_Boolean'Result.As_Boolean = Value; -- Create a TOML boolean value function Create_Integer (Value : Any_Integer) return TOML_Value with Post => Create_Integer'Result.Kind = TOML_Integer and then Create_Integer'Result.As_Integer = Value; -- Create a TOML integer value function Create_Float (Value : Any_Float) return TOML_Value with Post => Create_Float'Result.Kind = TOML_Float and then Create_Float'Result.As_Float = Value; -- Create a TOML integer value function Create_String (Value : String) return TOML_Value with Post => Create_String'Result.Kind = TOML_String and then Create_String'Result.As_String = Value; -- Create a TOML string value. Value must be a valid UTF-8 string. function Create_String (Value : Unbounded_UTF8_String) return TOML_Value with Post => Create_String'Result.Kind = TOML_String and then Create_String'Result.As_Unbounded_String = Value; -- Create a TOML string value function Create_Offset_Datetime (Value : Any_Offset_Datetime) return TOML_Value with Post => Create_Offset_Datetime'Result.Kind = TOML_Offset_Datetime and then Create_Offset_Datetime'Result.As_Offset_Datetime = Value; -- Create a TOML offset datetime value function Create_Local_Datetime (Value : Any_Local_Datetime) return TOML_Value with Post => Create_Local_Datetime'Result.Kind = TOML_Local_Datetime and then Create_Local_Datetime'Result.As_Local_Datetime = Value; -- Create a TOML local datetime value function Create_Local_Date (Value : Any_Local_Date) return TOML_Value with Post => Create_Local_Date'Result.Kind = TOML_Local_Date and then Create_Local_Date'Result.As_Local_Date = Value; -- Create a TOML local date value function Create_Local_Time (Value : Any_Local_Time) return TOML_Value with Post => Create_Local_Time'Result.Kind = TOML_Local_Time and then Create_Local_Time'Result.As_Local_Time = Value; -- Create a TOML local date value --------------------- -- Table modifiers -- --------------------- function Create_Table return TOML_Value with Post => Create_Table'Result.Kind = TOML_Table; -- Create an empty TOML table procedure Set (Value : TOML_Value; Key : String; Entry_Value : TOML_Value) with Pre => Value.Kind = TOML_Table; -- Create an entry in Value to bind Key to Entry_Value. If Value already -- has an entry for Key, replace it. procedure Set (Value : TOML_Value; Key : Unbounded_UTF8_String; Entry_Value : TOML_Value) with Pre => Value.Kind = TOML_Table; -- Likewise, but take an unbounded string procedure Set_Default (Value : TOML_Value; Key : String; Entry_Value : TOML_Value) with Pre => Value.Kind = TOML_Table; -- If Value has an entry for Key, do nothing. Otherwise, create an entry -- binding Key to Entry_Value. procedure Set_Default (Value : TOML_Value; Key : Unbounded_UTF8_String; Entry_Value : TOML_Value) with Pre => Value.Kind = TOML_Table; -- Likewise, but take an unbounded string procedure Unset (Value : TOML_Value; Key : String) with Pre => Value.Kind = TOML_Table and then Value.Has (Key); -- Remove the Key entry in Value procedure Unset (Value : TOML_Value; Key : Unbounded_UTF8_String) with Pre => Value.Kind = TOML_Table and then Value.Has (Key); -- Likewise, but take an unbounded string function Merge (L, R : TOML_Value) return TOML_Value with Pre => L.Kind = TOML_Table and then R.Kind = TOML_Table, Post => Merge'Result.Kind = TOML_Table; -- Merge two tables. If a key is present in both, Constraint_Error is -- raised. The operation is shallow, so the result table shares values with -- L and R. function Merge (L, R : TOML_Value; Merge_Entries : not null access function (Key : Unbounded_UTF8_String; L, R : TOML_Value) return TOML_Value) return TOML_Value with Pre => L.Kind = TOML_Table and then R.Kind = TOML_Table, Post => Merge'Result.Kind = TOML_Table; -- Merge two tables. If a key is present in both, call Merge_Entries to -- resolve the conflict: use its return value for the entry in the returned -- table. --------------------- -- Array modifiers -- --------------------- function Create_Array return TOML_Value with Post => Create_Array'Result.Kind = TOML_Array; -- Create a TOML array procedure Set (Value : TOML_Value; Index : Positive; Item : TOML_Value) with Pre => Value.Kind = TOML_Array and then Index <= Value.Length; -- Replace the Index'th item in Value with Item procedure Append (Value, Item : TOML_Value) with Pre => Value.Kind = TOML_Array; -- Append Item to the Value array procedure Insert_Before (Value : TOML_Value; Index : Positive; Item : TOML_Value) with Pre => Value.Kind = TOML_Array and then Index < Value.Length + 1; -- Insert Item before the Item'th element in the Value array ------------------ -- Input/Output -- ------------------ type Source_Location is record Line, Column : Natural; end record; No_Location : constant Source_Location := (0, 0); -- Result of TOML document parsing. If the parsing was successful, contains -- the corresponding TOML value, otherwise, contains an error message that -- describes why parsing failed. type Read_Result (Success : Boolean := True) is record case Success is when False => Message : Unbounded_UTF8_String; Location : Source_Location; when True => Value : TOML_Value; end case; end record; function Load_String (Content : String) return Read_Result; -- Parse Content as a TOML document function Dump_As_String (Value : TOML_Value) return String with Pre => Value.Kind = TOML_Table; -- Serialize Value as a valid TOML document function Dump_As_Unbounded (Value : TOML_Value) return Unbounded_UTF8_String with Pre => Value.Kind = TOML_Table; -- Likewise, but return an unbounded string -- To keep this package preelaborable, subprograms that perform I/O on files -- are found in TOML.File_IO function Format_Error (Result : Read_Result) return String with Pre => not Result.Success; -- Format the error information in Result into a GNU-style diagnostic private type TOML_Value_Record; type TOML_Value_Record_Access is access all TOML_Value_Record; type TOML_Value is new Ada.Finalization.Controlled with record Value : TOML_Value_Record_Access; end record; overriding procedure Adjust (Self : in out TOML_Value); overriding procedure Finalize (Self : in out TOML_Value); No_TOML_Value : constant TOML_Value := (Ada.Finalization.Controlled with Value => null); function Create_Error (Message : String; Location : Source_Location) return Read_Result; -- Create an unsuccessful Read_Result value with the provided error -- information. function Implicitly_Created (Self : TOML_Value'Class) return Boolean with Pre => Self.Kind in TOML_Table | TOML_Array; -- Helper for parsing. Return whether Self was created implicitly procedure Set_Implicitly_Created (Self : TOML_Value'Class) with Pre => Self.Kind in TOML_Table | TOML_Array; -- Make future calls to Implicitly_Created return True for Self procedure Set_Explicitly_Created (Self : TOML_Value'Class) with Pre => Self.Kind in TOML_Table | TOML_Array; -- Make future calls to Implicitly_Created return False for Self end TOML; alire-1.2.1/deps/ada-toml/test-importers/000077500000000000000000000000001411642634700202515ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/test-importers/burntsushi-toml-test.py000077500000000000000000000042421411642634700247640ustar00rootroot00000000000000#! /usr/bin/env python3 """ Import tests from . Run this script from the top-level directory in ada-toml's repository, passing to it the path to a checkout of the toml-test repository as its first argument. """ import json import os.path import shutil import sys import yaml burntsushi_root = sys.argv[1] tests_subdir = os.path.join(burntsushi_root, "tests") output_dir = os.path.join(os.getcwd(), 'tests', 'burntsushi-toml-test') os.mkdir(output_dir) def in_path(*args): return os.path.join(burntsushi_root, *args) def out_path(*args): return os.path.join(output_dir, *args) def create_test_name(toml_file): relname = os.path.relpath(toml_file, tests_subdir) return relname[:-5] def write_test_yaml(test_dir, content): with open(os.path.join(test_dir, 'test.yaml'), 'w', encoding='utf-8') as f: yaml.dump(content, f) def import_valid(toml_file): assert toml_file.endswith('.toml') test_name = create_test_name(toml_file) json_file = toml_file[:-5] + '.json' # Create the test directory test_dir = out_path(test_name) os.makedirs(test_dir) # Copy the TOML to parse shutil.copy(toml_file, os.path.join(test_dir, 'input.toml')) # Create the test.yaml, including the expected JSON with open(json_file, 'r', encoding='utf-8') as f: json_doc = json.load(f) write_test_yaml(test_dir, {"driver": "decoder", "output": json_doc}) def import_invalid(toml_file): assert toml_file.endswith('.toml') test_name = create_test_name(toml_file) # Create the test directory test_dir = out_path(test_name) os.makedirs(test_dir) # Copy the TOML to parse shutil.copy(toml_file, os.path.join(test_dir, 'input.toml')) # Create the test.yaml write_test_yaml(test_dir, {"driver": "decoder", "error": True}) def iter_tests(root_dir): for path, _, filenames in os.walk(root_dir): for fn in filenames: if fn.endswith(".toml"): yield os.path.join(path, fn) for valid in iter_tests(in_path('tests', 'valid')): import_valid(valid) for valid in iter_tests(in_path('tests', 'invalid')): import_invalid(valid) alire-1.2.1/deps/ada-toml/test-importers/iarna-toml-spec-tests.py000077500000000000000000000071361411642634700247700ustar00rootroot00000000000000#! /usr/bin/env python3 """ Import tests from . Run this script from the top-level directory in ada-toml's repository, passing to it the path to a checkout of the toml-spec-test repository as its first argument. """ import datetime import glob import json import os.path import shutil import sys import yaml # Some test YAML documents create big recursions in the YAML parser sys.setrecursionlimit(10000) iarna_root = sys.argv[1] output_dir = os.path.join(os.getcwd(), 'tests', 'iarna-toml-spec-tests') os.mkdir(output_dir) def in_path(*args): return os.path.join(iarna_root, *args) def out_path(*args): return os.path.join(output_dir, *args) def create_test_name(toml_file): return os.path.basename(toml_file)[:-5] def write_test_yaml(test_dir, content): with open(os.path.join(test_dir, 'test.yaml'), 'w', encoding='utf-8') as f: print(content, file=f) def yaml_to_json(yaml): """ Turn a YAML document to the equivalent JSON document that ada_toml_decode program will output. """ if isinstance(yaml, dict): return {key: yaml_to_json(value) for key, value in yaml.items()} elif isinstance(yaml, list): return [yaml_to_json(item) for item in yaml] if yaml is False: kind = 'bool', image = 'false' elif yaml is True: kind = 'bool' image = 'true' elif isinstance(yaml, int): kind = 'integer' image = str(yaml) elif isinstance(yaml, str): kind = 'string' image = yaml elif isinstance(yaml, float): kind = 'float' image = str(yaml) elif isinstance(yaml, datetime.datetime): kind = 'local-datetime' image = '{:>04}-{:>02}-{:>02}T{:>02}:{:>02}:{:>02}'.format( yaml.year, yaml.month, yaml.day, yaml.hour, yaml.minute, yaml.second ) if yaml.microsecond: image = '{}.{:>03}'.format(image, yaml.microsecond) else: raise ValueError('Unsupported YAML value ({}): {}' .format(type(yaml), yaml)) return {'type': kind, 'value': image} def import_valid(toml_file): assert toml_file.endswith('.toml') test_name = create_test_name(toml_file) yaml_file = os.path.join(os.path.dirname(toml_file), test_name + '.yaml') # Create the test directory test_dir = out_path('values', test_name) os.mkdir(test_dir) # Copy the TOML to parse shutil.copy(toml_file, os.path.join(test_dir, 'input.toml')) # Create the test.yaml, including the expected JSON try: with open(yaml_file, 'r', encoding='utf-8') as f: data = yaml.safe_load(f) except FileNotFoundError: print('warning: could not find YAML for {}'.format(toml_file)) return data = yaml_to_json(data) write_test_yaml(test_dir, 'driver: decoder' '\noutput: {}'.format(json.dumps(data))) def import_invalid(toml_file): assert toml_file.endswith('.toml') test_name = create_test_name(toml_file) # Create the test directory test_dir = out_path('errors', test_name) os.mkdir(test_dir) # Copy the TOML to parse shutil.copy(toml_file, os.path.join(test_dir, 'input.toml')) # Create the test.yaml write_test_yaml(test_dir, 'driver: decoder' '\nerror: True') os.mkdir(out_path('values')) for toml_file in glob.glob(in_path('values', '*.toml')): import_valid(toml_file) os.mkdir(out_path('errors')) for toml_file in glob.glob(in_path('errors', '*.toml')): import_invalid(toml_file) alire-1.2.1/deps/ada-toml/tests/000077500000000000000000000000001411642634700164125ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/api/000077500000000000000000000000001411642634700171635ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/api/clone/000077500000000000000000000000001411642634700202635ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/api/clone/example.toml000066400000000000000000000001031411642634700226050ustar00rootroot00000000000000array = [true, false] bool = true int = 0 string = "Hello, world!" alire-1.2.1/deps/ada-toml/tests/api/clone/main.adb000066400000000000000000000007031411642634700216570ustar00rootroot00000000000000with Ada.Text_IO; with TOML; with TOML.File_IO; procedure Main is Value : constant TOML.TOML_Value := TOML.File_IO.Load_File ("example.toml").Value; Clone : constant TOML.TOML_Value := Value.Clone; begin -- Mutate Value: the Clone is supposed to be unaffected Value.Set ("hello", TOML.Create_Boolean (true)); Value.Get ("array").Append (TOML.Create_Boolean (false)); Ada.Text_IO.Put_Line (Clone.Dump_As_String); end Main; alire-1.2.1/deps/ada-toml/tests/api/clone/test.out000066400000000000000000000001071411642634700217710ustar00rootroot00000000000000array = [ true, false, ] bool = true int = 0 string = "Hello, world!" alire-1.2.1/deps/ada-toml/tests/api/clone/test.yaml000066400000000000000000000000241411642634700221220ustar00rootroot00000000000000driver: run-program alire-1.2.1/deps/ada-toml/tests/api/compare/000077500000000000000000000000001411642634700206115ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/api/compare/example.toml000066400000000000000000000001031411642634700231330ustar00rootroot00000000000000array = [true, false] bool = true int = 0 string = "Hello, world!" alire-1.2.1/deps/ada-toml/tests/api/compare/main.adb000066400000000000000000000067461411642634700222220ustar00rootroot00000000000000with Ada.Text_IO; with TOML; procedure Main is procedure Assert (Predicate : Boolean; Message : String); -- If Predicate is false, emit the given error Message procedure Assert_Eq (Left, Right : TOML.TOML_Value; Message : String); -- Shortcut for Assert (TOML.Equals (Left, Right), Message) procedure Assert_Ne (Left, Right : TOML.TOML_Value; Message : String); -- Shortcut for Assert (not TOML.Equals (Left, Right), Message) ------------ -- Assert -- ------------ procedure Assert (Predicate : Boolean; Message : String) is begin if not Predicate then Ada.Text_IO.Put_Line ("Test failed: " & Message); end if; end Assert; --------------- -- Assert_Eq -- --------------- procedure Assert_Eq (Left, Right : TOML.TOML_Value; Message : String) is begin Assert (TOML.Equals (Left, Right), Message); end Assert_Eq; --------------- -- Assert_Ne -- --------------- procedure Assert_Ne (Left, Right : TOML.TOML_Value; Message : String) is begin Assert (not TOML.Equals (Left, Right), Message); end Assert_Ne; use TOML; begin Assert_Ne (Create_String ("ABCD"), Create_Integer (0), "different kinds"); Assert_Eq (Create_Boolean (True), Create_Boolean (True), "same boolean"); Assert_Ne (Create_Boolean (True), Create_Boolean (False), "different boolean"); Assert_Eq (Create_Integer (0), Create_Integer (0), "same integer"); Assert_Ne (Create_Integer (0), Create_Integer (1), "different integer"); Assert_Eq (Create_String ("ABCD"), Create_String ("ABCD"), "same string"); Assert_Ne (Create_String ("ABCD"), Create_String ("ABCDE"), "different string"); declare Empty_1 : constant TOML_Value := Create_Array; Empty_2 : constant TOML_Value := Create_Array; One_Int_1 : constant TOML_Value := Create_Array; One_Int_2 : constant TOML_Value := Create_Array; Two_Ints : constant TOML_Value := Create_Array; One_String : constant TOML_Value := Create_Array; begin One_Int_1.Append (Create_Integer (0)); One_Int_2.Append (Create_Integer (0)); Two_Ints.Append (Create_Integer (0)); Two_Ints.Append (Create_Integer (1)); One_String.Append (Create_String ("ABCD")); Assert_Eq (Empty_1, Empty_2, "empty arrays"); Assert_Ne (Empty_1, One_Int_1, "different array length"); Assert_Eq (One_Int_1, One_Int_2, "same int array"); Assert_Ne (One_Int_1, Two_Ints, "different int array"); Assert_Ne (One_Int_1, One_String, "different array item kind"); end; declare Empty_1 : constant TOML_Value := Create_Table; Empty_2 : constant TOML_Value := Create_Table; Same_Key_1 : constant TOML_Value := Create_Table; Same_Key_2 : constant TOML_Value := Create_Table; Same_Key_3 : constant TOML_Value := Create_Table; Different_Key : constant TOML_Value := Create_Table; begin Same_Key_1.Set ("key", Create_Boolean (True)); Same_Key_2.Set ("key", Create_Boolean (True)); Same_Key_3.Set ("key", Create_Boolean (False)); Different_Key.Set ("KEY", Create_Boolean (True)); Assert_Eq (Empty_1, Empty_2, "empty tables"); Assert_Ne (Empty_1, Same_Key_1, "different table size"); Assert_Eq (Same_Key_1, Same_Key_2, "same table content"); Assert_Ne (Same_Key_1, Same_Key_3, "different member value"); Assert_Ne (Same_Key_1, Different_Key, "different key"); end; Ada.Text_IO.Put_Line ("Done"); end Main; alire-1.2.1/deps/ada-toml/tests/api/compare/test.out000066400000000000000000000000051411642634700223140ustar00rootroot00000000000000Done alire-1.2.1/deps/ada-toml/tests/api/compare/test.yaml000066400000000000000000000000241411642634700224500ustar00rootroot00000000000000driver: run-program alire-1.2.1/deps/ada-toml/tests/api/iterate_on_table/000077500000000000000000000000001411642634700224635ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/api/iterate_on_table/example.toml000066400000000000000000000001031411642634700250050ustar00rootroot00000000000000array = [true, false] bool = true int = 0 string = "Hello, world!" alire-1.2.1/deps/ada-toml/tests/api/iterate_on_table/main.adb000066400000000000000000000006301411642634700240560ustar00rootroot00000000000000with Ada.Strings.Unbounded; with Ada.Text_IO; with TOML; with TOML.File_IO; procedure Main is package TIO renames Ada.Text_IO; Value : constant TOML.TOML_Value := TOML.File_IO.Load_File ("example.toml").Value; begin for E of Value.Iterate_On_Table loop TIO.Put_Line (Ada.Strings.Unbounded.To_String (E.Key) & " is a " & E.Value.Kind'Image); end loop; end Main; alire-1.2.1/deps/ada-toml/tests/api/iterate_on_table/test.out000066400000000000000000000001331411642634700241700ustar00rootroot00000000000000array is a TOML_ARRAY bool is a TOML_BOOLEAN int is a TOML_INTEGER string is a TOML_STRING alire-1.2.1/deps/ada-toml/tests/api/iterate_on_table/test.yaml000066400000000000000000000000241411642634700243220ustar00rootroot00000000000000driver: run-program alire-1.2.1/deps/ada-toml/tests/api/merge/000077500000000000000000000000001411642634700202625ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/api/merge/main.adb000066400000000000000000000041011411642634700216520ustar00rootroot00000000000000with Ada.Text_IO; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with TOML; procedure Main is Table1 : constant TOML.TOML_Value := TOML.Create_Table; Table2 : constant TOML.TOML_Value := TOML.Create_Table; Table3 : constant TOML.TOML_Value := TOML.Create_Table; Arr : constant TOML.TOML_Value := TOML.Create_Array; begin -- Populate tables Table1.Set ("a", TOML.Create_Integer (1)); Arr.Append (TOML.Create_Integer (1)); Table2.Set ("b", Arr); Table3.Set ("a", TOML.Create_Integer (3)); -- With the resolver-less Merge overload, expect a constraint error on -- duplicate keys. declare Dummy : TOML.TOML_Value; begin Dummy := TOML.Merge (Table1, Table3); Ada.Text_IO.Put_Line ("No exception..."); exception when Constraint_Error => Ada.Text_IO.Put_Line ("Merging two tables with duplicate keys raises an exception"); end; Ada.Text_IO.New_Line; -- With the resolver overload, check that conflicts are resolved as -- expected Ada.Text_IO.Put_Line ("Merging with conflict resolution..."); declare function Merge_Entries (Key : TOML.Unbounded_UTF8_String; L, R : TOML.TOML_Value) return TOML.TOML_Value is (TOML.Create_String (Key & ": " & L.As_String & " | " & R.As_String)); L : constant TOML.TOML_Value := TOML.Create_Table; R : constant TOML.TOML_Value := TOML.Create_Table; Merged : TOML.TOML_Value; begin L.Set ("a", TOML.Create_String ("good")); L.Set ("b", TOML.Create_String ("hello")); R.Set ("b", TOML.Create_String ("world")); R.Set ("c", TOML.Create_String ("bye")); Merged := TOML.Merge (L, R, Merge_Entries'Access); Ada.Text_IO.Put_Line (Merged.Dump_As_String); end; declare Merged : constant TOML.TOML_Value := TOML.Merge (Table1, Table2); begin -- Change array value to see the shallow copy modified Arr.Append (TOML.Create_Integer (2)); Ada.Text_IO.Put_Line ("Merged table:"); Ada.Text_IO.Put_Line (Merged.Dump_As_String); end; end Main; alire-1.2.1/deps/ada-toml/tests/api/merge/test.out000066400000000000000000000002601411642634700217700ustar00rootroot00000000000000Merging two tables with duplicate keys raises an exception Merging with conflict resolution... a = "good" b = "b: hello | world" c = "bye" Merged table: a = 1 b = [ 1, 2, ] alire-1.2.1/deps/ada-toml/tests/api/merge/test.yaml000066400000000000000000000000241411642634700221210ustar00rootroot00000000000000driver: run-program alire-1.2.1/deps/ada-toml/tests/api/unset/000077500000000000000000000000001411642634700203215ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/api/unset/example.toml000066400000000000000000000001031411642634700226430ustar00rootroot00000000000000array = [true, false] bool = true int = 0 string = "Hello, world!" alire-1.2.1/deps/ada-toml/tests/api/unset/main.adb000066400000000000000000000003721411642634700217170ustar00rootroot00000000000000with Ada.Text_IO; with TOML; with TOML.File_IO; procedure Main is Value : constant TOML.TOML_Value := TOML.File_IO.Load_File ("example.toml").Value; begin Value.Unset ("array"); Ada.Text_IO.Put_Line (Value.Dump_As_String); end Main; alire-1.2.1/deps/ada-toml/tests/api/unset/test.out000066400000000000000000000000561411642634700220320ustar00rootroot00000000000000bool = true int = 0 string = "Hello, world!" alire-1.2.1/deps/ada-toml/tests/api/unset/test.yaml000066400000000000000000000000241411642634700221600ustar00rootroot00000000000000driver: run-program alire-1.2.1/deps/ada-toml/tests/control-chars/000077500000000000000000000000001411642634700211705ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/control-chars/input.toml000066400000000000000000000000401411642634700232160ustar00rootroot00000000000000# empty file with delete char: alire-1.2.1/deps/ada-toml/tests/control-chars/test.yaml000066400000000000000000000000771411642634700230370ustar00rootroot00000000000000driver: decoder error: '1:31: invalid ASCII control character' alire-1.2.1/deps/ada-toml/tests/datetime/000077500000000000000000000000001411642634700202065ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/day-extra-digit/000077500000000000000000000000001411642634700232025ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/day-extra-digit/input.toml000066400000000000000000000000201411642634700252260ustar00rootroot00000000000000d = 0001-01-001 alire-1.2.1/deps/ada-toml/tests/datetime/day-extra-digit/test.yaml000066400000000000000000000000521411642634700250420ustar00rootroot00000000000000driver: decoder error: '1:4: invalid day' alire-1.2.1/deps/ada-toml/tests/datetime/day-miss-digit/000077500000000000000000000000001411642634700230325ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/day-miss-digit/input.toml000066400000000000000000000000161411642634700250630ustar00rootroot00000000000000d = 0001-01-1 alire-1.2.1/deps/ada-toml/tests/datetime/day-miss-digit/test.yaml000066400000000000000000000000521411642634700246720ustar00rootroot00000000000000driver: decoder error: '1:4: invalid day' alire-1.2.1/deps/ada-toml/tests/datetime/day-nondigit/000077500000000000000000000000001411642634700225745ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/day-nondigit/input.toml000066400000000000000000000000171411642634700246260ustar00rootroot00000000000000d = 0001-01-0a alire-1.2.1/deps/ada-toml/tests/datetime/day-nondigit/test.yaml000066400000000000000000000000521411642634700244340ustar00rootroot00000000000000driver: decoder error: '1:4: invalid day' alire-1.2.1/deps/ada-toml/tests/datetime/day-out-of-range/000077500000000000000000000000001411642634700232645ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/day-out-of-range/input.toml000066400000000000000000000000171411642634700253160ustar00rootroot00000000000000d = 0001-01-32 alire-1.2.1/deps/ada-toml/tests/datetime/day-out-of-range/test.yaml000066400000000000000000000000571411642634700251310ustar00rootroot00000000000000driver: decoder error: '1:4: out of range day' alire-1.2.1/deps/ada-toml/tests/datetime/month-bad-sep/000077500000000000000000000000001411642634700226445ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/month-bad-sep/input.toml000066400000000000000000000000171411642634700246760ustar00rootroot00000000000000d = 0001-01:01 alire-1.2.1/deps/ada-toml/tests/datetime/month-bad-sep/test.yaml000066400000000000000000000000541411642634700245060ustar00rootroot00000000000000driver: decoder error: '1:4: invalid month' alire-1.2.1/deps/ada-toml/tests/datetime/month-extra-digit/000077500000000000000000000000001411642634700235525ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/month-extra-digit/input.toml000066400000000000000000000000201411642634700255760ustar00rootroot00000000000000d = 0001-001-01 alire-1.2.1/deps/ada-toml/tests/datetime/month-extra-digit/test.yaml000066400000000000000000000000541411642634700254140ustar00rootroot00000000000000driver: decoder error: '1:4: invalid month' alire-1.2.1/deps/ada-toml/tests/datetime/month-miss-digit/000077500000000000000000000000001411642634700234025ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/month-miss-digit/input.toml000066400000000000000000000000161411642634700254330ustar00rootroot00000000000000d = 0001-1-01 alire-1.2.1/deps/ada-toml/tests/datetime/month-miss-digit/test.yaml000066400000000000000000000000541411642634700252440ustar00rootroot00000000000000driver: decoder error: '1:4: invalid month' alire-1.2.1/deps/ada-toml/tests/datetime/month-nondigit/000077500000000000000000000000001411642634700231445ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/month-nondigit/input.toml000066400000000000000000000000171411642634700251760ustar00rootroot00000000000000d = 0001-0a-01 alire-1.2.1/deps/ada-toml/tests/datetime/month-nondigit/test.yaml000066400000000000000000000000541411642634700250060ustar00rootroot00000000000000driver: decoder error: '1:4: invalid month' alire-1.2.1/deps/ada-toml/tests/datetime/month-out-of-range/000077500000000000000000000000001411642634700236345ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/month-out-of-range/input.toml000066400000000000000000000000171411642634700256660ustar00rootroot00000000000000d = 0001-13-01 alire-1.2.1/deps/ada-toml/tests/datetime/month-out-of-range/test.yaml000066400000000000000000000000611411642634700254740ustar00rootroot00000000000000driver: decoder error: '1:4: out of range month' alire-1.2.1/deps/ada-toml/tests/datetime/second-extra-digit/000077500000000000000000000000001411642634700237005ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/second-extra-digit/input.toml000066400000000000000000000000161411642634700257310ustar00rootroot00000000000000d = 00:00:000 alire-1.2.1/deps/ada-toml/tests/datetime/second-extra-digit/test.yaml000066400000000000000000000000551411642634700255430ustar00rootroot00000000000000driver: decoder error: '1:4: invalid second' alire-1.2.1/deps/ada-toml/tests/datetime/second-miss-digit/000077500000000000000000000000001411642634700235305ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/second-miss-digit/input.toml000066400000000000000000000000141411642634700255570ustar00rootroot00000000000000d = 00:00:0 alire-1.2.1/deps/ada-toml/tests/datetime/second-miss-digit/test.yaml000066400000000000000000000000551411642634700253730ustar00rootroot00000000000000driver: decoder error: '1:4: invalid second' alire-1.2.1/deps/ada-toml/tests/datetime/second-nondigit/000077500000000000000000000000001411642634700232725ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/second-nondigit/input.toml000066400000000000000000000000151411642634700253220ustar00rootroot00000000000000d = 00:00:0a alire-1.2.1/deps/ada-toml/tests/datetime/second-nondigit/test.yaml000066400000000000000000000000551411642634700251350ustar00rootroot00000000000000driver: decoder error: '1:4: invalid second' alire-1.2.1/deps/ada-toml/tests/datetime/second-out-of-range/000077500000000000000000000000001411642634700237625ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/second-out-of-range/input.toml000066400000000000000000000000151411642634700260120ustar00rootroot00000000000000d = 00:00:61 alire-1.2.1/deps/ada-toml/tests/datetime/second-out-of-range/test.yaml000066400000000000000000000000621411642634700256230ustar00rootroot00000000000000driver: decoder error: '1:4: out of range second' alire-1.2.1/deps/ada-toml/tests/datetime/tzhour-out-of-range/000077500000000000000000000000001411642634700240425ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/tzhour-out-of-range/input.toml000066400000000000000000000000361411642634700260750ustar00rootroot00000000000000d = 0001-01-01 00:00:00+24:00 alire-1.2.1/deps/ada-toml/tests/datetime/tzhour-out-of-range/test.yaml000066400000000000000000000000671411642634700257100ustar00rootroot00000000000000driver: decoder error: '1:4: out of range hour offset' alire-1.2.1/deps/ada-toml/tests/datetime/tzminute-out-of-range/000077500000000000000000000000001411642634700243665ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/tzminute-out-of-range/input.toml000066400000000000000000000000361411642634700264210ustar00rootroot00000000000000d = 0001-01-01 00:00:00+23:60 alire-1.2.1/deps/ada-toml/tests/datetime/tzminute-out-of-range/test.yaml000066400000000000000000000000711411642634700262270ustar00rootroot00000000000000driver: decoder error: '1:4: out of range minute offset' alire-1.2.1/deps/ada-toml/tests/datetime/valid/000077500000000000000000000000001411642634700213055ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/valid/input.toml000066400000000000000000000013111411642634700233350ustar00rootroot00000000000000d1 = 0001-01-01 d2 = 9999-12-31 d3 = 1970-02-28 d4 = [0001-01-01 ,9999-12-31] t1 = 00:00:00 t2 = 00:00:00.0 t3 = 00:00:00.1 t4 = 00:00:00.00 t5 = 00:00:00.01 t6 = 00:00:00.10 t7 = 00:00:00.000 t8 = 00:00:00.001 t9 = 00:00:00.010 t10 = 00:00:00.100 t11 = 00:00:01.000 t12 = 23:59:60.999 t13 = 23:59:60.9999 ldt1 = 0001-01-01T00:00:00 ldt2 = 0001-01-01 00:00:00 ldt3 = 9999-12-31 23:59:59.999 odt1 = 0001-01-01T00:00:00Z odt2 = 0001-01-01 00:00:00+00:00 odt3 = 0001-01-01 00:00:00-00:00 odt4 = 0001-01-01 00:00:00+01:01 odt5 = 0001-01-01 00:00:00-01:01 odt6 = 0001-01-01 00:00:00+23:59 odt7 = 0001-01-01 00:00:00-23:59 odt8 = 9999-12-31 23:59:59.999Z odt9 = 0001-01-01t00:00:00Z odt10 = 0001-01-01T00:00:00z alire-1.2.1/deps/ada-toml/tests/datetime/valid/test.yaml000066400000000000000000000037111411642634700231520ustar00rootroot00000000000000driver: decoder output: { "d1": {"type": "date-local", "value": "0001-01-01"}, "d2": {"type": "date-local", "value": "9999-12-31"}, "d3": {"type": "date-local", "value": "1970-02-28"}, "d4": [{"type": "date-local", "value": "0001-01-01"}, {"type": "date-local", "value": "9999-12-31"}], "t1": {"type": "time-local", "value": "00:00:00"}, "t2": {"type": "time-local", "value": "00:00:00"}, "t3": {"type": "time-local", "value": "00:00:00.100"}, "t4": {"type": "time-local", "value": "00:00:00"}, "t5": {"type": "time-local", "value": "00:00:00.010"}, "t6": {"type": "time-local", "value": "00:00:00.100"}, "t7": {"type": "time-local", "value": "00:00:00"}, "t8": {"type": "time-local", "value": "00:00:00.001"}, "t9": {"type": "time-local", "value": "00:00:00.010"}, "t10": {"type": "time-local", "value": "00:00:00.100"}, "t11": {"type": "time-local", "value": "00:00:01"}, "t12": {"type": "time-local", "value": "23:59:60.999"}, "t13": {"type": "time-local", "value": "23:59:60.999"}, "ldt1": {"type": "datetime-local", "value": "0001-01-01T00:00:00"}, "ldt2": {"type": "datetime-local", "value": "0001-01-01T00:00:00"}, "ldt3": {"type": "datetime-local", "value": "9999-12-31T23:59:59.999"}, "odt1": {"type": "datetime", "value": "0001-01-01T00:00:00Z"}, "odt2": {"type": "datetime", "value": "0001-01-01T00:00:00Z"}, "odt3": {"type": "datetime", "value": "0001-01-01T00:00:00-00:00"}, "odt4": {"type": "datetime", "value": "0001-01-01T00:00:00+01:01"}, "odt5": {"type": "datetime", "value": "0001-01-01T00:00:00-01:01"}, "odt6": {"type": "datetime", "value": "0001-01-01T00:00:00+23:59"}, "odt7": {"type": "datetime", "value": "0001-01-01T00:00:00-23:59"}, "odt8": {"type": "datetime", "value": "9999-12-31T23:59:59.999Z"}, "odt9": {"type": "datetime", "value": "0001-01-01T00:00:00Z"}, "odt10": {"type": "datetime", "value": "0001-01-01T00:00:00Z"} } alire-1.2.1/deps/ada-toml/tests/datetime/year-extra-digit/000077500000000000000000000000001411642634700233655ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/year-extra-digit/input.toml000066400000000000000000000000201411642634700254110ustar00rootroot00000000000000d = 00001-01-01 alire-1.2.1/deps/ada-toml/tests/datetime/year-extra-digit/test.yaml000066400000000000000000000000531411642634700252260ustar00rootroot00000000000000driver: decoder error: '1:4: invalid year' alire-1.2.1/deps/ada-toml/tests/datetime/year-miss-digit/000077500000000000000000000000001411642634700232155ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/year-miss-digit/input.toml000066400000000000000000000000161411642634700252460ustar00rootroot00000000000000d = 001-01-01 alire-1.2.1/deps/ada-toml/tests/datetime/year-miss-digit/test.yaml000066400000000000000000000000531411642634700250560ustar00rootroot00000000000000driver: decoder error: '1:4: invalid year' alire-1.2.1/deps/ada-toml/tests/datetime/year-out-of-range/000077500000000000000000000000001411642634700234475ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/datetime/year-out-of-range/input.toml000066400000000000000000000000171411642634700255010ustar00rootroot00000000000000d = 0000-01-01 alire-1.2.1/deps/ada-toml/tests/datetime/year-out-of-range/test.yaml000066400000000000000000000000601411642634700253060ustar00rootroot00000000000000driver: decoder error: '1:4: out of range year' alire-1.2.1/deps/ada-toml/tests/float/000077500000000000000000000000001411642634700175175ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/float/exp-nondigit/000077500000000000000000000000001411642634700221245ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/float/exp-nondigit/input.toml000066400000000000000000000000101411642634700241470ustar00rootroot00000000000000f = 0ea alire-1.2.1/deps/ada-toml/tests/float/exp-nondigit/test.yaml000066400000000000000000000000541411642634700237660ustar00rootroot00000000000000driver: decoder error: '1:4: invalid float' alire-1.2.1/deps/ada-toml/tests/float/exp-too-big-1/000077500000000000000000000000001411642634700220075ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/float/exp-too-big-1/input.toml000066400000000000000000000000151411642634700240370ustar00rootroot00000000000000f = 1e999999 alire-1.2.1/deps/ada-toml/tests/float/exp-too-big-1/test.yaml000066400000000000000000000001071411642634700236500ustar00rootroot00000000000000driver: decoder output: { "f": {"type": "float", "value": "0.0"} } alire-1.2.1/deps/ada-toml/tests/float/exp-too-big-2/000077500000000000000000000000001411642634700220105ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/float/exp-too-big-2/input.toml000066400000000000000000000000771411642634700240500ustar00rootroot00000000000000f = 0e99999999999999999999999999999999999999999999999999999999 alire-1.2.1/deps/ada-toml/tests/float/exp-too-big-2/test.yaml000066400000000000000000000000561411642634700236540ustar00rootroot00000000000000driver: decoder error: '1:4: too large float' alire-1.2.1/deps/ada-toml/tests/float/fract-nondigit/000077500000000000000000000000001411642634700224275ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/float/fract-nondigit/input.toml000066400000000000000000000000101411642634700244520ustar00rootroot00000000000000f = 0.a alire-1.2.1/deps/ada-toml/tests/float/fract-nondigit/test.yaml000066400000000000000000000000541411642634700242710ustar00rootroot00000000000000driver: decoder error: '1:4: invalid float' alire-1.2.1/deps/ada-toml/tests/float/fract-too-big/000077500000000000000000000000001411642634700221545ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/float/fract-too-big/input.toml000066400000000000000000000000771411642634700242140ustar00rootroot00000000000000f = 0.99999999999999999999999999999999999999999999999999999999 alire-1.2.1/deps/ada-toml/tests/float/fract-too-big/test.yaml000066400000000000000000000000561411642634700240200ustar00rootroot00000000000000driver: decoder error: '1:4: too large float' alire-1.2.1/deps/ada-toml/tests/float/missing-first-digit/000077500000000000000000000000001411642634700234135ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/float/missing-first-digit/input.toml000066400000000000000000000000101411642634700254360ustar00rootroot00000000000000f = -.1 alire-1.2.1/deps/ada-toml/tests/float/missing-first-digit/test.yaml000066400000000000000000000000541411642634700252550ustar00rootroot00000000000000driver: decoder error: '1:4: invalid float' alire-1.2.1/deps/ada-toml/tests/float/valid/000077500000000000000000000000001411642634700206165ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/float/valid/input.toml000066400000000000000000000001551411642634700226530ustar00rootroot00000000000000f1 = nan f2 = +nan f3 = -nan f4 = inf f5 = +inf f6 = -inf f7 = 0.0 f8 = 0e0 f9 = 1.2e3 f10 = 1_2.3_4_5e6_7 alire-1.2.1/deps/ada-toml/tests/float/valid/test.yaml000066400000000000000000000007541411642634700224670ustar00rootroot00000000000000driver: decoder output: { "f1": {"type": "float", "value": "nan"}, "f2": {"type": "float", "value": "nan"}, "f3": {"type": "float", "value": "-nan"}, "f4": {"type": "float", "value": "inf"}, "f5": {"type": "float", "value": "inf"}, "f6": {"type": "float", "value": "-inf"}, "f7": {"type": "float", "value": "0.0"}, "f8": {"type": "float", "value": "0.0"}, "f9": {"type": "float", "value": "1200.0"}, "f10": {"type": "float", "value": "12.345e67"}, } alire-1.2.1/deps/ada-toml/tests/integer/000077500000000000000000000000001411642634700200475ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/integer/in-collections/000077500000000000000000000000001411642634700227715ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/integer/in-collections/input.toml000066400000000000000000000000501411642634700250200ustar00rootroot00000000000000a = [0, 1] b = [[0], [1]] c = {"d" = 2} alire-1.2.1/deps/ada-toml/tests/integer/in-collections/test.yaml000066400000000000000000000004621411642634700246360ustar00rootroot00000000000000driver: decoder output: { "a": [ {"type": "integer", "value": "0"}, {"type": "integer", "value": "1"}, ], "b": [ [{"type": "integer", "value": "0"}], [{"type": "integer", "value": "1"}], ], "c": { "d": {"type": "integer", "value": "2"}, }, } alire-1.2.1/deps/ada-toml/tests/integer/leading-underscore/000077500000000000000000000000001411642634700236215ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/integer/leading-underscore/input.toml000066400000000000000000000000101411642634700256440ustar00rootroot00000000000000n = _42 alire-1.2.1/deps/ada-toml/tests/integer/leading-underscore/test.yaml000066400000000000000000000000541411642634700254630ustar00rootroot00000000000000driver: decoder error: '1:4: invalid token' alire-1.2.1/deps/ada-toml/tests/integer/non-decimal-minus/000077500000000000000000000000001411642634700233665ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/integer/non-decimal-minus/input.toml000066400000000000000000000000111411642634700254120ustar00rootroot00000000000000n = +0b1 alire-1.2.1/deps/ada-toml/tests/integer/non-decimal-minus/test.yaml000066400000000000000000000001111411642634700252220ustar00rootroot00000000000000driver: decoder error: '1:4: explicit sign not allowed but for decimals' alire-1.2.1/deps/ada-toml/tests/integer/non-decimal-plus/000077500000000000000000000000001411642634700232165ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/integer/non-decimal-plus/input.toml000066400000000000000000000000111411642634700252420ustar00rootroot00000000000000n = -0b1 alire-1.2.1/deps/ada-toml/tests/integer/non-decimal-plus/test.yaml000066400000000000000000000001111411642634700250520ustar00rootroot00000000000000driver: decoder error: '1:4: explicit sign not allowed but for decimals' alire-1.2.1/deps/ada-toml/tests/integer/nondigit/000077500000000000000000000000001411642634700216625ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/integer/nondigit/input.toml000066400000000000000000000000101411642634700237050ustar00rootroot00000000000000n = 01a alire-1.2.1/deps/ada-toml/tests/integer/nondigit/test.yaml000066400000000000000000000000541411642634700235240ustar00rootroot00000000000000driver: decoder error: '1:4: invalid token' alire-1.2.1/deps/ada-toml/tests/integer/trailing-underscore/000077500000000000000000000000001411642634700240275ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/integer/trailing-underscore/input.toml000066400000000000000000000000101411642634700260520ustar00rootroot00000000000000n = 42_ alire-1.2.1/deps/ada-toml/tests/integer/trailing-underscore/test.yaml000066400000000000000000000001071411642634700256700ustar00rootroot00000000000000driver: decoder error: '1:4: underscores must be surrounded by digits' alire-1.2.1/deps/ada-toml/tests/integer/underscore-after-base/000077500000000000000000000000001411642634700242275ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/integer/underscore-after-base/input.toml000066400000000000000000000000111411642634700262530ustar00rootroot00000000000000n = 0b_1 alire-1.2.1/deps/ada-toml/tests/integer/underscore-after-base/test.yaml000066400000000000000000000001071411642634700260700ustar00rootroot00000000000000driver: decoder error: '1:4: underscores must be surrounded by digits' alire-1.2.1/deps/ada-toml/tests/sections/000077500000000000000000000000001411642634700202415ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/arrays/000077500000000000000000000000001411642634700215425ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/arrays/input.toml000066400000000000000000000000711411642634700235740ustar00rootroot00000000000000[[a]] key1 = true [[a]] key2 = true [a.b] key3 = false alire-1.2.1/deps/ada-toml/tests/sections/arrays/test.yaml000066400000000000000000000004121411642634700234020ustar00rootroot00000000000000driver: decoder output : { "a": [ {"key1": {"type": "bool", "value": "true"}}, { "key2": {"type": "bool", "value": "true"}, "b": { "key3": {"type": "bool", "value": "false"} } } ] } alire-1.2.1/deps/ada-toml/tests/sections/heterogeneous-array/000077500000000000000000000000001411642634700242315ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/heterogeneous-array/input.toml000066400000000000000000000000151411642634700262610ustar00rootroot00000000000000a = [1, "a"] alire-1.2.1/deps/ada-toml/tests/sections/heterogeneous-array/test.yaml000066400000000000000000000003001411642634700260650ustar00rootroot00000000000000driver: decoder output: { "a": { "type": "array", "value": [ {"type": "integer", "value": "1"}, {"type": "string", "value": "a"}, ] } } alire-1.2.1/deps/ada-toml/tests/sections/key-escapes/000077500000000000000000000000001411642634700224525ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/key-escapes/input.toml000066400000000000000000000001051411642634700245020ustar00rootroot00000000000000'0.0' = 1 '0.1'.2 = 2 'key' = 3 "\u0000" = 4 '\u0000' = 5 ['0.1.2'] alire-1.2.1/deps/ada-toml/tests/sections/key-escapes/test.yaml000066400000000000000000000004541411642634700243200ustar00rootroot00000000000000driver: decoder output : { "0.0": {"type": "integer", "value": "1"}, "0.1": {"2": {"type": "integer", "value": "2"}}, "key": {"type": "integer", "value": "3"}, "\u0000": {"type": "integer", "value": "4"}, "\\u0000": {"type": "integer", "value": "5"}, "0.1.2": {}, } alire-1.2.1/deps/ada-toml/tests/sections/key-multiline/000077500000000000000000000000001411642634700230315ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/key-multiline/input.toml000066400000000000000000000000161411642634700250620ustar00rootroot00000000000000"""a b""" = 1 alire-1.2.1/deps/ada-toml/tests/sections/key-multiline/test.yaml000066400000000000000000000000551411642634700246740ustar00rootroot00000000000000driver: decoder error: '1:1: invalid syntax' alire-1.2.1/deps/ada-toml/tests/sections/missing-newline/000077500000000000000000000000001411642634700233515ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/missing-newline/input.toml000066400000000000000000000000141411642634700254000ustar00rootroot00000000000000a = 1 b = 2 alire-1.2.1/deps/ada-toml/tests/sections/missing-newline/test.yaml000066400000000000000000000000561411642634700252150ustar00rootroot00000000000000driver: decoder error: '1:6: missing newline' alire-1.2.1/deps/ada-toml/tests/sections/redef-explicit-array/000077500000000000000000000000001411642634700242615ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/redef-explicit-array/input.toml000066400000000000000000000000321411642634700263100ustar00rootroot00000000000000a = [] [[a]] key1 = true alire-1.2.1/deps/ada-toml/tests/sections/redef-explicit-array/test.yaml000066400000000000000000000001151411642634700261210ustar00rootroot00000000000000driver: decoder error: '3:1: arrays of tables cannot complete inline arrays' alire-1.2.1/deps/ada-toml/tests/sections/redef-explicit/000077500000000000000000000000001411642634700231455ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/redef-explicit/input.toml000066400000000000000000000000311411642634700251730ustar00rootroot00000000000000[a] foo = 1 [a] bar = 2 alire-1.2.1/deps/ada-toml/tests/sections/redef-explicit/test.yaml000066400000000000000000000000711411642634700250060ustar00rootroot00000000000000driver: decoder error: '4:1: cannot create tables twice' alire-1.2.1/deps/ada-toml/tests/sections/redef-implicit-array/000077500000000000000000000000001411642634700242525ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/redef-implicit-array/input.toml000066400000000000000000000000321411642634700263010ustar00rootroot00000000000000[[a.b]] c = 0 [[a]] c = 1 alire-1.2.1/deps/ada-toml/tests/sections/redef-implicit-array/test.yaml000066400000000000000000000000541411642634700261140ustar00rootroot00000000000000driver: decoder error: '3:1: invalid array' alire-1.2.1/deps/ada-toml/tests/sections/redef-implicit/000077500000000000000000000000001411642634700231365ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/redef-implicit/input.toml000066400000000000000000000000331411642634700251660ustar00rootroot00000000000000[a.b] foo = 1 [a] bar = 2 alire-1.2.1/deps/ada-toml/tests/sections/redef-implicit/test.yaml000066400000000000000000000002561411642634700250040ustar00rootroot00000000000000driver: decoder output: { "a": { "bar": {"type": "integer", "value": "2"}, "b": { "foo": {"type": "integer", "value": "1"}, } } } alire-1.2.1/deps/ada-toml/tests/sections/surrogates/000077500000000000000000000000001411642634700224375ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/surrogates/input.toml000066400000000000000000000000121411642634700244640ustar00rootroot00000000000000aí£¿b = 0 alire-1.2.1/deps/ada-toml/tests/sections/surrogates/test.yaml000066400000000000000000000000771411642634700243060ustar00rootroot00000000000000driver: decoder error: '1:2: surrogate codepoints are invalid' alire-1.2.1/deps/ada-toml/tests/sections/tables/000077500000000000000000000000001411642634700215135ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/sections/tables/input.toml000066400000000000000000000001021411642634700235400ustar00rootroot00000000000000[a] key1 = true [a.b] key2 = true [c] key3 = false a.b.c = true alire-1.2.1/deps/ada-toml/tests/sections/tables/test.yaml000066400000000000000000000005471411642634700233640ustar00rootroot00000000000000driver: decoder output: { "a": { "key1": {"type": "bool", "value": "true"}, "b": { "key2": {"type": "bool", "value": "true"} } }, "c": { "key3": {"type": "bool", "value": "false"}, "a": { "b": { "c": {"type": "bool", "value": "true"} } } } } alire-1.2.1/deps/ada-toml/tests/simple/000077500000000000000000000000001411642634700177035ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/simple/input.toml000066400000000000000000000000111411642634700217270ustar00rootroot00000000000000a = true alire-1.2.1/deps/ada-toml/tests/simple/test.yaml000066400000000000000000000001071411642634700215440ustar00rootroot00000000000000driver: decoder output: { "a": {"type": "bool", "value": "true"} } alire-1.2.1/deps/ada-toml/tests/strings/000077500000000000000000000000001411642634700201035ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/strings/empty-strings/000077500000000000000000000000001411642634700227305ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/strings/empty-strings/input.toml000066400000000000000000000000471411642634700247650ustar00rootroot00000000000000s1 = "" s2 = "" # Comment s3 = {""=""} alire-1.2.1/deps/ada-toml/tests/strings/empty-strings/test.yaml000066400000000000000000000002441411642634700245730ustar00rootroot00000000000000driver: decoder output : { "s1": {"type": "string", "value": ""}, "s2": {"type": "string", "value": ""}, "s3": {"": {"type": "string", "value": ""}}, } alire-1.2.1/deps/ada-toml/tests/strings/escapes/000077500000000000000000000000001411642634700215265ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/strings/escapes/input.toml000066400000000000000000000002331411642634700235600ustar00rootroot00000000000000null = "\u0000" bell = "\u0007" del = "\u007f" bs = "\b" ht = "\t" lf = "\n" ff = "\f" cr = "\r" quote = "\"" backslash = "\\" others = "~Héllo Wörld!~" alire-1.2.1/deps/ada-toml/tests/strings/escapes/test.yaml000066400000000000000000000011731411642634700233730ustar00rootroot00000000000000driver: decoder output : { "null": {"type": "string", "value": "\u0000"}, "bell": {"type": "string", "value": "\u0007"}, "del": {"type": "string", "value": "\u007f"}, "bs": {"type": "string", "value": "\b"}, "ht": {"type": "string", "value": "\t"}, "lf": {"type": "string", "value": "\n"}, "ff": {"type": "string", "value": "\f"}, "cr": {"type": "string", "value": "\r"}, "quote": {"type": "string", "value": "\""}, "backslash": {"type": "string", "value": "\\"}, "others": {"type": "string", "value": "~H\u00e9llo W\u00f6rld!~"}, } alire-1.2.1/deps/ada-toml/tests/strings/invalid-backslash-space/000077500000000000000000000000001411642634700245535ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/strings/invalid-backslash-space/input.toml000066400000000000000000000000221411642634700266010ustar00rootroot00000000000000foo = """a\ b """ alire-1.2.1/deps/ada-toml/tests/strings/invalid-backslash-space/test.yaml000066400000000000000000000000671411642634700264210ustar00rootroot00000000000000driver: decoder error: "1:11: invalid escape sequence" alire-1.2.1/deps/ada-toml/tests/strings/line-ending-backslash/000077500000000000000000000000001411642634700242255ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/strings/line-ending-backslash/input.toml000066400000000000000000000004231411642634700262600ustar00rootroot00000000000000# The following strings are byte-for-byte equivalent: str1 = "The quick brown fox jumps over the lazy dog." str2 = """ The quick brown \ fox jumps over \ the lazy dog.""" str3 = """\ The quick brown \ fox jumps over \ the lazy dog.\ """ alire-1.2.1/deps/ada-toml/tests/strings/line-ending-backslash/test.yaml000066400000000000000000000005161411642634700260720ustar00rootroot00000000000000driver: decoder output: { "str1": {"type": "string", "value": "The quick brown fox jumps over the lazy dog."}, "str2": {"type": "string", "value": "The quick brown fox jumps over the lazy dog."}, "str3": {"type": "string", "value": "The quick brown fox jumps over the lazy dog."}, } alire-1.2.1/deps/ada-toml/tests/strings/multiline-ambiguous-closing/000077500000000000000000000000001411642634700255325ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/strings/multiline-ambiguous-closing/input.toml000066400000000000000000000003001411642634700275570ustar00rootroot00000000000000sdq = """"Single double quotes"""" ddq = """""Double double quotes""""" ssq = ''''Single single quotes'''' dsq = '''''Double single quotes''''' v1 = """Variant 1\"""" v2 = '''Variant 2\'''' alire-1.2.1/deps/ada-toml/tests/strings/multiline-ambiguous-closing/test.yaml000066400000000000000000000006211411642634700273740ustar00rootroot00000000000000driver: decoder output: { "sdq": {"type": "string", "value": "\"Single double quotes\""}, "ddq": {"type": "string", "value": "\"\"Double double quotes\"\""}, "ssq": {"type": "string", "value": "'Single single quotes'"}, "dsq": {"type": "string", "value": "''Double single quotes''"}, "v1": {"type": "string", "value": "Variant 1\""}, "v2": {"type": "string", "value": "Variant 2\\'"}, } alire-1.2.1/deps/ada-toml/tests/strings/surrogate/000077500000000000000000000000001411642634700221165ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/strings/surrogate/input.toml000066400000000000000000000000151411642634700241460ustar00rootroot00000000000000a = "\uDABC" alire-1.2.1/deps/ada-toml/tests/strings/surrogate/test.yaml000066400000000000000000000000771411642634700237650ustar00rootroot00000000000000driver: decoder error: "1:6: surrogate codepoints are invalid" alire-1.2.1/deps/ada-toml/tests/strings/tab/000077500000000000000000000000001411642634700206515ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/strings/tab/input.toml000066400000000000000000000000101411642634700226740ustar00rootroot00000000000000s = " " alire-1.2.1/deps/ada-toml/tests/strings/tab/test.yaml000066400000000000000000000001111411642634700225050ustar00rootroot00000000000000driver: decoder output : { "s": {"type": "string", "value": "\t"}, } alire-1.2.1/deps/ada-toml/tests/tables/000077500000000000000000000000001411642634700176645ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/tables/nested-empty/000077500000000000000000000000001411642634700223025ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/tables/nested-empty/input.toml000066400000000000000000000000231411642634700243310ustar00rootroot00000000000000empty = [ [ {} ] ] alire-1.2.1/deps/ada-toml/tests/tables/nested-empty/test.yaml000066400000000000000000000003501411642634700241430ustar00rootroot00000000000000driver: decoder output: { "empty": { "type": "array", "value": [ { "type": "array", "value": [ {} ] } ] } } alire-1.2.1/deps/ada-toml/tests/tables/trailing-comma/000077500000000000000000000000001411642634700225675ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/tables/trailing-comma/input.toml000066400000000000000000000000401411642634700246150ustar00rootroot00000000000000animal = { type.name = "pug", } alire-1.2.1/deps/ada-toml/tests/tables/trailing-comma/test.yaml000066400000000000000000000000661411642634700244340ustar00rootroot00000000000000driver: decoder error: '1:31: invalid trailing comma' alire-1.2.1/deps/ada-toml/tests/tables/valid/000077500000000000000000000000001411642634700207635ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/tables/valid/input.toml000066400000000000000000000000371411642634700230170ustar00rootroot00000000000000animal = { type.name = "pug" } alire-1.2.1/deps/ada-toml/tests/tables/valid/test.yaml000066400000000000000000000002051411642634700226230ustar00rootroot00000000000000driver: decoder output: { "animal": { "type": { "name": {"type": "string", "value": "pug"} } } } alire-1.2.1/deps/ada-toml/tests/token-1-sloc/000077500000000000000000000000001411642634700206265ustar00rootroot00000000000000alire-1.2.1/deps/ada-toml/tests/token-1-sloc/input.toml000066400000000000000000000000021411642634700226520ustar00rootroot00000000000000^ alire-1.2.1/deps/ada-toml/tests/token-1-sloc/test.yaml000066400000000000000000000000541411642634700224700ustar00rootroot00000000000000driver: decoder error: '1:1: invalid token' pax_global_header00006660000000000000000000000064140273461270014520gustar00rootroot0000000000000052 comment=e5d01db5e7834d15c4066f0a8e33d780deae3cc9 alire-1.2.1/deps/ajunitgen/000077500000000000000000000000001402734612700155345ustar00rootroot00000000000000alire-1.2.1/deps/ajunitgen/.gitignore000066400000000000000000000001341402734612700175220ustar00rootroot00000000000000# Object file *.o obj # Ada Library Information *.ali # Alire /alire/ /config/ alire.lock alire-1.2.1/deps/ajunitgen/LICENSE000066400000000000000000000167431402734612700165540ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. alire-1.2.1/deps/ajunitgen/README.md000066400000000000000000000005521402734612700170150ustar00rootroot00000000000000# AJUnitGen Generator of JUnit-compatible XML reports in Ada No-nonsense straighforward generator of reports, without the need of having a real test-suite like AUnit of Ahven. Useful to report results in a custom test setup. Depends on [XML_EZ_Out](https://github.com/alire-project/xmlezout). Part of the [Alire Project](https://github.com/alire-project/). alire-1.2.1/deps/ajunitgen/ajunitgen.gpr000066400000000000000000000010031402734612700202240ustar00rootroot00000000000000with "xml_ez_out"; project Ajunitgen is for Source_Dirs use ("src"); for Object_Dir use "obj"; package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnato", "-fstack-check", "-gnata", "-gnat12"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; package Linker is for Switches ("ada") use ("-g"); end Linker; end Ajunitgen; alire-1.2.1/deps/ajunitgen/alire.toml000066400000000000000000000004561402734612700175320ustar00rootroot00000000000000name = "ajunitgen" version = "1.0.2-dev" description = "Generator of JUnit-compatible XML reports" authors = [ "Alejandro R. Mosteo", ] licenses = "LGPL-3.0-only" maintainers = [ "alejandro@mosteo.com", ] maintainers-logins = [ "mosteo", ] tags = ["junit", "xml"] [[depends-on]] xml_ez_out = "^1.6" alire-1.2.1/deps/ajunitgen/src/000077500000000000000000000000001402734612700163235ustar00rootroot00000000000000alire-1.2.1/deps/ajunitgen/src/ajunitgen.adb000066400000000000000000000117221402734612700207620ustar00rootroot00000000000000with Ada.Strings.Unbounded; with McKae.XML.EZ_Out.Text_File; package body AJUnitGen is --------------- -- Add_Suite -- --------------- procedure Add_Suite (Col : in out Collection; Suite : Test_Suite'Class) is begin Col.Append (Test_Suite (Suite)); end Add_Suite; -------------- -- Add_Case -- -------------- procedure Add_Case (Suite : in out Test_Suite; Test : Test_Case) is begin Suite.Tests.Append (Test); Suite.Size := Suite.Size + 1; Suite.Counters (Test.Outcome) := Suite.Counters (Test.Outcome) + 1; end Add_Case; --------------- -- New_Suite -- --------------- function New_Suite (Name : String) return Test_Suite is begin return (Name'Length, Name, others => <>); end New_Suite; -------------- -- New_Case -- -------------- function New_Case (Name : String; Outcome : Outcomes := Pass; Classname : String := ""; Message : String := ""; Output : String := "") return Test_Case is begin return (Name'Length, Classname'Length, Message'Length, Output'Length, Name, Outcome, Classname, Message, Output); end New_Case; ------------------- -- To_Collection -- ------------------- function To_Collection (Suite : Test_Suite) return Collection'Class is Result : Collection; begin Result.Append (Suite); return Result; end To_Collection; ----------- -- Write -- ----------- procedure Write (Col : Collection; File : Ada.Text_IO.File_Type) is use McKae.XML.EZ_Out.Text_File; Id : Natural := 0; begin Output_XML_Header (File); Start_Element (File, "testsuites"); for S of Col loop Start_Element (File, "testsuite", ("name" = S.Name, "id" = Id, "tests" = S.Size, "errors" = S.Counters (Error), "failures" = S.Counters (Fail), "skipped" = S.Counters (Skip))); for T of S.Tests loop -- Element start case T.Outcome is when Pass => Output_Element (File, "testcase", Content => "", Attrs => ("name" = T.Name, "classname" = T.Classname, "status" = T.Outcome'Img)); when others => Start_Element (File, "testcase", Attrs => ("name" = T.Name, "classname" = T.Classname, "status" = T.Outcome'Img)); end case; -- Element content case T.Outcome is when Pass => null; when Error => Output_Element (File, "error", T.Output, "message" = T.Message); when Fail => Output_Element (File, "failure", T.Output, "message" = T.Message); when Skip => Output_Element (File, "skipped", T.Output, "message" = T.Message); end case; -- Element end case T.Outcome is when Pass => null; when others => End_Element (File, "testcase"); end case; end loop; End_Element (File, "testsuite"); Id := Id + 1; end loop; End_Element (File, "testsuites"); end Write; Unsafe_Chars : constant array (Character) of Boolean := ('&' | ''' | '"' | '<' | '>' => True, others => False); type String_Access is access constant String; Replacings : constant array (Character) of String_Access := ('&' => new String'("&"), ''' => new String'("'"), '"' => new String'("""), '<' => new String'("<"), '>' => new String'(">"), others => new String'("")); ------------ -- Escape -- ------------ function Escape (S : in String) return String is use Ada.Strings.Unbounded; package ASU renames Ada.Strings.Unbounded; Aux : Unbounded_String := To_Unbounded_String (S); Pos : Positive := 1; Cur : Character; begin loop exit when Pos > ASU.Length (Aux); Cur := ASU.Element (Aux, Pos); if Unsafe_Chars (Cur) then ASU.Replace_Slice (Aux, Pos, Pos, Replacings (Cur).all); end if; Pos := Pos + 1; end loop; return To_String (Aux); end Escape; end AJUnitGen; alire-1.2.1/deps/ajunitgen/src/ajunitgen.ads000066400000000000000000000046761402734612700210150ustar00rootroot00000000000000with Ada.Containers.Indefinite_Doubly_Linked_Lists; with Ada.Text_IO; package AJUnitGen is -- Simple package to generate JUnit-compatible XML reports -- Create suites with the constructor function -- Add test cases to suites type Collection is tagged private; type Test_Suite (<>) is tagged private; type Test_Case (<>) is private; type Outcomes is (Pass, Error, Fail, Skip); procedure Add_Suite (Col : in out Collection; Suite : Test_Suite'Class); procedure Add_Case (Suite : in out Test_Suite; Test : Test_Case); function New_Suite (Name : String) return Test_Suite; function New_Case (Name : String; Outcome : Outcomes := Pass; Classname : String := ""; Message : String := ""; Output : String := "") return Test_Case; -- Classname is the code location failing -- Message is a short attribute message on the reason of not PASS -- Output is a multiline text child element (e.g. a trace) function To_Collection (Suite : Test_Suite) return Collection'Class; -- Collection containing a single suite procedure Write (Col : Collection; File : Ada.Text_IO.File_Type); -- Write to an already open file -- UTILS function Escape (S : String) return String; -- Encodes an ASCII string for XML validity. -- Used internally but might be generally useful private -- In truth Escape is not needed since XML EZ Out already escapes as needed type Outcome_Counters is array (Outcomes) of Natural; type Test_Case (Name_Len, Class_Len, Msg_Len, Out_Len : Natural) is record Name : String (1 .. Name_Len); Outcome : Outcomes; Classname : String (1 .. Class_Len); Message : String (1 .. Msg_Len); Output : String (1 .. Out_Len); end record; package Test_Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Test_Case); type Test_Suite (Name_Len : Natural) is tagged record Name : String (1 .. Name_Len); Tests : Test_Lists.List; Size : Natural := 0; Counters : Outcome_Counters := (others => 0); end record; package Suite_Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Test_Suite); type Collection is new Suite_Lists.List with null record; end AJUnitGen; pax_global_header00006660000000000000000000000064140273471300014513gustar00rootroot0000000000000052 comment=acf9afca3afe1f8b8843c061f3cef860d7567307 alire-1.2.1/deps/ansi/000077500000000000000000000000001402734713000144755ustar00rootroot00000000000000alire-1.2.1/deps/ansi/.github/000077500000000000000000000000001402734713000160355ustar00rootroot00000000000000alire-1.2.1/deps/ansi/.github/workflows/000077500000000000000000000000001402734713000200725ustar00rootroot00000000000000alire-1.2.1/deps/ansi/.github/workflows/build.yml000066400000000000000000000005611402734713000217160ustar00rootroot00000000000000name: Build on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Set up GNAT toolchain run: > sudo apt-get update && sudo apt-get install gnat gprbuild - name: Build run: gprbuild -j0 -p alire-1.2.1/deps/ansi/.gitignore000066400000000000000000000000421402734713000164610ustar00rootroot00000000000000alire bin /config/ lib obj *.sw? alire-1.2.1/deps/ansi/LICENSE000066400000000000000000000020631402734713000155030ustar00rootroot00000000000000MIT License Copyright (c) 2020 Alejandro R Mosteo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. alire-1.2.1/deps/ansi/README.md000066400000000000000000000003461402734713000157570ustar00rootroot00000000000000# ansi-ada [![Alire indexed](https://img.shields.io/badge/alire-0.1.0-blue.svg)](https://alire.ada.dev) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) ANSI control sequences for the Ada language alire-1.2.1/deps/ansi/alire.lock000066400000000000000000000001501402734713000164370ustar00rootroot00000000000000# THIS IS A MACHINE-GENERATED FILE. DO NOT EDIT MANUALLY. [solution] [solution.context] solved = true alire-1.2.1/deps/ansi/alire.toml000066400000000000000000000003721402734713000164700ustar00rootroot00000000000000name = "ansiada" description = "ANSI escape sequences" version = "0.2-dev" licenses = "MIT" authors = ["Alejandro R. Mosteo"] maintainers = ["Alejandro R. Mosteo "] maintainers-logins = ["mosteo"] project-files = ["ansi.gpr"] alire-1.2.1/deps/ansi/ansi.gpr000066400000000000000000000022221402734713000161370ustar00rootroot00000000000000project ANSI is for Create_Missing_Dirs use "True"; type Build_Modes is ("On_Demand", "Static_Lib", "Shared_Lib"); Build_Mode : Build_Modes := External ("ANSIADA_BUILD_MODE", "On_Demand"); case Build_Mode is when "On_Demand" => for Main use ("ansi-demo.adb"); for Exec_Dir use "bin"; for Object_Dir use "obj"; when "Static_Lib" => for Library_Kind use "static-pic"; for Library_Name use "ansiada"; for Library_Dir use "lib"; for Object_Dir use "obj/static"; when "Shared_Lib" => for Library_Kind use "dynamic"; for Library_Name use "ansiada"; for Library_Dir use "lib"; for Object_Dir use "obj/shared"; end case; for Source_Dirs use ("src"); package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end ANSI; alire-1.2.1/deps/ansi/src/000077500000000000000000000000001402734713000152645ustar00rootroot00000000000000alire-1.2.1/deps/ansi/src/ansi-demo.adb000066400000000000000000000076231402734713000176200ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; procedure ANSI.Demo is function Pad (S : String; Len : Positive) return String is (S & (1 .. Len - S'Length => ' ')); procedure Title (Text : String) is begin New_Line; Put_Line (Style_Wrap (Text => "=== " & Text & "===", Style => Bright)); end Title; begin Put_Line (Reset_All); Title ("BASIC COLOR TEST"); -- Named color tests: best seen in a 96-column term for Fg in Colors'Range loop for Bg in Colors'Range loop if Fg /= Bg then Put (Color_Wrap (Text => Fg'Img & " on " & Bg'Img, Foreground => Foreground (Fg), Background => Background (Bg))); end if; end loop; end loop; New_Line; Title ("PALETTE COLOR TEST (subsample)"); declare Palette : constant array (Positive range <>) of Palette_RGB := (0, 1, 3, 5); begin for R of Palette loop for G of Palette loop for B of Palette loop for BR of Palette loop for BG of Palette loop for BB of Palette loop Put (Color_Wrap (Text => "X", Foreground => Palette_Fg (R, G, B), Background => Palette_Bg (BR, BG, BB))); end loop; end loop; end loop; end loop; end loop; end loop; New_Line; end; Title ("GREYSCALE COLOR TEST"); for Fg in Greyscale'Range loop for Bg in Greyscale'Range loop Put (Color_Wrap (Text => Fg'Img & " on" & Bg'Img, Foreground => Foreground (Fg), Background => Background (Bg))); end loop; end loop; Put_Line ("TRUE COLOR TEST (subsample)"); declare Palette : constant array (Positive range <>) of True_RGB := (0, 84, 171, 255); begin for R of Palette loop for G of Palette loop for B of Palette loop for BR of Palette loop for BG of Palette loop for BB of Palette loop Put (Color_Wrap (Text => "X", Foreground => Foreground (R, G, B), Background => Background (BR, BG, BB))); end loop; end loop; end loop; end loop; end loop; end loop; New_Line; end; Title ("NAMED COLOR + STYLE TEST"); for Color in Colors'Range loop for Style in Default .. Dim loop Put (Style_Wrap (Text => Color_Wrap (Text => Pad (Style'Img & " " & Color'Img, 22), Foreground => Foreground (Color)), Style => Style)); end loop; New_Line; end loop; Title ("STYLE TEST"); for Style in Styles'Range loop Put_Line (Style_Wrap ("This text is using the " & Style'Img & " style", Style)); end loop; Title ("CURSOR POSITIONING TEST"); Put ("Storing cursor position..."); Put_Line (Store); for I in 1 .. 4 loop Put_Line ((1 .. 20 => 'X')); end loop; Put (Scroll_Up (4)); Put_Line ("Scrolled up 4 lines"); Put (Restore); Put ("Restored cursor (should be aligned with 'Storing...' end column)"); Put (Up (Lines => 8)); Put (Horizontal (Column => 10)); delay 1.0; Put (Clear_To_End_Of_Line); Put (Down); delay 1.0; Put (Clear_To_Beginning_Of_Line); Put (Down (Lines => 7)); Put (Horizontal); -- Back to first position of last line Put (Store); Put (Position (4, 1)); Put_Line ("Absolute positioning test to top-left"); Put (Restore); New_Line; Put_Line ("Test ended, check the text at top-left"); end ANSI.Demo; alire-1.2.1/deps/ansi/src/ansi.ads000066400000000000000000000302201402734713000167040ustar00rootroot00000000000000package ANSI with Pure is Reset_All : constant String; -- Resets the device to its original state. This may include (if -- applicable): reset graphic rendition, clear tabulation stops, reset -- to default font, and more. type States is (Off, On); function Shorten (Sequence : String) return String is (Sequence); -- Some consecutive commands can be combined, resulting in a shorter -- string. Currently does nothing, but included for future optimization. ----------- -- COLOR -- ----------- type Colors is (Default, -- Implementation defined according to ANSI Black, Red, Green, Yellow, Blue, Magenta, Cyan, Grey, -- Note: these light variants might not work in older terminals. In -- general, the bold + [light] color combination will result in the -- same bright color Light_Black, Light_Red, Light_Green, Light_Yellow, Light_Blue, Light_Magenta, Light_Cyan, Light_Grey); Reset : constant String; -- Back to defaults. Applies to colors & styles. function Foreground (Color : Colors) return String; function Background (Color : Colors) return String; -- Basic palette, 8/16 colors subtype Palette_RGB is Natural range 0 .. 5; -- Used for the 256-palette colors. Actual colors in this index-mode -- palette can slightly vary from terminal to terminal. function Palette_Fg (R, G, B : Palette_RGB) return String; function Palette_Bg (R, G, B : Palette_RGB) return String; subtype Greyscale is Natural range 0 .. 23; -- Drawn from the same palette mode. 0 is black, 23 is white function Foreground (Level : Greyscale) return String; function Background (Level : Greyscale) return String; subtype True_RGB is Natural range 0 .. 255; -- Modern terminals support true 24-bit RGB color function Foreground (R, G, B : True_RGB) return String; function Background (R, G, B : True_RGB) return String; Default_Foreground : constant String; Default_Background : constant String; function Color_Wrap (Text : String; Foreground : String := ""; Background : String := "") return String; -- Wraps text between opening color and closing Defaults. See the combo -- color+styles below. ------------ -- STYLES -- ------------ type Styles is (Default, -- equivalent to Default_Foreground/Background Bright, -- aka Bold Dim, -- aka Faint Italic, Underline, Blink, Rapid_Blink, -- ansi.sys only Invert, -- swaps fg/bg, aka reverse video Conceal, -- aka hide Strike, -- aka crossed-out Fraktur, -- rarely supported, gothic style Double_Underline); function Style (Style : Styles; Active : States := On) return String; -- Apply/Remove a style function Style_Wrap (Text : String; Style : Styles) return String; -- Wraps Text in the given style between On/Off sequences function Wrap (Text : String; Style : Styles; Foreground : String := ""; Background : String := "") return String; ------------ -- CURSOR -- ------------ -- Cursor movement. No effect if at edge of screen. function Back (Cells : Positive := 1) return String; function Down (Lines : Positive := 1) return String; function Forward (Cells : Positive := 1) return String; function Up (Lines : Positive := 1) return String; function Next (Lines : Positive := 1) return String; function Previous (Lines : Positive := 1) return String; -- Move to the beginning of the next/prev lines. Not in ansi.sys function Horizontal (Column : Positive := 1) return String; -- Move to a certain absolute column. Not in ansy.sys function Position (Row, Column : Positive := 1) return String; -- 1, 1 is top-left Store : constant String; -- Store cursor position. Private SCO extension, may work in current vts Restore : constant String; -- Restore cursor position to the previously stored one Hide : constant String; Show : constant String; -- DECTCEM private extension, may work in current vts -------------- -- CLEARING -- -------------- Clear_Screen : constant String; Clear_Screen_And_Buffer : constant String; -- Clear also the backscroll buffer Clear_To_Beginning_Of_Screen : constant String; Clear_To_End_Of_Screen : constant String; -- From the cursor position Clear_Line : constant String; -- Does not change cursor position (neither the two following). Clear_To_Beginning_Of_Line : constant String; Clear_To_End_Of_Line : constant String; function Scroll_Up (Lines : Positive) return String; -- Adds lines at bottom function Scroll_Down (Lines : Positive) return String; -- Adds lines at top private ESC : constant Character := ASCII.ESC; CSI : constant String := ESC & '['; Reset_All : constant String := ESC & "c"; -- Helpers for the many int-to-str conversions function Tail (S : String) return String is (S (S'First + 1 .. S'Last)); function Img (I : Natural) return String is (Tail (I'Img)); ------------ -- COLORS -- ------------ Reset : constant String := CSI & "0m"; -- Back to defaults. Applies to colors & styles. function Foreground (Color : Colors) return String is (CSI & (case Color is when Default => "39", when Black => "30", when Red => "31", when Green => "32", when Yellow => "33", when Blue => "34", when Magenta => "35", when Cyan => "36", when Grey => "37", when Light_Black => "90", when Light_Red => "91", when Light_Green => "92", when Light_Yellow => "93", when Light_Blue => "94", when Light_Magenta => "95", when Light_Cyan => "96", when Light_Grey => "97") & "m"); function Background (Color : Colors) return String is (CSI & (case Color is when Default => "49", when Black => "40", when Red => "41", when Green => "42", when Yellow => "43", when Blue => "44", when Magenta => "45", when Cyan => "46", when Grey => "47", when Light_Black => "100", when Light_Red => "101", when Light_Green => "102", when Light_Yellow => "103", when Light_Blue => "104", when Light_Magenta => "105", when Light_Cyan => "106", when Light_Grey => "107") & "m"); function Bit8 (R, G, B : Palette_RGB) return String is (Img (16 + 36 * R + 6 * G + B)); Fg : constant String := "38"; Bg : constant String := "48"; function Palette_Fg (R, G, B : Palette_RGB) return String is (CSI & Fg & ";5;" & Bit8 (R, G, B) & "m"); function Palette_Bg (R, G, B : Palette_RGB) return String is (CSI & Bg & ";5;" & Bit8 (R, G, B) & "m"); function Foreground (Level : Greyscale) return String is (CSI & Fg & ";5;" & Img (232 + Level) & "m"); function Background (Level : Greyscale) return String is (CSI & Bg & ";5;" & Img (232 + Level) & "m"); function Foreground (R, G, B : True_RGB) return String is (CSI & Fg & ";2;" & Img (R) & ";" & Img (G) & ";" & Img (B) & "m"); function Background (R, G, B : True_RGB) return String is (CSI & Bg & ";2;" & Img (R) & ";" & Img (G) & ";" & Img (B) & "m"); Default_Foreground : constant String := CSI & "39m"; Default_Background : constant String := CSI & "49m"; function Color_Wrap (Text : String; Foreground : String := ""; Background : String := "") return String is ((if Foreground /= "" then Foreground else "") & (if Background /= "" then Background else "") & Text & (if Background /= "" then Default_Background else "") & (if Foreground /= "" then Default_Foreground else "")); ------------ -- STYLES -- ------------ function Style (Style : Styles; Active : States := On) return String is (CSI & (case Active is when On => (case Style is when Default => "39", when Bright => "1", when Dim => "2", when Italic => "3", when Underline => "4", when Blink => "5", when Rapid_Blink => "6", when Invert => "7", when Conceal => "8", when Strike => "9", when Fraktur => "20", when Double_Underline => "21" ), when Off => (case Style is when Default => "49", when Bright => "22", when Dim => "22", when Italic => "23", when Underline => "24", when Blink => "25", when Rapid_Blink => "25", when Invert => "27", when Conceal => "28", when Strike => "29", when Fraktur => "23", when Double_Underline => "24" )) & "m"); function Style_Wrap (Text : String; Style : Styles) return String is (ANSI.Style (Style, On) & Text & ANSI.Style (Style, Off)); function Wrap (Text : String; Style : Styles; Foreground : String := ""; Background : String := "") return String is (Style_Wrap (Style => Style, Text => Color_Wrap (Text => Text, Foreground => Foreground, Background => Background))); ------------ -- CURSOR -- ------------ function Cursor (N : Positive; Code : Character) return String is (CSI & Img (N) & Code) with Inline_Always; -- For common Cursor sequences function Back (Cells : Positive := 1) return String is (Cursor (Cells, 'D')); function Down (Lines : Positive := 1) return String is (Cursor (Lines, 'B')); function Forward (Cells : Positive := 1) return String is (Cursor (Cells, 'C')); function Up (Lines : Positive := 1) return String is (Cursor (Lines, 'A')); function Next (Lines : Positive := 1) return String is (Cursor (Lines, 'E')); function Previous (Lines : Positive := 1) return String is (Cursor (Lines, 'F')); function Horizontal (Column : Positive := 1) return String is (Cursor (Column, 'G')); function Position (Row, Column : Positive := 1) return String is (CSI & Img (Row) & ";" & Img (Column) & "H"); Store : constant String := CSI & "s"; Restore : constant String := CSI & "u"; Hide : constant String := CSI & "?25l"; Show : constant String := CSI & "?25h"; -------------- -- CLEARING -- -------------- Clear_Screen : constant String := CSI & "2J"; Clear_Screen_And_Buffer : constant String := CSI & "3J"; Clear_To_Beginning_Of_Screen : constant String := CSI & "2J"; Clear_To_End_Of_Screen : constant String := CSI & "0J"; Clear_Line : constant String := CSI & "2K"; Clear_To_Beginning_Of_Line : constant String := CSI & "1K"; Clear_To_End_Of_Line : constant String := CSI & "0K"; function Scroll_Up (Lines : Positive) return String is (CSI & Img (Lines) & "S"); function Scroll_Down (Lines : Positive) return String is (CSI & Img (Lines) & "T"); end ANSI; pax_global_header00006660000000000000000000000064142457037570014530gustar00rootroot0000000000000052 comment=185519d65b089c3238e24cfe87f1d22db1f3e0d9 alire-1.2.1/deps/clic/000077500000000000000000000000001424570375700144725ustar00rootroot00000000000000alire-1.2.1/deps/clic/.github/000077500000000000000000000000001424570375700160325ustar00rootroot00000000000000alire-1.2.1/deps/clic/.github/workflows/000077500000000000000000000000001424570375700200675ustar00rootroot00000000000000alire-1.2.1/deps/clic/.github/workflows/main.yml000066400000000000000000000010201424570375700215270ustar00rootroot00000000000000 on: push: pull_request: workflow_dispatch: jobs: build: strategy: matrix: os: [macos-latest, windows-latest, ubuntu-latest] gnat_version: [^10, ^11] gprbuild_version: [^21] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - uses: alire-project/setup-alire@v1 with: toolchain: gprbuild${{ matrix.gprbuild_version }} gnat_native${{ matrix.gnat_version }} --disable-assistant - run: alr build - run: cd example && alr build alire-1.2.1/deps/clic/.gitignore000066400000000000000000000000441424570375700164600ustar00rootroot00000000000000obj/ lib/ alire/ config/ alire.lock alire-1.2.1/deps/clic/LICENSE000066400000000000000000000020461424570375700155010ustar00rootroot00000000000000MIT License Copyright (c) 2021 Alire Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. alire-1.2.1/deps/clic/README.md000066400000000000000000000000511424570375700157450ustar00rootroot00000000000000# clic Command Line Interface Components alire-1.2.1/deps/clic/alire.toml000066400000000000000000000015241424570375700164650ustar00rootroot00000000000000name = "clic" description = "Command Line Interface Components" version = "0.2.1-dev" authors = ["Alejandro R. Mosteo", "Fabien Chouteau"] maintainers = ["alejandro@mosteo.com", "Fabien Chouteau "] maintainers-logins = ["mosteo", "Fabien-Chouteau"] licenses = "MIT AND GPL-3.0-or-later WITH GCC-exception-3.1" tags = ["cli", "command-line", "user-input", "tty"] website = "https://github.com/alire-project/clic" long-description = """ Command Line Interface Components: - "git like" subcommand handling - TTY color and formatting - User input queries - User configuration """ [configuration] disabled = true # CLIC is an Alire dependency using git submodule, so we can't # use the crate configuration here. [[depends-on]] aaa = "~0.2.4" simple_logging = "^1.2.0" ansiada = "~0.1.0" ada_toml = "~0.2.0" alire-1.2.1/deps/clic/clic.gpr000066400000000000000000000056331424570375700161250ustar00rootroot00000000000000with "aaa.gpr"; with "ansi.gpr"; with "simple_logging.gpr"; with "ada_toml.gpr"; project Clic is for Library_Name use "Clic"; for Library_Version use "0.0.0"; for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Library_Dir use "lib"; type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := external ("CLIC_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); for Library_Kind use Library_Type; type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("CLIC_COMPILE_CHECKS", "disabled"); Runtime_Checks : Enabled_Kind := External ("CLIC_RUNTIME_CHECKS", "disabled"); Style_Checks : Enabled_Kind := External ("CLIC_STYLE_CHECKS", "disabled"); Contracts_Checks : Enabled_Kind := External ("CLIC_CONTRACTS", "disabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("CLIC_BUILD_MODE", "optimize"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Supress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-d", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnatyO", -- Overriding subprograms explicitly marked as such "-gnaty-s"); -- Relax fwd decl when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => null; end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnatw.X", -- Disable warnings for No_Exception_Propagation "-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Clic; alire-1.2.1/deps/clic/example/000077500000000000000000000000001424570375700161255ustar00rootroot00000000000000alire-1.2.1/deps/clic/example/.gitignore000066400000000000000000000000351424570375700201130ustar00rootroot00000000000000obj/ lib/ alire/ config/ bin alire-1.2.1/deps/clic/example/alire.toml000066400000000000000000000005661424570375700201250ustar00rootroot00000000000000name = "clic_example" description = "Shiny new project" version = "0.0.0" authors = ["Fabien Chouteau"] maintainers = ["Fabien Chouteau "] maintainers-logins = ["Fabien-Chouteau"] executables = ["clic_example"] [[depends-on]] # Added by alr clic = "~0.1.0" # Added by alr [[pins]] # Added by alr clic = { path='../../clic' } # Added by alr alire-1.2.1/deps/clic/example/clic_example.gpr000066400000000000000000000051761424570375700212750ustar00rootroot00000000000000with "config/clic_example_config.gpr"; project Clic_Example is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Exec_Dir use "bin"; for Main use ("clic_example.adb"); type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("CLIC_EXAMPLE_COMPILE_CHECKS", "disabled"); Runtime_Checks : Enabled_Kind := External ("CLIC_EXAMPLE_RUNTIME_CHECKS", "disabled"); Style_Checks : Enabled_Kind := External ("CLIC_EXAMPLE_STYLE_CHECKS", "disabled"); Contracts_Checks : Enabled_Kind := External ("CLIC_EXAMPLE_CONTRACTS", "disabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("CLIC_EXAMPLE_BUILD_MODE", "optimize"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Supress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-d", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnatyO"); -- Overriding subprograms explicitly marked as such when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => null; end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnatw.X", -- Disable warnings for No_Exception_Propagation "-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Clic_Example; alire-1.2.1/deps/clic/example/src/000077500000000000000000000000001424570375700167145ustar00rootroot00000000000000alire-1.2.1/deps/clic/example/src/clic_ex-commands-config.adb000066400000000000000000000131461424570375700240410ustar00rootroot00000000000000with GNAT.OS_Lib; with Simple_Logging; with CLIC.Config.Info; with CLIC.Config.Edit; with CLIC.Config.Load; package body CLIC_Ex.Commands.Config is package Trace renames Simple_Logging; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector) is Enabled : Natural := 0; Config_Path : constant String := (if Cmd.Global then "global_config.toml" else "local_config.toml"); begin -- Check no multi-action Enabled := Enabled + (if Cmd.List then 1 else 0); Enabled := Enabled + (if Cmd.Get then 1 else 0); Enabled := Enabled + (if Cmd.Set then 1 else 0); Enabled := Enabled + (if Cmd.Unset then 1 else 0); Enabled := Enabled + (if Cmd.Builtins_Doc then 1 else 0); if Enabled > 1 then Trace.Error ("Specify at most one subcommand"); GNAT.OS_Lib.OS_Exit (1); end if; if Enabled = 0 then -- The default command is --list Cmd.List := True; end if; if Cmd.Show_Origin and then not Cmd.List then Trace.Error ("--show-origin only valid with --list"); GNAT.OS_Lib.OS_Exit (1); end if; if Cmd.List then case Args.Count is when 0 => Trace.Always (CLIC.Config.Info.List (Cmd.Config, Filter => "*", Show_Origin => Cmd.Show_Origin).Flatten (ASCII.LF)); when 1 => Trace.Always (CLIC.Config.Info.List (Cmd.Config, Filter => Args.First_Element, Show_Origin => Cmd.Show_Origin).Flatten (ASCII.LF)); when others => Trace.Error ("List expects at most one argument"); GNAT.OS_Lib.OS_Exit (1); end case; elsif Cmd.Get then if Args.Count /= 1 then Trace.Error ("Unset expects one argument"); GNAT.OS_Lib.OS_Exit (1); end if; if not CLIC.Config.Is_Valid_Config_Key (Args.First_Element) then Trace.Error ("Invalid configration key '" & Args.First_Element & "'"); GNAT.OS_Lib.OS_Exit (1); end if; if Cmd.Config.Defined (Args.First_Element) then Trace.Always (Cmd.Config.Get_As_String (Args.First_Element)); else Trace.Error ("Configuration key '" & Args.First_Element & "' is not defined"); GNAT.OS_Lib.OS_Exit (1); end if; elsif Cmd.Set then if Args.Count /= 2 then Trace.Error ("Set expects two arguments"); GNAT.OS_Lib.OS_Exit (1); end if; declare Key : constant String := Args.Element (1); Val : constant String := Args.Element (2); begin if not CLIC.Config.Is_Valid_Config_Key (Key) then Trace.Error ("Invalid configration key '" & Key & "'"); GNAT.OS_Lib.OS_Exit (1); end if; if not CLIC.Config.Edit.Set (Config_Path, Key, Val) then GNAT.OS_Lib.OS_Exit (1); end if; end; elsif Cmd.Unset then if Args.Count /= 1 then Trace.Error ("Unset expects one argument"); GNAT.OS_Lib.OS_Exit (1); end if; declare Key : constant String := Args.Element (1); begin if not CLIC.Config.Is_Valid_Config_Key (Key) then Trace.Error ("Invalid configration key '" & Key & "'"); GNAT.OS_Lib.OS_Exit (1); end if; if not CLIC.Config.Edit.Unset (Config_Path, Key) then GNAT.OS_Lib.OS_Exit (1); end if; end; end if; end Execute; -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config => Config, Output => Cmd.List'Access, Long_Switch => "--list", Help => "List configuration options"); Define_Switch (Config => Config, Output => Cmd.Show_Origin'Access, Long_Switch => "--show-origin", Help => "Show origin of configuration values in --list"); Define_Switch (Config => Config, Output => Cmd.Get'Access, Long_Switch => "--get", Help => "Print value of a configuration option"); Define_Switch (Config => Config, Output => Cmd.Set'Access, Long_Switch => "--set", Help => "Set a configuration option"); Define_Switch (Config => Config, Output => Cmd.Unset'Access, Long_Switch => "--unset", Help => "Unset a configuration option"); Define_Switch (Config => Config, Output => Cmd.Global'Access, Long_Switch => "--global", Help => "Set and Unset global configuration instead" & " of the local one"); Define_Switch (Config => Config, Output => Cmd.Builtins_Doc'Access, Long_Switch => "--builtins-doc", Help => "Print Markdown list of built-in configuration options"); end Setup_Switches; end CLIC_Ex.Commands.Config; alire-1.2.1/deps/clic/example/src/clic_ex-commands-config.ads000066400000000000000000000053371424570375700240650ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; with CLIC.Config; package CLIC_Ex.Commands.Config is type Instance is limited new CLIC.Subcommand.Command with private; overriding function Name (Cmd : Instance) return CLIC.Subcommand.Identifier is ("config"); overriding function Switch_Parsing (This : Instance) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Parse_All); overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector); overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Instance) return String is ("List, Get, Set or Unset configuration options"); overriding function Usage_Custom_Parameters (Cmd : Instance) return String is ("[--list] [--show-origin] [key_regex] |" & " --get |" & " --set |" & " --unset "); overriding function Long_Description (Cmd : Instance) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Provides a command line interface to the Alire configuration" & " option files.") .New_Line .Append ("Option names (keys) can use lowercase and uppercase" & " alphanumeric characters") .Append ("from the Latin alphabet. Underscores and dashes can also be" & " used except as") .Append ("first or last character. Dot '.' is used to specify" & " sub-categories, e.g.") .Append ("'user.name' or 'user.email'.") .New_Line .Append ("Option values can be integers, float, Boolean (true or" & " false) or strings. The") .Append ("type detection is automatic, e.g. 10 is integer, 10.1 is" & " float, true is") .Append ("Boolean. You can force a value to be set a string by using" & " double-quotes, e.g.") .Append ("""10.1"" or ""true"". Extra type checking is used for" & " built-in options (see below).") .New_Line .Append ("Built-in configuration options:")); private type Instance is limited new CLIC.Subcommand.Command with record Config : CLIC.Config.Instance; Show_Origin : aliased Boolean := False; List : aliased Boolean := False; Get : aliased Boolean := False; Set : aliased Boolean := False; Unset : aliased Boolean := False; Global : aliased Boolean := False; Builtins_Doc : aliased Boolean := False; end record; end CLIC_Ex.Commands.Config; alire-1.2.1/deps/clic/example/src/clic_ex-commands-double_dash.adb000066400000000000000000000015671424570375700250510ustar00rootroot00000000000000package body CLIC_Ex.Commands.Double_Dash is Upper_Case : aliased Boolean := False; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector) is begin if Upper_Case then Ada.Text_IO.Put_Line (AAA.Strings.To_Upper_Case (Args.Flatten)); else Ada.Text_IO.Put_Line (Args.Flatten); end if; end Execute; -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration) is begin CLIC.Subcommand.Define_Switch (Config, Output => Upper_Case'Access, Long_Switch => "--upper"); end Setup_Switches; end CLIC_Ex.Commands.Double_Dash; alire-1.2.1/deps/clic/example/src/clic_ex-commands-double_dash.ads000066400000000000000000000022171424570375700250630ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; package CLIC_Ex.Commands.Double_Dash is type Instance is new CLIC.Subcommand.Command with private; overriding function Name (Cmd : Instance) return CLIC.Subcommand.Identifier is ("double_dash"); overriding function Switch_Parsing (This : Instance) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Before_Double_Dash); overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Instance) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector); overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Instance) return String is ("Switch parsing before -- (double dash)"); overriding function Usage_Custom_Parameters (Cmd : Instance) return String is ("[--upper] [--] [args]"); private type Instance is new CLIC.Subcommand.Command with null record; end CLIC_Ex.Commands.Double_Dash; alire-1.2.1/deps/clic/example/src/clic_ex-commands-subsub.adb000066400000000000000000000023761424570375700241020ustar00rootroot00000000000000with CLIC_Ex.Commands.TTY; with CLIC_Ex.Commands.User_Input; package body CLIC_Ex.Commands.Subsub is ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector) is procedure Set_Global_Switches (Config : in out CLIC.Subcommand.Switches_Configuration) is null; package Sub is new CLIC.Subcommand.Instance (Main_Command_Name => "subsub", Version => "0.0.0", Set_Global_Switches => Set_Global_Switches, Put => Ada.Text_IO.Put, Put_Line => Ada.Text_IO.Put_Line, Put_Error => Ada.Text_IO.Put_Line, Error_Exit => GNAT.OS_Lib.OS_Exit, TTY_Chapter => CLIC.TTY.Info, TTY_Description => CLIC.TTY.Description, TTY_Version => CLIC.TTY.Version, TTY_Underline => CLIC.TTY.Underline, TTY_Emph => CLIC.TTY.Emph); begin Sub.Register (new Sub.Builtin_Help); Sub.Register (new CLIC_Ex.Commands.TTY.Instance); Sub.Register (new CLIC_Ex.Commands.User_Input.Instance); Sub.Execute (Args); end Execute; end CLIC_Ex.Commands.Subsub; alire-1.2.1/deps/clic/example/src/clic_ex-commands-subsub.ads000066400000000000000000000021421424570375700241120ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; package CLIC_Ex.Commands.Subsub is type Instance is new CLIC.Subcommand.Command with private; overriding function Name (Cmd : Instance) return CLIC.Subcommand.Identifier is ("subsub"); overriding function Switch_Parsing (This : Instance) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Parse_All); overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Instance) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector); overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration) is null; overriding function Short_Description (Cmd : Instance) return String is ("Subcommands in a subcommand"); overriding function Usage_Custom_Parameters (Cmd : Instance) return String is (""); private type Instance is new CLIC.Subcommand.Command with null record; end CLIC_Ex.Commands.Subsub; alire-1.2.1/deps/clic/example/src/clic_ex-commands-switches_and_args.adb000066400000000000000000000005061424570375700262570ustar00rootroot00000000000000with Ada.Text_IO; package body CLIC_Ex.Commands.Switches_And_Args is ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector) is begin Ada.Text_IO.Put_Line (Args.Flatten); end Execute; end CLIC_Ex.Commands.Switches_And_Args; alire-1.2.1/deps/clic/example/src/clic_ex-commands-switches_and_args.ads000066400000000000000000000022461424570375700263030ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; package CLIC_Ex.Commands.Switches_And_Args is type Instance is new CLIC.Subcommand.Command with private; overriding function Name (Cmd : Instance) return CLIC.Subcommand.Identifier is ("switches_and_args"); overriding function Switch_Parsing (This : Instance) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.All_As_Args); overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Instance) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector); overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration) is null; overriding function Short_Description (Cmd : Instance) return String is ("Print all the sub-command switches and args"); overriding function Usage_Custom_Parameters (Cmd : Instance) return String is ("[switches] [args]"); private type Instance is new CLIC.Subcommand.Command with null record; end CLIC_Ex.Commands.Switches_And_Args; alire-1.2.1/deps/clic/example/src/clic_ex-commands-topics-example.ads000066400000000000000000000011401424570375700255360ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; with CLIC.TTY; package CLIC_Ex.Commands.Topics.Example is type Instance is new CLIC.Subcommand.Help_Topic with null record; overriding function Name (This : Instance) return CLIC.Subcommand.Identifier is ("topic_example"); overriding function Title (This : Instance) return String is ("Just an example of CLIC help topic"); overriding function Content (This : Instance) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Not " & CLIC.TTY.Dim ("much") & " to see here...")); end CLIC_Ex.Commands.Topics.Example; alire-1.2.1/deps/clic/example/src/clic_ex-commands-topics.ads000066400000000000000000000001011424570375700241010ustar00rootroot00000000000000package CLIC_Ex.Commands.Topics is end CLIC_Ex.Commands.Topics; alire-1.2.1/deps/clic/example/src/clic_ex-commands-tty.adb000066400000000000000000000035421424570375700234130ustar00rootroot00000000000000with CLIC.TTY; use CLIC.TTY; with Ada.Text_IO; use Ada.Text_IO; package body CLIC_Ex.Commands.TTY is package TTY renames CLIC.TTY; -------------------- -- Setup_Switches -- -------------------- overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration) is begin CLIC.Subcommand.Define_Switch (Config, Cmd.Blink'Access, Long_Switch => "--blink"); end Setup_Switches; ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector) is begin if not Args.Is_Empty then Put_Line (Cmd.Name & " takes no arguments"); GNAT.OS_Lib.OS_Exit (1); end if; Put_Line (TTY.Bold ("CLIC.TTY.Bold ()")); Put_Line (TTY.Dim ("CLIC.TTY.Dim ()")); Put_Line (TTY.Italic ("CLIC.TTY.Italic ()")); Put_Line (TTY.Underline ("CLIC.TTY.Underline ()")); Put_Line (TTY.Emph ("CLIC.TTY.Emph ()")); Put_Line (TTY.Description ("CLIC.TTY.Description ()")); Put_Line (TTY.Error ("CLIC.TTY.Error ()")); Put_Line (TTY.Warn ("CLIC.TTY.Warn ()")); Put_Line (TTY.Info ("CLIC.TTY.Info ()")); Put_Line (TTY.Success ("CLIC.TTY.Success ()")); Put_Line (TTY.Terminal ("CLIC.TTY.Terminal ()")); Put_Line (TTY.Format (Text => "CLIC.TTY.Format (""," & " Fore => ANSI.Light_Blue, Style => ANSI.Strike)", Fore => ANSI.Light_Blue, Style => ANSI.Strike)); if Cmd.Blink then Put_Line (TTY.Format (Text => "Blinky blink!", Fore => ANSI.Red, Style => ANSI.Blink)); end if; end Execute; end CLIC_Ex.Commands.TTY; alire-1.2.1/deps/clic/example/src/clic_ex-commands-tty.ads000066400000000000000000000024241424570375700234320ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; package CLIC_Ex.Commands.TTY is type Instance is new CLIC.Subcommand.Command with private; overriding function Name (Cmd : Instance) return CLIC.Subcommand.Identifier is ("tty"); overriding function Switch_Parsing (This : Instance) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Parse_All); overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Instance) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Long description of the TTY command.") .Append ("Multiple lines:") .Append (" - 1") .Append (" - 2") .Append (" - 3") ); overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration); overriding function Short_Description (Cmd : Instance) return String is ("Show tty colors"); overriding function Usage_Custom_Parameters (Cmd : Instance) return String is (""); private type Instance is new CLIC.Subcommand.Command with record Blink : aliased Boolean; end record; end CLIC_Ex.Commands.TTY; alire-1.2.1/deps/clic/example/src/clic_ex-commands-user_input.adb000066400000000000000000000036261424570375700247730ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; with AAA.Strings; with CLIC.User_Input; use CLIC.User_Input; with GNAT.OS_Lib; package body CLIC_Ex.Commands.User_Input is function Valid_Number (Str : String) return Boolean is (for all C of Str => C in '0' .. '9'); ------------- -- Execute -- ------------- overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector) is begin if not Args.Is_Empty then Put_Line (Cmd.Name & " takes no arguments"); GNAT.OS_Lib.OS_Exit (1); end if; declare Answer : Answer_Kind; begin Answer := Query (Question => "Do you like this tool?", Valid => (others => True), Default => Yes); if Answer = No then Put_Line ("Fine then."); GNAT.OS_Lib.OS_Exit (42); end if; end; declare Languages : constant AAA.Strings.Vector := AAA.Strings.Empty_Vector .Append ("Ada") .Append ("C") .Append ("C++") .Append ("Rust") .Append ("OCAML") .Append ("Fortran") .Append ("Go"); Answer : Positive; begin Answer := Query_Multi (Question => "What is you favorite programming language?", Choices => Languages); if Answer /= 1 then Put_Line ("Wrong answer."); GNAT.OS_Lib.OS_Exit (42); end if; end; Continue_Or_Abort; declare Answer : constant String := Query_String (Question => "Enter a number please", Default => "42", Validation => Valid_Number'Access); begin Put_Line ("Thanks for your answer: '" & Answer & "'"); end; end Execute; end CLIC_Ex.Commands.User_Input; alire-1.2.1/deps/clic/example/src/clic_ex-commands-user_input.ads000066400000000000000000000024251424570375700250100ustar00rootroot00000000000000with AAA.Strings; with CLIC.Subcommand; package CLIC_Ex.Commands.User_Input is type Instance is new CLIC.Subcommand.Command with private; overriding function Name (Cmd : Instance) return CLIC.Subcommand.Identifier is ("user_input"); overriding function Switch_Parsing (This : Instance) return CLIC.Subcommand.Switch_Parsing_Kind is (CLIC.Subcommand.Parse_All); overriding procedure Execute (Cmd : in out Instance; Args : AAA.Strings.Vector); overriding function Long_Description (Cmd : Instance) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Long description of the user_input command.") .Append ("Multiple lines:") .Append (" - 1") .Append (" - 2") .Append (" - 3") ); overriding procedure Setup_Switches (Cmd : in out Instance; Config : in out CLIC.Subcommand.Switches_Configuration) is null; overriding function Short_Description (Cmd : Instance) return String is ("Asks questions..."); overriding function Usage_Custom_Parameters (Cmd : Instance) return String is (""); private type Instance is new CLIC.Subcommand.Command with null record; end CLIC_Ex.Commands.User_Input; alire-1.2.1/deps/clic/example/src/clic_ex-commands.adb000066400000000000000000000061501424570375700225730ustar00rootroot00000000000000with AAA.Strings; with CLIC.TTY; with CLIC.User_Input; with CLIC.Config.Load; with CLIC_Ex.Commands.TTY; with CLIC_Ex.Commands.User_Input; with CLIC_Ex.Commands.Switches_And_Args; with CLIC_Ex.Commands.Double_Dash; with CLIC_Ex.Commands.Topics.Example; with CLIC_Ex.Commands.Config; with CLIC_Ex.Commands.Subsub; package body CLIC_Ex.Commands is Help_Switch : aliased Boolean := False; No_Color : aliased Boolean := False; -- Force-disable color output No_TTY : aliased Boolean := False; -- Used to disable control characters in output ------------------------- -- Set_Global_Switches -- ------------------------- procedure Set_Global_Switches (Config : in out CLIC.Subcommand.Switches_Configuration) is use CLIC.Subcommand; begin Define_Switch (Config, Help_Switch'Access, "-h", "--help", "Display general or command-specific help"); Define_Switch (Config, CLIC.User_Input.Not_Interactive'Access, "-n", "--non-interactive", "Assume default answers for all user prompts"); Define_Switch (Config, No_Color'Access, Long_Switch => "--no-color", Help => "Disables colors in output"); Define_Switch (Config, No_TTY'Access, Long_Switch => "--no-tty", Help => "Disables control characters in output"); end Set_Global_Switches; ------------- -- Execute -- ------------- procedure Execute is begin Sub_Cmd.Parse_Global_Switches; if No_TTY then CLIC.TTY.Force_Disable_TTY; end if; if not No_Color and then not No_TTY then CLIC.TTY.Enable_Color (Force => False); -- This may still not enable color if TTY is detected to be incapable end if; CLIC.Config.Load.From_TOML (Config_DB, "global", "global_config.toml"); CLIC.Config.Load.From_TOML (Config_DB, "local", "local_config.toml"); Sub_Cmd.Load_Aliases (Config_DB); Sub_Cmd.Execute; end Execute; begin Sub_Cmd.Register (new Sub_Cmd.Builtin_Help); Sub_Cmd.Register (new CLIC_Ex.Commands.Config.Instance); Sub_Cmd.Register (new CLIC_Ex.Commands.TTY.Instance); Sub_Cmd.Register (new CLIC_Ex.Commands.User_Input.Instance); Sub_Cmd.Register (new CLIC_Ex.Commands.Switches_And_Args.Instance); Sub_Cmd.Register (new CLIC_Ex.Commands.Double_Dash.Instance); Sub_Cmd.Register (new CLIC_Ex.Commands.Subsub.Instance); Sub_Cmd.Register (new CLIC_Ex.Commands.Topics.Example.Instance); Sub_Cmd.Set_Alias ("blink", AAA.Strings.Empty_Vector .Append ("tty") .Append ("--blink")); Sub_Cmd.Set_Alias ("error_alias", AAA.Strings.Empty_Vector .Append ("tty") .Append ("--test")); Sub_Cmd.Set_Alias ("alias_to_switch", AAA.Strings.Empty_Vector .Append ("--plop")); end CLIC_Ex.Commands; alire-1.2.1/deps/clic/example/src/clic_ex-commands.ads000066400000000000000000000017221424570375700226140ustar00rootroot00000000000000 private with Ada.Text_IO; private with GNAT.OS_Lib; private with CLIC.Subcommand.Instance; private with CLIC.TTY; private with CLIC.Config; package CLIC_Ex.Commands is procedure Execute; private Config_DB : CLIC.Config.Instance; procedure Set_Global_Switches (Config : in out CLIC.Subcommand.Switches_Configuration); package Sub_Cmd is new CLIC.Subcommand.Instance (Main_Command_Name => "clic_example", Version => "0.0.0", Set_Global_Switches => Set_Global_Switches, Put => Ada.Text_IO.Put, Put_Line => Ada.Text_IO.Put_Line, Put_Error => Ada.Text_IO.Put_Line, Error_Exit => GNAT.OS_Lib.OS_Exit, TTY_Chapter => CLIC.TTY.Info, TTY_Description => CLIC.TTY.Description, TTY_Version => CLIC.TTY.Version, TTY_Underline => CLIC.TTY.Underline, TTY_Emph => CLIC.TTY.Emph); end CLIC_Ex.Commands; alire-1.2.1/deps/clic/example/src/clic_ex.ads000066400000000000000000000000401424570375700210050ustar00rootroot00000000000000package CLIC_Ex is end CLIC_Ex; alire-1.2.1/deps/clic/example/src/clic_example.adb000066400000000000000000000001471424570375700220130ustar00rootroot00000000000000with CLIC_Ex.Commands; procedure Clic_Example is begin CLIC_Ex.Commands.Execute; end Clic_Example; alire-1.2.1/deps/clic/src/000077500000000000000000000000001424570375700152615ustar00rootroot00000000000000alire-1.2.1/deps/clic/src/clic-command_line.adb000066400000000000000000003443451424570375700213030ustar00rootroot00000000000000-- This package is imported from GNAT FSF 11.2 source to have a common -- implementation of Command_Line parsing across any version of GNAT. ------------------------------------------------------------------------------ -- -- -- GNAT COMPILER COMPONENTS -- -- -- -- G N A T . C O M M A N D _ L I N E -- -- -- -- B o d y -- -- -- -- Copyright (C) 1999-2020, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 3, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Strings.Unbounded; with Ada.Text_IO; use Ada.Text_IO; with Ada.Unchecked_Deallocation; with GNAT.Directory_Operations; use GNAT.Directory_Operations; with GNAT.OS_Lib; use GNAT.OS_Lib; package body CLIC.Command_Line is -- General note: this entire body could use much more commenting. There -- are large sections of uncommented code throughout, and many formal -- parameters of local subprograms are not documented at all ??? package CL renames Ada.Command_Line; type Switch_Parameter_Type is (Parameter_None, Parameter_With_Optional_Space, -- ':' in getopt Parameter_With_Space_Or_Equal, -- '=' in getopt Parameter_No_Space, -- '!' in getopt Parameter_Optional); -- '?' in getopt procedure Set_Parameter (Variable : out Parameter_Type; Arg_Num : Positive; First : Positive; Last : Natural; Extra : Character := ASCII.NUL); pragma Inline (Set_Parameter); -- Set the parameter that will be returned by Parameter below -- -- Extra is a character that needs to be added when reporting Full_Switch. -- (it will in general be the switch character, for instance '-'). -- Otherwise, Full_Switch will report 'f' instead of '-f'. In particular, -- it needs to be set when reporting an invalid switch or handling '*'. -- -- Parameters need to be defined ??? function Goto_Next_Argument_In_Section (Parser : Opt_Parser) return Boolean; -- Go to the next argument on the command line. If we are at the end of -- the current section, we want to make sure there is no other identical -- section on the command line (there might be multiple instances of -- -largs). Returns True iff there is another argument. function Get_File_Names_Case_Sensitive return Integer; pragma Import (C, Get_File_Names_Case_Sensitive, "__gnat_get_file_names_case_sensitive"); File_Names_Case_Sensitive : constant Boolean := Get_File_Names_Case_Sensitive /= 0; procedure Canonical_Case_File_Name (S : in out String); -- Given a file name, converts it to canonical case form. For systems where -- file names are case sensitive, this procedure has no effect. If file -- names are not case sensitive (i.e. for example if you have the file -- "xyz.adb", you can refer to it as XYZ.adb or XyZ.AdB), then this call -- converts the given string to canonical all lower case form, so that two -- file names compare equal if they refer to the same file. procedure Internal_Initialize_Option_Scan (Parser : Opt_Parser; Switch_Char : Character; Stop_At_First_Non_Switch : Boolean; Section_Delimiters : String); -- Initialize Parser, which must have been allocated already function Argument (Parser : Opt_Parser; Index : Integer) return String; -- Return the index-th command line argument procedure Find_Longest_Matching_Switch (Switches : String; Arg : String; Index_In_Switches : out Integer; Switch_Length : out Integer; Param : out Switch_Parameter_Type); -- Return the Longest switch from Switches that at least partially matches -- Arg. Index_In_Switches is set to 0 if none matches. What are other -- parameters??? in particular Param is not always set??? procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Argument_List, Argument_List_Access); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Command_Line_Configuration_Record, Command_Line_Configuration); procedure Remove (Line : in out Argument_List_Access; Index : Integer); -- Remove a specific element from Line procedure Add (Line : in out Argument_List_Access; Str : String_Access; Before : Boolean := False); -- Add a new element to Line. If Before is True, the item is inserted at -- the beginning, else it is appended. procedure Add (Config : in out Command_Line_Configuration; Switch : Switch_Definition); procedure Add (Def : in out Alias_Definitions_List; Alias : Alias_Definition); -- Add a new element to Def procedure Initialize_Switch_Def (Def : out Switch_Definition; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG"); -- Initialize [Def] with the contents of the other parameters. -- This also checks consistency of the switch parameters, and will raise -- Invalid_Switch if they do not match. procedure Decompose_Switch (Switch : String; Parameter_Type : out Switch_Parameter_Type; Switch_Last : out Integer); -- Given a switch definition ("name:" for instance), extracts the type of -- parameter that is expected, and the name of the switch function Can_Have_Parameter (S : String) return Boolean; -- True if S can have a parameter function Require_Parameter (S : String) return Boolean; -- True if S requires a parameter function Actual_Switch (S : String) return String; -- Remove any possible trailing '!', ':', '?' and '=' generic with procedure Callback (Simple_Switch : String; Separator : String; Parameter : String; Index : Integer); -- Index in Config.Switches, or -1 procedure For_Each_Simple_Switch (Config : Command_Line_Configuration; Section : String; Switch : String; Parameter : String := ""; Unalias : Boolean := True); -- Breaks Switch into as simple switches as possible (expanding aliases and -- ungrouping common prefixes when possible), and call Callback for each of -- these. procedure Sort_Sections (Line : not null GNAT.OS_Lib.Argument_List_Access; Sections : GNAT.OS_Lib.Argument_List_Access; Params : GNAT.OS_Lib.Argument_List_Access); -- Reorder the command line switches so that the switches belonging to a -- section are grouped together. procedure Group_Switches (Cmd : Command_Line; Result : Argument_List_Access; Sections : Argument_List_Access; Params : Argument_List_Access); -- Group switches with common prefixes whenever possible. Once they have -- been grouped, we also check items for possible aliasing. procedure Alias_Switches (Cmd : Command_Line; Result : Argument_List_Access; Params : Argument_List_Access); -- When possible, replace one or more switches by an alias, i.e. a shorter -- version. function Looking_At (Type_Str : String; Index : Natural; Substring : String) return Boolean; -- Return True if the characters starting at Index in Type_Str are -- equivalent to Substring. generic with function Callback (S : String; Index : Integer) return Boolean; procedure Foreach_Switch (Config : Command_Line_Configuration; Section : String); -- Iterate over all switches defined in Config, for a specific section. -- Index is set to the index in Config.Switches. Stop iterating when -- Callback returns False. -------------- -- Argument -- -------------- function Argument (Parser : Opt_Parser; Index : Integer) return String is begin if Parser.Arguments /= null then return Parser.Arguments (Index + Parser.Arguments'First - 1).all; else return CL.Argument (Index); end if; end Argument; ------------------------------ -- Canonical_Case_File_Name -- ------------------------------ procedure Canonical_Case_File_Name (S : in out String) is begin if not File_Names_Case_Sensitive then for J in S'Range loop if S (J) in 'A' .. 'Z' then S (J) := Character'Val (Character'Pos (S (J)) + (Character'Pos ('a') - Character'Pos ('A'))); end if; end loop; end if; end Canonical_Case_File_Name; --------------- -- Expansion -- --------------- function Expansion (Iterator : Expansion_Iterator) return String is type Pointer is access all Expansion_Iterator; It : constant Pointer := Iterator'Unrestricted_Access; S : String (1 .. 1024); Last : Natural; Current : Depth := It.Current_Depth; NL : Positive; begin -- It is assumed that a directory is opened at the current level. -- Otherwise GNAT.Directory_Operations.Directory_Error will be raised -- at the first call to Read. loop Read (It.Levels (Current).Dir, S, Last); -- If we have exhausted the directory, close it and go back one level if Last = 0 then Close (It.Levels (Current).Dir); -- If we are at level 1, we are finished; return an empty string if Current = 1 then return String'(1 .. 0 => ' '); -- Otherwise continue with the directory at the previous level else Current := Current - 1; It.Current_Depth := Current; end if; -- If this is a directory, that is neither "." or "..", attempt to -- go to the next level. elsif Is_Directory (It.Dir_Name (1 .. It.Levels (Current).Name_Last) & S (1 .. Last)) and then S (1 .. Last) /= "." and then S (1 .. Last) /= ".." then -- We can go to the next level only if we have not reached the -- maximum depth, if Current < It.Maximum_Depth then NL := It.Levels (Current).Name_Last; -- And if relative path of this new directory is not too long if NL + Last + 1 < Max_Path_Length then Current := Current + 1; It.Current_Depth := Current; It.Dir_Name (NL + 1 .. NL + Last) := S (1 .. Last); NL := NL + Last + 1; It.Dir_Name (NL) := Directory_Separator; It.Levels (Current).Name_Last := NL; Canonical_Case_File_Name (It.Dir_Name (1 .. NL)); -- Open the new directory, and read from it GNAT.Directory_Operations.Open (It.Levels (Current).Dir, It.Dir_Name (1 .. NL)); end if; end if; end if; -- Check the relative path against the pattern -- Note that we try to match also against directory names, since -- clients of this function may expect to retrieve directories. declare Name : String := It.Dir_Name (It.Start .. It.Levels (Current).Name_Last) & S (1 .. Last); begin Canonical_Case_File_Name (Name); -- If it matches return the relative path if GNAT.Regexp.Match (Name, Iterator.Regexp) then return Name; end if; end; end loop; end Expansion; --------------------- -- Current_Section -- --------------------- function Current_Section (Parser : Opt_Parser := Command_Line_Parser) return String is begin if Parser.Current_Section = 1 then return ""; end if; for Index in reverse 1 .. Integer'Min (Parser.Current_Argument - 1, Parser.Section'Last) loop if Parser.Section (Index) = 0 then return Argument (Parser, Index); end if; end loop; return ""; end Current_Section; ----------------- -- Full_Switch -- ----------------- function Full_Switch (Parser : Opt_Parser := Command_Line_Parser) return String is begin if Parser.The_Switch.Extra = ASCII.NUL then return Argument (Parser, Parser.The_Switch.Arg_Num) (Parser.The_Switch.First .. Parser.The_Switch.Last); else return Parser.The_Switch.Extra & Argument (Parser, Parser.The_Switch.Arg_Num) (Parser.The_Switch.First .. Parser.The_Switch.Last); end if; end Full_Switch; ------------------ -- Get_Argument -- ------------------ function Get_Argument (Do_Expansion : Boolean := False; Parser : Opt_Parser := Command_Line_Parser) return String is End_Of_Args : Boolean; begin return Get_Argument (Do_Expansion, Parser, End_Of_Args); end Get_Argument; ------------------ -- Get_Argument -- ------------------ function Get_Argument (Do_Expansion : Boolean := False; Parser : Opt_Parser := Command_Line_Parser; End_Of_Arguments : out Boolean) return String is begin End_Of_Arguments := False; if Parser.In_Expansion then declare S : constant String := Expansion (Parser.Expansion_It); begin if S'Length /= 0 then return S; else Parser.In_Expansion := False; end if; end; end if; if Parser.Current_Argument > Parser.Arg_Count then -- If this is the first time this function is called if Parser.Current_Index = 1 then Parser.Current_Argument := 1; while Parser.Current_Argument <= Parser.Arg_Count and then Parser.Section (Parser.Current_Argument) /= Parser.Current_Section loop Parser.Current_Argument := Parser.Current_Argument + 1; end loop; else End_Of_Arguments := True; return String'(1 .. 0 => ' '); end if; elsif Parser.Section (Parser.Current_Argument) = 0 then while Parser.Current_Argument <= Parser.Arg_Count and then Parser.Section (Parser.Current_Argument) /= Parser.Current_Section loop Parser.Current_Argument := Parser.Current_Argument + 1; end loop; end if; Parser.Current_Index := Integer'Last; while Parser.Current_Argument <= Parser.Arg_Count and then Parser.Is_Switch (Parser.Current_Argument) loop Parser.Current_Argument := Parser.Current_Argument + 1; end loop; if Parser.Current_Argument > Parser.Arg_Count then End_Of_Arguments := True; return String'(1 .. 0 => ' '); elsif Parser.Section (Parser.Current_Argument) = 0 then return Get_Argument (Do_Expansion, Parser, End_Of_Arguments); end if; Parser.Current_Argument := Parser.Current_Argument + 1; -- Could it be a file name with wildcards to expand? if Do_Expansion then declare Arg : constant String := Argument (Parser, Parser.Current_Argument - 1); begin for Index in Arg'Range loop if Arg (Index) in '*' | '?' | '[' then Parser.In_Expansion := True; Start_Expansion (Parser.Expansion_It, Arg); return Get_Argument (Do_Expansion, Parser, End_Of_Arguments); end if; end loop; end; end if; return Argument (Parser, Parser.Current_Argument - 1); end Get_Argument; ---------------------- -- Decompose_Switch -- ---------------------- procedure Decompose_Switch (Switch : String; Parameter_Type : out Switch_Parameter_Type; Switch_Last : out Integer) is begin if Switch = "" then Parameter_Type := Parameter_None; Switch_Last := Switch'Last; return; end if; case Switch (Switch'Last) is when ':' => Parameter_Type := Parameter_With_Optional_Space; Switch_Last := Switch'Last - 1; when '=' => Parameter_Type := Parameter_With_Space_Or_Equal; Switch_Last := Switch'Last - 1; when '!' => Parameter_Type := Parameter_No_Space; Switch_Last := Switch'Last - 1; when '?' => Parameter_Type := Parameter_Optional; Switch_Last := Switch'Last - 1; when others => Parameter_Type := Parameter_None; Switch_Last := Switch'Last; end case; end Decompose_Switch; ---------------------------------- -- Find_Longest_Matching_Switch -- ---------------------------------- procedure Find_Longest_Matching_Switch (Switches : String; Arg : String; Index_In_Switches : out Integer; Switch_Length : out Integer; Param : out Switch_Parameter_Type) is Index : Natural; Length : Natural := 1; Last : Natural; P : Switch_Parameter_Type; begin Param := Parameter_None; Index_In_Switches := 0; Switch_Length := 0; -- Remove all leading spaces first to make sure that Index points -- at the start of the first switch. Index := Switches'First; while Index <= Switches'Last and then Switches (Index) = ' ' loop Index := Index + 1; end loop; while Index <= Switches'Last loop -- Search the length of the parameter at this position in Switches Length := Index; while Length <= Switches'Last and then Switches (Length) /= ' ' loop Length := Length + 1; end loop; -- Length now marks the separator after the current switch. Last will -- mark the last character of the name of the switch. if Length = Index + 1 then P := Parameter_None; Last := Index; else Decompose_Switch (Switches (Index .. Length - 1), P, Last); end if; -- If it is the one we searched, it may be a candidate if Arg'First + Last - Index <= Arg'Last and then Switches (Index .. Last) = Arg (Arg'First .. Arg'First + Last - Index) and then Last - Index + 1 > Switch_Length and then (P /= Parameter_With_Space_Or_Equal or else Arg'Last = Arg'First + Last - Index or else Arg (Arg'First + Last - Index + 1) = '=') then Param := P; Index_In_Switches := Index; Switch_Length := Last - Index + 1; end if; -- Look for the next switch in Switches while Index <= Switches'Last and then Switches (Index) /= ' ' loop Index := Index + 1; end loop; Index := Index + 1; end loop; end Find_Longest_Matching_Switch; ------------ -- Getopt -- ------------ function Getopt (Switches : String; Concatenate : Boolean := True; Parser : Opt_Parser := Command_Line_Parser) return Character is Dummy : Boolean; begin <> -- If we have finished parsing the current command line item (there -- might be multiple switches in a single item), then go to the next -- element. if Parser.Current_Argument > Parser.Arg_Count or else (Parser.Current_Index > Argument (Parser, Parser.Current_Argument)'Last and then not Goto_Next_Argument_In_Section (Parser)) then return ASCII.NUL; end if; -- By default, the switch will not have a parameter Parser.The_Parameter := (Integer'Last, Integer'Last, Integer'Last - 1, ASCII.NUL); Parser.The_Separator := ASCII.NUL; declare Arg : constant String := Argument (Parser, Parser.Current_Argument); Index_Switches : Natural := 0; Max_Length : Natural := 0; End_Index : Natural; Param : Switch_Parameter_Type; begin -- If we are on a new item, test if this might be a switch if Parser.Current_Index = Arg'First then if Arg = "" or else Arg (Arg'First) /= Parser.Switch_Character then -- If it isn't a switch, return it immediately. We also know it -- isn't the parameter to a previous switch, since that has -- already been handled. if Switches (Switches'First) = '*' then Set_Parameter (Parser.The_Switch, Arg_Num => Parser.Current_Argument, First => Arg'First, Last => Arg'Last); Parser.Is_Switch (Parser.Current_Argument) := True; Dummy := Goto_Next_Argument_In_Section (Parser); return '*'; end if; if Parser.Stop_At_First then Parser.Current_Argument := Positive'Last; return ASCII.NUL; elsif not Goto_Next_Argument_In_Section (Parser) then return ASCII.NUL; else -- Recurse to get the next switch on the command line goto Restart; end if; end if; -- We are on the first character of a new command line argument, -- which starts with Switch_Character. Further analysis is needed. Parser.Current_Index := Parser.Current_Index + 1; Parser.Is_Switch (Parser.Current_Argument) := True; end if; Find_Longest_Matching_Switch (Switches => Switches, Arg => Arg (Parser.Current_Index .. Arg'Last), Index_In_Switches => Index_Switches, Switch_Length => Max_Length, Param => Param); -- If switch is not accepted, it is either invalid or is returned -- in the context of '*'. if Index_Switches = 0 then -- Find the current switch that we did not recognize. This is in -- fact difficult because Getopt does not know explicitly about -- short and long switches. Ideally, we would want the following -- behavior: -- * for short switches, with Concatenate: -- if -a is not recognized, and the command line has -daf -- we should report the invalid switch as "-a". -- * for short switches, wihtout Concatenate: -- we should report the invalid switch as "-daf". -- * for long switches: -- if the commadn line is "--long" we should report --long -- as unrecongized. -- Unfortunately, the fact that long switches start with a -- duplicate switch character is just a convention (so we could -- have a long switch "-long" for instance). We'll still rely on -- this convention here to try and get as helpful an error message -- as possible. -- Long switch case (starting with double switch character) if Arg (Arg'First + 1) = Parser.Switch_Character then End_Index := Arg'Last; -- Short switch case else End_Index := (if Concatenate then Parser.Current_Index else Arg'Last); end if; if Switches /= "" and then Switches (Switches'First) = '*' then -- Always prepend the switch character, so that users know -- that this comes from a switch on the command line. This -- is especially important when Concatenate is False, since -- otherwise the current argument first character is lost. if Parser.Section (Parser.Current_Argument) = 0 then -- A section transition should not be returned to the user Dummy := Goto_Next_Argument_In_Section (Parser); goto Restart; else Set_Parameter (Parser.The_Switch, Arg_Num => Parser.Current_Argument, First => Parser.Current_Index, Last => Arg'Last, Extra => Parser.Switch_Character); Parser.Is_Switch (Parser.Current_Argument) := True; Dummy := Goto_Next_Argument_In_Section (Parser); return '*'; end if; end if; if Parser.Current_Index = Arg'First then Set_Parameter (Parser.The_Switch, Arg_Num => Parser.Current_Argument, First => Parser.Current_Index, Last => End_Index); else Set_Parameter (Parser.The_Switch, Arg_Num => Parser.Current_Argument, First => Parser.Current_Index, Last => End_Index, Extra => Parser.Switch_Character); end if; Parser.Current_Index := End_Index + 1; raise Invalid_Switch with "Unrecognized option '" & Full_Switch (Parser) & '''; end if; End_Index := Parser.Current_Index + Max_Length - 1; Set_Parameter (Parser.The_Switch, Arg_Num => Parser.Current_Argument, First => Parser.Current_Index, Last => End_Index); case Param is when Parameter_With_Optional_Space => if End_Index < Arg'Last then Set_Parameter (Parser.The_Parameter, Arg_Num => Parser.Current_Argument, First => End_Index + 1, Last => Arg'Last); Dummy := Goto_Next_Argument_In_Section (Parser); elsif Parser.Current_Argument < Parser.Arg_Count and then Parser.Section (Parser.Current_Argument + 1) /= 0 then Parser.Current_Argument := Parser.Current_Argument + 1; Parser.The_Separator := ' '; Set_Parameter (Parser.The_Parameter, Arg_Num => Parser.Current_Argument, First => Argument (Parser, Parser.Current_Argument)'First, Last => Argument (Parser, Parser.Current_Argument)'Last); Parser.Is_Switch (Parser.Current_Argument) := True; Dummy := Goto_Next_Argument_In_Section (Parser); else Parser.Current_Index := End_Index + 1; raise Invalid_Parameter; end if; when Parameter_With_Space_Or_Equal => -- If the switch is of the form =xxx if End_Index < Arg'Last then if Arg (End_Index + 1) = '=' and then End_Index + 1 < Arg'Last then Parser.The_Separator := '='; Set_Parameter (Parser.The_Parameter, Arg_Num => Parser.Current_Argument, First => End_Index + 2, Last => Arg'Last); Dummy := Goto_Next_Argument_In_Section (Parser); else Parser.Current_Index := End_Index + 1; raise Invalid_Parameter; end if; -- Case of switch of the form xxx elsif Parser.Current_Argument < Parser.Arg_Count and then Parser.Section (Parser.Current_Argument + 1) /= 0 then Parser.Current_Argument := Parser.Current_Argument + 1; Parser.The_Separator := ' '; Set_Parameter (Parser.The_Parameter, Arg_Num => Parser.Current_Argument, First => Argument (Parser, Parser.Current_Argument)'First, Last => Argument (Parser, Parser.Current_Argument)'Last); Parser.Is_Switch (Parser.Current_Argument) := True; Dummy := Goto_Next_Argument_In_Section (Parser); else Parser.Current_Index := End_Index + 1; raise Invalid_Parameter; end if; when Parameter_No_Space => if End_Index < Arg'Last then Set_Parameter (Parser.The_Parameter, Arg_Num => Parser.Current_Argument, First => End_Index + 1, Last => Arg'Last); Dummy := Goto_Next_Argument_In_Section (Parser); else Parser.Current_Index := End_Index + 1; raise Invalid_Parameter; end if; when Parameter_Optional => if End_Index < Arg'Last then Set_Parameter (Parser.The_Parameter, Arg_Num => Parser.Current_Argument, First => End_Index + 1, Last => Arg'Last); end if; Dummy := Goto_Next_Argument_In_Section (Parser); when Parameter_None => if Concatenate or else End_Index = Arg'Last then Parser.Current_Index := End_Index + 1; else -- If Concatenate is False and the full argument is not -- recognized as a switch, this is an invalid switch. if Switches (Switches'First) = '*' then Set_Parameter (Parser.The_Switch, Arg_Num => Parser.Current_Argument, First => Arg'First, Last => Arg'Last); Parser.Is_Switch (Parser.Current_Argument) := True; Dummy := Goto_Next_Argument_In_Section (Parser); return '*'; end if; Set_Parameter (Parser.The_Switch, Arg_Num => Parser.Current_Argument, First => Parser.Current_Index, Last => Arg'Last, Extra => Parser.Switch_Character); Parser.Current_Index := Arg'Last + 1; raise Invalid_Switch with "Unrecognized option '" & Full_Switch (Parser) & '''; end if; end case; return Switches (Index_Switches); end; end Getopt; ----------------------------------- -- Goto_Next_Argument_In_Section -- ----------------------------------- function Goto_Next_Argument_In_Section (Parser : Opt_Parser) return Boolean is begin Parser.Current_Argument := Parser.Current_Argument + 1; if Parser.Current_Argument > Parser.Arg_Count or else Parser.Section (Parser.Current_Argument) = 0 then loop Parser.Current_Argument := Parser.Current_Argument + 1; if Parser.Current_Argument > Parser.Arg_Count then Parser.Current_Index := 1; return False; end if; exit when Parser.Section (Parser.Current_Argument) = Parser.Current_Section; end loop; end if; Parser.Current_Index := Argument (Parser, Parser.Current_Argument)'First; return True; end Goto_Next_Argument_In_Section; ------------------ -- Goto_Section -- ------------------ procedure Goto_Section (Name : String := ""; Parser : Opt_Parser := Command_Line_Parser) is Index : Integer; begin Parser.In_Expansion := False; if Name = "" then Parser.Current_Argument := 1; Parser.Current_Index := 1; Parser.Current_Section := 1; return; end if; Index := 1; while Index <= Parser.Arg_Count loop if Parser.Section (Index) = 0 and then Argument (Parser, Index) = Parser.Switch_Character & Name then Parser.Current_Argument := Index + 1; Parser.Current_Index := 1; if Parser.Current_Argument <= Parser.Arg_Count then Parser.Current_Section := Parser.Section (Parser.Current_Argument); end if; -- Exit from loop if we have the start of another section if Index = Parser.Section'Last or else Parser.Section (Index + 1) /= 0 then return; end if; end if; Index := Index + 1; end loop; Parser.Current_Argument := Positive'Last; Parser.Current_Index := 2; -- so that Get_Argument returns nothing end Goto_Section; ---------------------------- -- Initialize_Option_Scan -- ---------------------------- procedure Initialize_Option_Scan (Switch_Char : Character := '-'; Stop_At_First_Non_Switch : Boolean := False; Section_Delimiters : String := "") is begin Internal_Initialize_Option_Scan (Parser => Command_Line_Parser, Switch_Char => Switch_Char, Stop_At_First_Non_Switch => Stop_At_First_Non_Switch, Section_Delimiters => Section_Delimiters); end Initialize_Option_Scan; ---------------------------- -- Initialize_Option_Scan -- ---------------------------- procedure Initialize_Option_Scan (Parser : out Opt_Parser; Command_Line : GNAT.OS_Lib.Argument_List_Access; Switch_Char : Character := '-'; Stop_At_First_Non_Switch : Boolean := False; Section_Delimiters : String := "") is begin Free (Parser); if Command_Line = null then Parser := new Opt_Parser_Data (CL.Argument_Count); Internal_Initialize_Option_Scan (Parser => Parser, Switch_Char => Switch_Char, Stop_At_First_Non_Switch => Stop_At_First_Non_Switch, Section_Delimiters => Section_Delimiters); else Parser := new Opt_Parser_Data (Command_Line'Length); Parser.Arguments := Command_Line; Internal_Initialize_Option_Scan (Parser => Parser, Switch_Char => Switch_Char, Stop_At_First_Non_Switch => Stop_At_First_Non_Switch, Section_Delimiters => Section_Delimiters); end if; end Initialize_Option_Scan; ------------------------------------- -- Internal_Initialize_Option_Scan -- ------------------------------------- procedure Internal_Initialize_Option_Scan (Parser : Opt_Parser; Switch_Char : Character; Stop_At_First_Non_Switch : Boolean; Section_Delimiters : String) is Section_Num : Section_Number; Section_Index : Integer; Last : Integer; Delimiter_Found : Boolean; Discard : Boolean; pragma Warnings (Off, Discard); begin Parser.Current_Argument := 0; Parser.Current_Index := 0; Parser.In_Expansion := False; Parser.Switch_Character := Switch_Char; Parser.Stop_At_First := Stop_At_First_Non_Switch; Parser.Section := (others => 1); -- If we are using sections, we have to preprocess the command line to -- delimit them. A section can be repeated, so we just give each item -- on the command line a section number Section_Num := 1; Section_Index := Section_Delimiters'First; while Section_Index <= Section_Delimiters'Last loop Last := Section_Index; while Last <= Section_Delimiters'Last and then Section_Delimiters (Last) /= ' ' loop Last := Last + 1; end loop; Delimiter_Found := False; Section_Num := Section_Num + 1; for Index in 1 .. Parser.Arg_Count loop pragma Assert (Argument (Parser, Index)'First = 1); if Argument (Parser, Index) /= "" and then Argument (Parser, Index)(1) = Parser.Switch_Character and then Argument (Parser, Index) = Parser.Switch_Character & Section_Delimiters (Section_Index .. Last - 1) then Parser.Section (Index) := 0; Delimiter_Found := True; elsif Parser.Section (Index) = 0 then -- A previous section delimiter Delimiter_Found := False; elsif Delimiter_Found then Parser.Section (Index) := Section_Num; end if; end loop; Section_Index := Last + 1; while Section_Index <= Section_Delimiters'Last and then Section_Delimiters (Section_Index) = ' ' loop Section_Index := Section_Index + 1; end loop; end loop; Discard := Goto_Next_Argument_In_Section (Parser); end Internal_Initialize_Option_Scan; --------------- -- Parameter -- --------------- function Parameter (Parser : Opt_Parser := Command_Line_Parser) return String is begin if Parser.The_Parameter.First > Parser.The_Parameter.Last then return String'(1 .. 0 => ' '); else return Argument (Parser, Parser.The_Parameter.Arg_Num) (Parser.The_Parameter.First .. Parser.The_Parameter.Last); end if; end Parameter; --------------- -- Separator -- --------------- function Separator (Parser : Opt_Parser := Command_Line_Parser) return Character is begin return Parser.The_Separator; end Separator; ------------------- -- Set_Parameter -- ------------------- procedure Set_Parameter (Variable : out Parameter_Type; Arg_Num : Positive; First : Positive; Last : Natural; Extra : Character := ASCII.NUL) is begin Variable.Arg_Num := Arg_Num; Variable.First := First; Variable.Last := Last; Variable.Extra := Extra; end Set_Parameter; --------------------- -- Start_Expansion -- --------------------- procedure Start_Expansion (Iterator : out Expansion_Iterator; Pattern : String; Directory : String := ""; Basic_Regexp : Boolean := True) is Directory_Separator : Character; pragma Import (C, Directory_Separator, "__gnat_dir_separator"); First : Positive := Pattern'First; Pat : String := Pattern; begin Canonical_Case_File_Name (Pat); Iterator.Current_Depth := 1; -- If Directory is unspecified, use the current directory ("./" or ".\") if Directory = "" then Iterator.Dir_Name (1 .. 2) := "." & Directory_Separator; Iterator.Start := 3; else Iterator.Dir_Name (1 .. Directory'Length) := Directory; Iterator.Start := Directory'Length + 1; Canonical_Case_File_Name (Iterator.Dir_Name (1 .. Directory'Length)); -- Make sure that the last character is a directory separator if Directory (Directory'Last) /= Directory_Separator then Iterator.Dir_Name (Iterator.Start) := Directory_Separator; Iterator.Start := Iterator.Start + 1; end if; end if; Iterator.Levels (1).Name_Last := Iterator.Start - 1; -- Open the initial Directory, at depth 1 GNAT.Directory_Operations.Open (Iterator.Levels (1).Dir, Iterator.Dir_Name (1 .. Iterator.Start - 1)); -- If in the current directory and the pattern starts with "./" or ".\", -- drop the "./" or ".\" from the pattern. if Directory = "" and then Pat'Length > 2 and then Pat (Pat'First) = '.' and then Pat (Pat'First + 1) = Directory_Separator then First := Pat'First + 2; end if; Iterator.Regexp := GNAT.Regexp.Compile (Pat (First .. Pat'Last), Basic_Regexp, True); Iterator.Maximum_Depth := 1; -- Maximum_Depth is equal to 1 plus the number of directory separators -- in the pattern. for Index in First .. Pat'Last loop if Pat (Index) = Directory_Separator then Iterator.Maximum_Depth := Iterator.Maximum_Depth + 1; exit when Iterator.Maximum_Depth = Max_Depth; end if; end loop; end Start_Expansion; ---------- -- Free -- ---------- procedure Free (Parser : in out Opt_Parser) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Opt_Parser_Data, Opt_Parser); begin if Parser /= null and then Parser /= Command_Line_Parser then Free (Parser.Arguments); Unchecked_Free (Parser); end if; end Free; ------------------ -- Define_Alias -- ------------------ procedure Define_Alias (Config : in out Command_Line_Configuration; Switch : String; Expanded : String; Section : String := "") is Def : Alias_Definition; begin if Config = null then Config := new Command_Line_Configuration_Record; end if; Def.Alias := new String'(Switch); Def.Expansion := new String'(Expanded); Def.Section := new String'(Section); Add (Config.Aliases, Def); end Define_Alias; ------------------- -- Define_Prefix -- ------------------- procedure Define_Prefix (Config : in out Command_Line_Configuration; Prefix : String) is begin if Config = null then Config := new Command_Line_Configuration_Record; end if; Add (Config.Prefixes, new String'(Prefix)); end Define_Prefix; --------- -- Add -- --------- procedure Add (Config : in out Command_Line_Configuration; Switch : Switch_Definition) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Switch_Definitions, Switch_Definitions_List); Tmp : Switch_Definitions_List; begin if Config = null then Config := new Command_Line_Configuration_Record; end if; Tmp := Config.Switches; if Tmp = null then Config.Switches := new Switch_Definitions (1 .. 1); else Config.Switches := new Switch_Definitions (1 .. Tmp'Length + 1); Config.Switches (1 .. Tmp'Length) := Tmp.all; Unchecked_Free (Tmp); end if; if Switch.Switch /= null and then Switch.Switch.all = "*" then Config.Star_Switch := True; end if; Config.Switches (Config.Switches'Last) := Switch; end Add; --------- -- Add -- --------- procedure Add (Def : in out Alias_Definitions_List; Alias : Alias_Definition) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Alias_Definitions, Alias_Definitions_List); Tmp : Alias_Definitions_List := Def; begin if Tmp = null then Def := new Alias_Definitions (1 .. 1); else Def := new Alias_Definitions (1 .. Tmp'Length + 1); Def (1 .. Tmp'Length) := Tmp.all; Unchecked_Free (Tmp); end if; Def (Def'Last) := Alias; end Add; --------------------------- -- Initialize_Switch_Def -- --------------------------- procedure Initialize_Switch_Def (Def : out Switch_Definition; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG") is P1, P2 : Switch_Parameter_Type := Parameter_None; Last1, Last2 : Integer; begin if Switch /= "" then Def.Switch := new String'(Switch); Decompose_Switch (Switch, P1, Last1); end if; if Long_Switch /= "" then Def.Long_Switch := new String'(Long_Switch); Decompose_Switch (Long_Switch, P2, Last2); end if; if Switch /= "" and then Long_Switch /= "" then if (P1 = Parameter_None and then P2 /= P1) or else (P2 = Parameter_None and then P1 /= P2) or else (P1 = Parameter_Optional and then P2 /= P1) or else (P2 = Parameter_Optional and then P2 /= P1) then raise Invalid_Switch with "Inconsistent parameter types for " & Switch & " and " & Long_Switch; end if; end if; if Section /= "" then Def.Section := new String'(Section); end if; if Argument /= "ARG" then Def.Argument := new String'(Argument); end if; if Help /= "" then Def.Help := new String'(Help); end if; end Initialize_Switch_Def; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Command_Line_Configuration; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG") is Def : Switch_Definition; begin if Switch /= "" or else Long_Switch /= "" then Initialize_Switch_Def (Def, Switch, Long_Switch, Help, Section, Argument); Add (Config, Def); end if; end Define_Switch; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Command_Line_Configuration; Output : access Boolean; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Value : Boolean := True) is Def : Switch_Definition (Switch_Boolean); begin if Switch /= "" or else Long_Switch /= "" then Initialize_Switch_Def (Def, Switch, Long_Switch, Help, Section); Def.Boolean_Output := Output.all'Unchecked_Access; Def.Boolean_Value := Value; Add (Config, Def); end if; end Define_Switch; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Command_Line_Configuration; Output : access Integer; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Initial : Integer := 0; Default : Integer := 1; Argument : String := "ARG") is Def : Switch_Definition (Switch_Integer); begin if Switch /= "" or else Long_Switch /= "" then Initialize_Switch_Def (Def, Switch, Long_Switch, Help, Section, Argument); Def.Integer_Output := Output.all'Unchecked_Access; Def.Integer_Default := Default; Def.Integer_Initial := Initial; Add (Config, Def); end if; end Define_Switch; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Command_Line_Configuration; Output : access GNAT.Strings.String_Access; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG") is Def : Switch_Definition (Switch_String); begin if Switch /= "" or else Long_Switch /= "" then Initialize_Switch_Def (Def, Switch, Long_Switch, Help, Section, Argument); Def.String_Output := Output.all'Unchecked_Access; Add (Config, Def); end if; end Define_Switch; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Command_Line_Configuration; Callback : not null Value_Callback; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG") is Def : Switch_Definition (Switch_Callback); begin if Switch /= "" or else Long_Switch /= "" then Initialize_Switch_Def (Def, Switch, Long_Switch, Help, Section, Argument); Def.Callback := Callback; Add (Config, Def); end if; end Define_Switch; -------------------- -- Define_Section -- -------------------- procedure Define_Section (Config : in out Command_Line_Configuration; Section : String) is begin if Config = null then Config := new Command_Line_Configuration_Record; end if; Add (Config.Sections, new String'(Section)); end Define_Section; -------------------- -- Foreach_Switch -- -------------------- procedure Foreach_Switch (Config : Command_Line_Configuration; Section : String) is begin if Config /= null and then Config.Switches /= null then for J in Config.Switches'Range loop if (Section = "" and then Config.Switches (J).Section = null) or else (Config.Switches (J).Section /= null and then Config.Switches (J).Section.all = Section) then exit when Config.Switches (J).Switch /= null and then not Callback (Config.Switches (J).Switch.all, J); exit when Config.Switches (J).Long_Switch /= null and then not Callback (Config.Switches (J).Long_Switch.all, J); end if; end loop; end if; end Foreach_Switch; ------------------ -- Get_Switches -- ------------------ function Get_Switches (Config : Command_Line_Configuration; Switch_Char : Character := '-'; Section : String := "") return String is Ret : Ada.Strings.Unbounded.Unbounded_String; use Ada.Strings.Unbounded; function Add_Switch (S : String; Index : Integer) return Boolean; -- Add a switch to Ret ---------------- -- Add_Switch -- ---------------- function Add_Switch (S : String; Index : Integer) return Boolean is pragma Unreferenced (Index); begin if S = "*" then Ret := "*" & Ret; -- Always first elsif S (S'First) = Switch_Char then Append (Ret, " " & S (S'First + 1 .. S'Last)); else Append (Ret, " " & S); end if; return True; end Add_Switch; Tmp : Boolean; pragma Unreferenced (Tmp); procedure Foreach is new Foreach_Switch (Add_Switch); -- Start of processing for Get_Switches begin if Config = null then return ""; end if; Foreach (Config, Section => Section); -- Add relevant aliases if Config.Aliases /= null then for A in Config.Aliases'Range loop if Config.Aliases (A).Section.all = Section then Tmp := Add_Switch (Config.Aliases (A).Alias.all, -1); end if; end loop; end if; return To_String (Ret); end Get_Switches; ------------------------ -- Section_Delimiters -- ------------------------ function Section_Delimiters (Config : Command_Line_Configuration) return String is use Ada.Strings.Unbounded; Result : Unbounded_String; begin if Config /= null and then Config.Sections /= null then for S in Config.Sections'Range loop Append (Result, " " & Config.Sections (S).all); end loop; end if; return To_String (Result); end Section_Delimiters; ----------------------- -- Set_Configuration -- ----------------------- procedure Set_Configuration (Cmd : in out Command_Line; Config : Command_Line_Configuration) is begin Cmd.Config := Config; end Set_Configuration; ----------------------- -- Get_Configuration -- ----------------------- function Get_Configuration (Cmd : Command_Line) return Command_Line_Configuration is begin return Cmd.Config; end Get_Configuration; ---------------------- -- Set_Command_Line -- ---------------------- procedure Set_Command_Line (Cmd : in out Command_Line; Switches : String; Getopt_Description : String := ""; Switch_Char : Character := '-') is Tmp : Argument_List_Access; Parser : Opt_Parser; S : Character; Section : String_Access := null; function Real_Full_Switch (S : Character; Parser : Opt_Parser) return String; -- Ensure that the returned switch value contains the Switch_Char prefix -- if needed. ---------------------- -- Real_Full_Switch -- ---------------------- function Real_Full_Switch (S : Character; Parser : Opt_Parser) return String is begin if S = '*' then return Full_Switch (Parser); else return Switch_Char & Full_Switch (Parser); end if; end Real_Full_Switch; -- Start of processing for Set_Command_Line begin Free (Cmd.Expanded); Free (Cmd.Params); if Switches /= "" then Tmp := Argument_String_To_List (Switches); Initialize_Option_Scan (Parser, Tmp, Switch_Char); loop begin if Cmd.Config /= null then -- Do not use Getopt_Description in this case. Otherwise, -- if we have defined a prefix -gnaty, and two switches -- -gnatya and -gnatyL!, we would have a different behavior -- depending on the order of switches: -- -gnatyL1a => -gnatyL with argument "1a" -- -gnatyaL1 => -gnatya and -gnatyL with argument "1" -- This is because the call to Getopt below knows nothing -- about prefixes, and in the first case finds a valid -- switch with arguments, so returns it without analyzing -- the argument. In the second case, the switch matches "*", -- and is then decomposed below. -- Note: When a Command_Line object is associated with a -- Command_Line_Config (which is mostly the case for tools -- that let users choose the command line before spawning -- other tools, for instance IDEs), the configuration of -- the switches must be taken from the Command_Line_Config. S := Getopt (Switches => "* " & Get_Switches (Cmd.Config), Concatenate => False, Parser => Parser); else S := Getopt (Switches => "* " & Getopt_Description, Concatenate => False, Parser => Parser); end if; exit when S = ASCII.NUL; declare Sw : constant String := Real_Full_Switch (S, Parser); Is_Section : Boolean := False; begin if Cmd.Config /= null and then Cmd.Config.Sections /= null then Section_Search : for S in Cmd.Config.Sections'Range loop if Sw = Cmd.Config.Sections (S).all then Section := Cmd.Config.Sections (S); Is_Section := True; exit Section_Search; end if; end loop Section_Search; end if; if not Is_Section then if Section = null then Add_Switch (Cmd, Sw, Parameter (Parser)); else Add_Switch (Cmd, Sw, Parameter (Parser), Section => Section.all); end if; end if; end; exception when Invalid_Parameter => -- Add it with no parameter, if that's the way the user -- wants it. -- Specify the separator in all cases, as the switch might -- need to be unaliased, and the alias might contain -- switches with parameters. if Section = null then Add_Switch (Cmd, Switch_Char & Full_Switch (Parser)); else Add_Switch (Cmd, Switch_Char & Full_Switch (Parser), Section => Section.all); end if; end; end loop; Free (Parser); end if; end Set_Command_Line; ---------------- -- Looking_At -- ---------------- function Looking_At (Type_Str : String; Index : Natural; Substring : String) return Boolean is begin return Index + Substring'Length - 1 <= Type_Str'Last and then Type_Str (Index .. Index + Substring'Length - 1) = Substring; end Looking_At; ------------------------ -- Can_Have_Parameter -- ------------------------ function Can_Have_Parameter (S : String) return Boolean is begin if S'Length <= 1 then return False; end if; case S (S'Last) is when '!' | ':' | '?' | '=' => return True; when others => return False; end case; end Can_Have_Parameter; ----------------------- -- Require_Parameter -- ----------------------- function Require_Parameter (S : String) return Boolean is begin if S'Length <= 1 then return False; end if; case S (S'Last) is when '!' | ':' | '=' => return True; when others => return False; end case; end Require_Parameter; ------------------- -- Actual_Switch -- ------------------- function Actual_Switch (S : String) return String is begin if S'Length <= 1 then return S; end if; case S (S'Last) is when '!' | ':' | '?' | '=' => return S (S'First .. S'Last - 1); when others => return S; end case; end Actual_Switch; ---------------------------- -- For_Each_Simple_Switch -- ---------------------------- procedure For_Each_Simple_Switch (Config : Command_Line_Configuration; Section : String; Switch : String; Parameter : String := ""; Unalias : Boolean := True) is function Group_Analysis (Prefix : String; Group : String) return Boolean; -- Perform the analysis of a group of switches Found_In_Config : Boolean := False; function Is_In_Config (Config_Switch : String; Index : Integer) return Boolean; -- If Switch is the same as Config_Switch, run the callback and sets -- Found_In_Config to True. function Starts_With (Config_Switch : String; Index : Integer) return Boolean; -- if Switch starts with Config_Switch, sets Found_In_Config to True. -- The return value is for the Foreach_Switch iterator. -------------------- -- Group_Analysis -- -------------------- function Group_Analysis (Prefix : String; Group : String) return Boolean is Idx : Natural; Found : Boolean; function Analyze_Simple_Switch (Switch : String; Index : Integer) return Boolean; -- "Switches" is one of the switch definitions passed to the -- configuration, not one of the switches found on the command line. --------------------------- -- Analyze_Simple_Switch -- --------------------------- function Analyze_Simple_Switch (Switch : String; Index : Integer) return Boolean is pragma Unreferenced (Index); Full : constant String := Prefix & Group (Idx .. Group'Last); Sw : constant String := Actual_Switch (Switch); -- Switches definition minus argument definition Last : Natural; Param : Natural; begin -- Verify that sw starts with Prefix if Looking_At (Sw, Sw'First, Prefix) -- Verify that the group starts with sw and then Looking_At (Full, Full'First, Sw) then Last := Idx + Sw'Length - Prefix'Length - 1; Param := Last + 1; if Can_Have_Parameter (Switch) then -- Include potential parameter to the recursive call. Only -- numbers are allowed. while Last < Group'Last and then Group (Last + 1) in '0' .. '9' loop Last := Last + 1; end loop; end if; if not Require_Parameter (Switch) or else Last >= Param then if Idx = Group'First and then Last = Group'Last and then Last < Param then -- The group only concerns a single switch. Do not -- perform recursive call. -- Note that we still perform a recursive call if -- a parameter is detected in the switch, as this -- is a way to correctly identify such a parameter -- in aliases. return False; end if; Found := True; -- Recursive call, using the detected parameter if any if Last >= Param then For_Each_Simple_Switch (Config, Section, Prefix & Group (Idx .. Param - 1), Group (Param .. Last)); else For_Each_Simple_Switch (Config, Section, Prefix & Group (Idx .. Last), ""); end if; Idx := Last + 1; return False; end if; end if; return True; end Analyze_Simple_Switch; procedure Foreach is new Foreach_Switch (Analyze_Simple_Switch); -- Start of processing for Group_Analysis begin Idx := Group'First; while Idx <= Group'Last loop Found := False; Foreach (Config, Section); if not Found then For_Each_Simple_Switch (Config, Section, Prefix & Group (Idx), ""); Idx := Idx + 1; end if; end loop; return True; end Group_Analysis; ------------------ -- Is_In_Config -- ------------------ function Is_In_Config (Config_Switch : String; Index : Integer) return Boolean is Last : Natural; P : Switch_Parameter_Type; begin Decompose_Switch (Config_Switch, P, Last); if Config_Switch (Config_Switch'First .. Last) = Switch then case P is when Parameter_None => if Parameter = "" then Callback (Switch, "", "", Index => Index); Found_In_Config := True; return False; end if; when Parameter_With_Optional_Space => Callback (Switch, " ", Parameter, Index => Index); Found_In_Config := True; return False; when Parameter_With_Space_Or_Equal => Callback (Switch, "=", Parameter, Index => Index); Found_In_Config := True; return False; when Parameter_No_Space | Parameter_Optional => Callback (Switch, "", Parameter, Index); Found_In_Config := True; return False; end case; end if; return True; end Is_In_Config; ----------------- -- Starts_With -- ----------------- function Starts_With (Config_Switch : String; Index : Integer) return Boolean is Last : Natural; Param : Natural; P : Switch_Parameter_Type; begin -- This function is called when we believe the parameter was -- specified as part of the switch, instead of separately. Thus we -- look in the config to find all possible switches. Decompose_Switch (Config_Switch, P, Last); if Looking_At (Switch, Switch'First, Config_Switch (Config_Switch'First .. Last)) then -- Set first char of Param, and last char of Switch Param := Switch'First + Last; Last := Switch'First + Last - Config_Switch'First; case P is -- None is already handled in Is_In_Config when Parameter_None => null; when Parameter_With_Space_Or_Equal => if Param <= Switch'Last and then (Switch (Param) = ' ' or else Switch (Param) = '=') then Callback (Switch (Switch'First .. Last), "=", Switch (Param + 1 .. Switch'Last), Index); Found_In_Config := True; return False; end if; when Parameter_With_Optional_Space => if Param <= Switch'Last and then Switch (Param) = ' ' then Param := Param + 1; end if; Callback (Switch (Switch'First .. Last), " ", Switch (Param .. Switch'Last), Index); Found_In_Config := True; return False; when Parameter_No_Space | Parameter_Optional => Callback (Switch (Switch'First .. Last), "", Switch (Param .. Switch'Last), Index); Found_In_Config := True; return False; end case; end if; return True; end Starts_With; procedure Foreach_In_Config is new Foreach_Switch (Is_In_Config); procedure Foreach_Starts_With is new Foreach_Switch (Starts_With); -- Start of processing for For_Each_Simple_Switch begin -- First determine if the switch corresponds to one belonging to the -- configuration. If so, run callback and exit. -- ??? Is this necessary. On simple tests, we seem to have the same -- results with or without this call. Foreach_In_Config (Config, Section); if Found_In_Config then return; end if; -- If adding a switch that can in fact be expanded through aliases, -- add separately each of its expansions. -- This takes care of expansions like "-T" -> "-gnatwrs", where the -- alias and its expansion do not have the same prefix. Given the order -- in which we do things here, the expansion of the alias will itself -- be checked for a common prefix and split into simple switches. if Unalias and then Config /= null and then Config.Aliases /= null then for A in Config.Aliases'Range loop if Config.Aliases (A).Section.all = Section and then Config.Aliases (A).Alias.all = Switch and then Parameter = "" then For_Each_Simple_Switch (Config, Section, Config.Aliases (A).Expansion.all, ""); return; end if; end loop; end if; -- If adding a switch grouping several switches, add each of the simple -- switches instead. if Config /= null and then Config.Prefixes /= null then for P in Config.Prefixes'Range loop if Switch'Length > Config.Prefixes (P)'Length + 1 and then Looking_At (Switch, Switch'First, Config.Prefixes (P).all) then -- Alias expansion will be done recursively if Config.Switches = null then for S in Switch'First + Config.Prefixes (P)'Length .. Switch'Last loop For_Each_Simple_Switch (Config, Section, Config.Prefixes (P).all & Switch (S), ""); end loop; return; elsif Group_Analysis (Config.Prefixes (P).all, Switch (Switch'First + Config.Prefixes (P)'Length .. Switch'Last)) then -- Recursive calls already done on each switch of the group: -- Return without executing Callback. return; end if; end if; end loop; end if; -- Test if added switch is a known switch with parameter attached -- instead of being specified separately if Parameter = "" and then Config /= null and then Config.Switches /= null then Found_In_Config := False; Foreach_Starts_With (Config, Section); if Found_In_Config then return; end if; end if; -- The switch is invalid in the config, but we still want to report it. -- The config could, for instance, include "*" to specify it accepts -- all switches. Callback (Switch, " ", Parameter, Index => -1); end For_Each_Simple_Switch; ---------------- -- Add_Switch -- ---------------- procedure Add_Switch (Cmd : in out Command_Line; Switch : String; Parameter : String := ""; Separator : Character := ASCII.NUL; Section : String := ""; Add_Before : Boolean := False) is Success : Boolean; pragma Unreferenced (Success); begin Add_Switch (Cmd, Switch, Parameter, Separator, Section, Add_Before, Success); end Add_Switch; ---------------- -- Add_Switch -- ---------------- procedure Add_Switch (Cmd : in out Command_Line; Switch : String; Parameter : String := ""; Separator : Character := ASCII.NUL; Section : String := ""; Add_Before : Boolean := False; Success : out Boolean) is procedure Add_Simple_Switch (Simple : String; Sepa : String; Param : String; Index : Integer); -- Add a new switch that has had all its aliases expanded, and switches -- ungrouped. We know there are no more aliases in Switches. ----------------------- -- Add_Simple_Switch -- ----------------------- procedure Add_Simple_Switch (Simple : String; Sepa : String; Param : String; Index : Integer) is Sep : Character; begin if Index = -1 and then Cmd.Config /= null and then not Cmd.Config.Star_Switch then raise Invalid_Switch with "Invalid switch " & Simple; end if; if Separator /= ASCII.NUL then Sep := Separator; elsif Sepa = "" then Sep := ASCII.NUL; else Sep := Sepa (Sepa'First); end if; if Cmd.Expanded = null then Cmd.Expanded := new Argument_List'(1 .. 1 => new String'(Simple)); if Param /= "" then Cmd.Params := new Argument_List'(1 .. 1 => new String'(Sep & Param)); else Cmd.Params := new Argument_List'(1 .. 1 => null); end if; if Section = "" then Cmd.Sections := new Argument_List'(1 .. 1 => null); else Cmd.Sections := new Argument_List'(1 .. 1 => new String'(Section)); end if; else -- Do we already have this switch? for C in Cmd.Expanded'Range loop if Cmd.Expanded (C).all = Simple and then ((Cmd.Params (C) = null and then Param = "") or else (Cmd.Params (C) /= null and then Cmd.Params (C).all = Sep & Param)) and then ((Cmd.Sections (C) = null and then Section = "") or else (Cmd.Sections (C) /= null and then Cmd.Sections (C).all = Section)) then return; end if; end loop; -- Inserting at least one switch Success := True; Add (Cmd.Expanded, new String'(Simple), Add_Before); if Param /= "" then Add (Cmd.Params, new String'(Sep & Param), Add_Before); else Add (Cmd.Params, null, Add_Before); end if; if Section = "" then Add (Cmd.Sections, null, Add_Before); else Add (Cmd.Sections, new String'(Section), Add_Before); end if; end if; end Add_Simple_Switch; procedure Add_Simple_Switches is new For_Each_Simple_Switch (Add_Simple_Switch); -- Local Variables Section_Valid : Boolean := False; -- Start of processing for Add_Switch begin if Section /= "" and then Cmd.Config /= null then for S in Cmd.Config.Sections'Range loop if Section = Cmd.Config.Sections (S).all then Section_Valid := True; exit; end if; end loop; if not Section_Valid then raise Invalid_Section; end if; end if; Success := False; Add_Simple_Switches (Cmd.Config, Section, Switch, Parameter); Free (Cmd.Coalesce); end Add_Switch; ------------ -- Remove -- ------------ procedure Remove (Line : in out Argument_List_Access; Index : Integer) is Tmp : Argument_List_Access := Line; begin Line := new Argument_List (Tmp'First .. Tmp'Last - 1); if Index /= Tmp'First then Line (Tmp'First .. Index - 1) := Tmp (Tmp'First .. Index - 1); end if; Free (Tmp (Index)); if Index /= Tmp'Last then Line (Index .. Tmp'Last - 1) := Tmp (Index + 1 .. Tmp'Last); end if; Unchecked_Free (Tmp); end Remove; --------- -- Add -- --------- procedure Add (Line : in out Argument_List_Access; Str : String_Access; Before : Boolean := False) is Tmp : Argument_List_Access := Line; begin if Tmp /= null then Line := new Argument_List (Tmp'First .. Tmp'Last + 1); if Before then Line (Tmp'First) := Str; Line (Tmp'First + 1 .. Tmp'Last + 1) := Tmp.all; else Line (Tmp'Range) := Tmp.all; Line (Tmp'Last + 1) := Str; end if; Unchecked_Free (Tmp); else Line := new Argument_List'(1 .. 1 => Str); end if; end Add; ------------------- -- Remove_Switch -- ------------------- procedure Remove_Switch (Cmd : in out Command_Line; Switch : String; Remove_All : Boolean := False; Has_Parameter : Boolean := False; Section : String := "") is Success : Boolean; pragma Unreferenced (Success); begin Remove_Switch (Cmd, Switch, Remove_All, Has_Parameter, Section, Success); end Remove_Switch; ------------------- -- Remove_Switch -- ------------------- procedure Remove_Switch (Cmd : in out Command_Line; Switch : String; Remove_All : Boolean := False; Has_Parameter : Boolean := False; Section : String := ""; Success : out Boolean) is procedure Remove_Simple_Switch (Simple, Separator, Param : String; Index : Integer); -- Removes a simple switch, with no aliasing or grouping -------------------------- -- Remove_Simple_Switch -- -------------------------- procedure Remove_Simple_Switch (Simple, Separator, Param : String; Index : Integer) is C : Integer; pragma Unreferenced (Param, Separator, Index); begin if Cmd.Expanded /= null then C := Cmd.Expanded'First; while C <= Cmd.Expanded'Last loop if Cmd.Expanded (C).all = Simple and then (Remove_All or else (Cmd.Sections (C) = null and then Section = "") or else (Cmd.Sections (C) /= null and then Section = Cmd.Sections (C).all)) and then (not Has_Parameter or else Cmd.Params (C) /= null) then Remove (Cmd.Expanded, C); Remove (Cmd.Params, C); Remove (Cmd.Sections, C); Success := True; if not Remove_All then return; end if; else C := C + 1; end if; end loop; end if; end Remove_Simple_Switch; procedure Remove_Simple_Switches is new For_Each_Simple_Switch (Remove_Simple_Switch); -- Start of processing for Remove_Switch begin Success := False; Remove_Simple_Switches (Cmd.Config, Section, Switch, "", Unalias => not Has_Parameter); Free (Cmd.Coalesce); end Remove_Switch; ------------------- -- Remove_Switch -- ------------------- procedure Remove_Switch (Cmd : in out Command_Line; Switch : String; Parameter : String; Section : String := "") is procedure Remove_Simple_Switch (Simple, Separator, Param : String; Index : Integer); -- Removes a simple switch, with no aliasing or grouping -------------------------- -- Remove_Simple_Switch -- -------------------------- procedure Remove_Simple_Switch (Simple, Separator, Param : String; Index : Integer) is pragma Unreferenced (Separator, Index); C : Integer; begin if Cmd.Expanded /= null then C := Cmd.Expanded'First; while C <= Cmd.Expanded'Last loop if Cmd.Expanded (C).all = Simple and then ((Cmd.Sections (C) = null and then Section = "") or else (Cmd.Sections (C) /= null and then Section = Cmd.Sections (C).all)) and then ((Cmd.Params (C) = null and then Param = "") or else (Cmd.Params (C) /= null -- Ignore the separator stored in Parameter and then Cmd.Params (C) (Cmd.Params (C)'First + 1 .. Cmd.Params (C)'Last) = Param)) then Remove (Cmd.Expanded, C); Remove (Cmd.Params, C); Remove (Cmd.Sections, C); -- The switch is necessarily unique by construction of -- Add_Switch. return; else C := C + 1; end if; end loop; end if; end Remove_Simple_Switch; procedure Remove_Simple_Switches is new For_Each_Simple_Switch (Remove_Simple_Switch); -- Start of processing for Remove_Switch begin Remove_Simple_Switches (Cmd.Config, Section, Switch, Parameter); Free (Cmd.Coalesce); end Remove_Switch; -------------------- -- Group_Switches -- -------------------- procedure Group_Switches (Cmd : Command_Line; Result : Argument_List_Access; Sections : Argument_List_Access; Params : Argument_List_Access) is function Compatible_Parameter (Param : String_Access) return Boolean; -- True when the parameter can be part of a group -------------------------- -- Compatible_Parameter -- -------------------------- function Compatible_Parameter (Param : String_Access) return Boolean is begin -- No parameter OK if Param = null then return True; -- We need parameters without separators elsif Param (Param'First) /= ASCII.NUL then return False; -- Parameters must be all digits else for J in Param'First + 1 .. Param'Last loop if Param (J) not in '0' .. '9' then return False; end if; end loop; return True; end if; end Compatible_Parameter; -- Local declarations Group : Ada.Strings.Unbounded.Unbounded_String; First : Natural; use type Ada.Strings.Unbounded.Unbounded_String; -- Start of processing for Group_Switches begin if Cmd.Config = null or else Cmd.Config.Prefixes = null then return; end if; for P in Cmd.Config.Prefixes'Range loop Group := Ada.Strings.Unbounded.Null_Unbounded_String; First := 0; for C in Result'Range loop if Result (C) /= null and then Compatible_Parameter (Params (C)) and then Looking_At (Result (C).all, Result (C)'First, Cmd.Config.Prefixes (P).all) then -- If we are still in the same section, group the switches if First = 0 or else (Sections (C) = null and then Sections (First) = null) or else (Sections (C) /= null and then Sections (First) /= null and then Sections (C).all = Sections (First).all) then Group := Group & Result (C) (Result (C)'First + Cmd.Config.Prefixes (P)'Length .. Result (C)'Last); if Params (C) /= null then Group := Group & Params (C) (Params (C)'First + 1 .. Params (C)'Last); Free (Params (C)); end if; if First = 0 then First := C; end if; Free (Result (C)); -- We changed section: we put the grouped switches to the first -- place, on continue with the new section. else Result (First) := new String' (Cmd.Config.Prefixes (P).all & Ada.Strings.Unbounded.To_String (Group)); Group := Ada.Strings.Unbounded.To_Unbounded_String (Result (C) (Result (C)'First + Cmd.Config.Prefixes (P)'Length .. Result (C)'Last)); First := C; end if; end if; end loop; if First > 0 then Result (First) := new String' (Cmd.Config.Prefixes (P).all & Ada.Strings.Unbounded.To_String (Group)); end if; end loop; end Group_Switches; -------------------- -- Alias_Switches -- -------------------- procedure Alias_Switches (Cmd : Command_Line; Result : Argument_List_Access; Params : Argument_List_Access) is Found : Boolean; First : Natural; procedure Check_Cb (Switch, Separator, Param : String; Index : Integer); -- Checks whether the command line contains [Switch]. Sets the global -- variable [Found] appropriately. This is called for each simple switch -- that make up an alias, to know whether the alias should be applied. procedure Remove_Cb (Switch, Separator, Param : String; Index : Integer); -- Remove the simple switch [Switch] from the command line, since it is -- part of a simpler alias -------------- -- Check_Cb -- -------------- procedure Check_Cb (Switch, Separator, Param : String; Index : Integer) is pragma Unreferenced (Separator, Index); begin if Found then for E in Result'Range loop if Result (E) /= null and then (Params (E) = null or else Params (E) (Params (E)'First + 1 .. Params (E)'Last) = Param) and then Result (E).all = Switch then return; end if; end loop; Found := False; end if; end Check_Cb; --------------- -- Remove_Cb -- --------------- procedure Remove_Cb (Switch, Separator, Param : String; Index : Integer) is pragma Unreferenced (Separator, Index); begin for E in Result'Range loop if Result (E) /= null and then (Params (E) = null or else Params (E) (Params (E)'First + 1 .. Params (E)'Last) = Param) and then Result (E).all = Switch then if First > E then First := E; end if; Free (Result (E)); Free (Params (E)); return; end if; end loop; end Remove_Cb; procedure Check_All is new For_Each_Simple_Switch (Check_Cb); procedure Remove_All is new For_Each_Simple_Switch (Remove_Cb); -- Start of processing for Alias_Switches begin if Cmd.Config = null or else Cmd.Config.Aliases = null then return; end if; for A in Cmd.Config.Aliases'Range loop -- Compute the various simple switches that make up the alias. We -- split the expansion into as many simple switches as possible, and -- then check whether the expanded command line has all of them. Found := True; Check_All (Cmd.Config, Switch => Cmd.Config.Aliases (A).Expansion.all, Section => Cmd.Config.Aliases (A).Section.all); if Found then First := Integer'Last; Remove_All (Cmd.Config, Switch => Cmd.Config.Aliases (A).Expansion.all, Section => Cmd.Config.Aliases (A).Section.all); Result (First) := new String'(Cmd.Config.Aliases (A).Alias.all); end if; end loop; end Alias_Switches; ------------------- -- Sort_Sections -- ------------------- procedure Sort_Sections (Line : not null GNAT.OS_Lib.Argument_List_Access; Sections : GNAT.OS_Lib.Argument_List_Access; Params : GNAT.OS_Lib.Argument_List_Access) is Sections_List : Argument_List_Access := new Argument_List'(1 .. 1 => null); Found : Boolean; Old_Line : constant Argument_List := Line.all; Old_Sections : constant Argument_List := Sections.all; Old_Params : constant Argument_List := Params.all; Index : Natural; begin -- First construct a list of all sections for E in Line'Range loop if Sections (E) /= null then Found := False; for S in Sections_List'Range loop if (Sections_List (S) = null and then Sections (E) = null) or else (Sections_List (S) /= null and then Sections (E) /= null and then Sections_List (S).all = Sections (E).all) then Found := True; exit; end if; end loop; if not Found then Add (Sections_List, Sections (E)); end if; end if; end loop; Index := Line'First; for S in Sections_List'Range loop for E in Old_Line'Range loop if (Sections_List (S) = null and then Old_Sections (E) = null) or else (Sections_List (S) /= null and then Old_Sections (E) /= null and then Sections_List (S).all = Old_Sections (E).all) then Line (Index) := Old_Line (E); Sections (Index) := Old_Sections (E); Params (Index) := Old_Params (E); Index := Index + 1; end if; end loop; end loop; Unchecked_Free (Sections_List); end Sort_Sections; ----------- -- Start -- ----------- procedure Start (Cmd : in out Command_Line; Iter : in out Command_Line_Iterator; Expanded : Boolean := False) is begin if Cmd.Expanded = null then Iter.List := null; return; end if; -- Reorder the expanded line so that sections are grouped Sort_Sections (Cmd.Expanded, Cmd.Sections, Cmd.Params); -- Coalesce the switches as much as possible if not Expanded and then Cmd.Coalesce = null then Cmd.Coalesce := new Argument_List (Cmd.Expanded'Range); for E in Cmd.Expanded'Range loop Cmd.Coalesce (E) := new String'(Cmd.Expanded (E).all); end loop; Free (Cmd.Coalesce_Sections); Cmd.Coalesce_Sections := new Argument_List (Cmd.Sections'Range); for E in Cmd.Sections'Range loop Cmd.Coalesce_Sections (E) := (if Cmd.Sections (E) = null then null else new String'(Cmd.Sections (E).all)); end loop; Free (Cmd.Coalesce_Params); Cmd.Coalesce_Params := new Argument_List (Cmd.Params'Range); for E in Cmd.Params'Range loop Cmd.Coalesce_Params (E) := (if Cmd.Params (E) = null then null else new String'(Cmd.Params (E).all)); end loop; -- Not a clone, since we will not modify the parameters anyway Alias_Switches (Cmd, Cmd.Coalesce, Cmd.Coalesce_Params); Group_Switches (Cmd, Cmd.Coalesce, Cmd.Coalesce_Sections, Cmd.Coalesce_Params); end if; if Expanded then Iter.List := Cmd.Expanded; Iter.Params := Cmd.Params; Iter.Sections := Cmd.Sections; else Iter.List := Cmd.Coalesce; Iter.Params := Cmd.Coalesce_Params; Iter.Sections := Cmd.Coalesce_Sections; end if; if Iter.List = null then Iter.Current := Integer'Last; else Iter.Current := Iter.List'First - 1; Next (Iter); end if; end Start; -------------------- -- Current_Switch -- -------------------- function Current_Switch (Iter : Command_Line_Iterator) return String is begin return Iter.List (Iter.Current).all; end Current_Switch; -------------------- -- Is_New_Section -- -------------------- function Is_New_Section (Iter : Command_Line_Iterator) return Boolean is Section : constant String := Current_Section (Iter); begin if Iter.Sections = null then return False; elsif Iter.Current = Iter.Sections'First or else Iter.Sections (Iter.Current - 1) = null then return Section /= ""; else return Section /= Iter.Sections (Iter.Current - 1).all; end if; end Is_New_Section; --------------------- -- Current_Section -- --------------------- function Current_Section (Iter : Command_Line_Iterator) return String is begin if Iter.Sections = null or else Iter.Current > Iter.Sections'Last or else Iter.Sections (Iter.Current) = null then return ""; end if; return Iter.Sections (Iter.Current).all; end Current_Section; ----------------------- -- Current_Separator -- ----------------------- function Current_Separator (Iter : Command_Line_Iterator) return String is begin if Iter.Params = null or else Iter.Current > Iter.Params'Last or else Iter.Params (Iter.Current) = null then return ""; else declare Sep : constant Character := Iter.Params (Iter.Current) (Iter.Params (Iter.Current)'First); begin if Sep = ASCII.NUL then return ""; else return "" & Sep; end if; end; end if; end Current_Separator; ----------------------- -- Current_Parameter -- ----------------------- function Current_Parameter (Iter : Command_Line_Iterator) return String is begin if Iter.Params = null or else Iter.Current > Iter.Params'Last or else Iter.Params (Iter.Current) = null then return ""; else -- Return result, skipping separator declare P : constant String := Iter.Params (Iter.Current).all; begin return P (P'First + 1 .. P'Last); end; end if; end Current_Parameter; -------------- -- Has_More -- -------------- function Has_More (Iter : Command_Line_Iterator) return Boolean is begin return Iter.List /= null and then Iter.Current <= Iter.List'Last; end Has_More; ---------- -- Next -- ---------- procedure Next (Iter : in out Command_Line_Iterator) is begin Iter.Current := Iter.Current + 1; while Iter.Current <= Iter.List'Last and then Iter.List (Iter.Current) = null loop Iter.Current := Iter.Current + 1; end loop; end Next; ---------- -- Free -- ---------- procedure Free (Config : in out Command_Line_Configuration) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Switch_Definitions, Switch_Definitions_List); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Alias_Definitions, Alias_Definitions_List); begin if Config /= null then Free (Config.Prefixes); Free (Config.Sections); Free (Config.Usage); Free (Config.Help); Free (Config.Help_Msg); if Config.Aliases /= null then for A in Config.Aliases'Range loop Free (Config.Aliases (A).Alias); Free (Config.Aliases (A).Expansion); Free (Config.Aliases (A).Section); end loop; Unchecked_Free (Config.Aliases); end if; if Config.Switches /= null then for S in Config.Switches'Range loop Free (Config.Switches (S).Switch); Free (Config.Switches (S).Long_Switch); Free (Config.Switches (S).Help); Free (Config.Switches (S).Section); Free (Config.Switches (S).Argument); end loop; Unchecked_Free (Config.Switches); end if; Unchecked_Free (Config); end if; end Free; ---------- -- Free -- ---------- procedure Free (Cmd : in out Command_Line) is begin Free (Cmd.Expanded); Free (Cmd.Coalesce); Free (Cmd.Coalesce_Sections); Free (Cmd.Coalesce_Params); Free (Cmd.Params); Free (Cmd.Sections); end Free; --------------- -- Set_Usage -- --------------- procedure Set_Usage (Config : in out Command_Line_Configuration; Usage : String := "[switches] [arguments]"; Help : String := ""; Help_Msg : String := "") is begin if Config = null then Config := new Command_Line_Configuration_Record; end if; Free (Config.Usage); Free (Config.Help); Free (Config.Help_Msg); Config.Usage := new String'(Usage); Config.Help := new String'(Help); Config.Help_Msg := new String'(Help_Msg); end Set_Usage; ------------------ -- Display_Help -- ------------------ procedure Display_Help (Config : Command_Line_Configuration) is function Switch_Name (Def : Switch_Definition; Section : String) return String; -- Return the "-short, --long=ARG" string for Def. -- Returns "" if the switch is not in the section. function Param_Name (P : Switch_Parameter_Type; Name : String := "ARG") return String; -- Return the display for a switch parameter procedure Display_Section_Help (Section : String); -- Display the help for a specific section ("" is the default section) -------------------------- -- Display_Section_Help -- -------------------------- procedure Display_Section_Help (Section : String) is Max_Len : Natural := 0; begin -- ??? Special display for "*" New_Line; if Section /= "" then Put_Line ("Switches after " & Section); end if; -- Compute size of the switches column for S in Config.Switches'Range loop Max_Len := Natural'Max (Max_Len, Switch_Name (Config.Switches (S), Section)'Length); end loop; if Config.Aliases /= null then for A in Config.Aliases'Range loop if Config.Aliases (A).Section.all = Section then Max_Len := Natural'Max (Max_Len, Config.Aliases (A).Alias'Length); end if; end loop; end if; -- Display the switches for S in Config.Switches'Range loop declare N : constant String := Switch_Name (Config.Switches (S), Section); begin if N /= "" then Put (" "); Put (N); Put ((1 .. Max_Len - N'Length + 1 => ' ')); if Config.Switches (S).Help /= null then Put (Config.Switches (S).Help.all); end if; New_Line; end if; end; end loop; -- Display the aliases if Config.Aliases /= null then for A in Config.Aliases'Range loop if Config.Aliases (A).Section.all = Section then Put (" "); Put (Config.Aliases (A).Alias.all); Put ((1 .. Max_Len - Config.Aliases (A).Alias'Length + 1 => ' ')); Put ("Equivalent to " & Config.Aliases (A).Expansion.all); New_Line; end if; end loop; end if; end Display_Section_Help; ---------------- -- Param_Name -- ---------------- function Param_Name (P : Switch_Parameter_Type; Name : String := "ARG") return String is begin case P is when Parameter_None => return ""; when Parameter_With_Optional_Space => return " " & To_Upper (Name); when Parameter_With_Space_Or_Equal => return "=" & To_Upper (Name); when Parameter_No_Space => return To_Upper (Name); when Parameter_Optional => return '[' & To_Upper (Name) & ']'; end case; end Param_Name; ----------------- -- Switch_Name -- ----------------- function Switch_Name (Def : Switch_Definition; Section : String) return String is use Ada.Strings.Unbounded; Result : Unbounded_String; P1, P2 : Switch_Parameter_Type; Last1, Last2 : Integer := 0; begin if (Section = "" and then Def.Section = null) or else (Def.Section /= null and then Def.Section.all = Section) then if Def.Switch /= null and then Def.Switch.all = "*" then return "[any switch]"; end if; if Def.Switch /= null then Decompose_Switch (Def.Switch.all, P1, Last1); Append (Result, Def.Switch (Def.Switch'First .. Last1)); if Def.Long_Switch /= null then Decompose_Switch (Def.Long_Switch.all, P2, Last2); Append (Result, ", " & Def.Long_Switch (Def.Long_Switch'First .. Last2)); if Def.Argument = null then Append (Result, Param_Name (P2, "ARG")); else Append (Result, Param_Name (P2, Def.Argument.all)); end if; else if Def.Argument = null then Append (Result, Param_Name (P1, "ARG")); else Append (Result, Param_Name (P1, Def.Argument.all)); end if; end if; -- Def.Switch is null (Long_Switch must be non-null) else Decompose_Switch (Def.Long_Switch.all, P2, Last2); Append (Result, Def.Long_Switch (Def.Long_Switch'First .. Last2)); if Def.Argument = null then Append (Result, Param_Name (P2, "ARG")); else Append (Result, Param_Name (P2, Def.Argument.all)); end if; end if; end if; return To_String (Result); end Switch_Name; -- Start of processing for Display_Help begin if Config = null then return; end if; if Config.Help /= null and then Config.Help.all /= "" then Put_Line (Config.Help.all); end if; if Config.Usage /= null then Put_Line ("Usage: " & Base_Name (Ada.Command_Line.Command_Name) & " " & Config.Usage.all); else Put_Line ("Usage: " & Base_Name (Ada.Command_Line.Command_Name) & " [switches] [arguments]"); end if; if Config.Help_Msg /= null and then Config.Help_Msg.all /= "" then Put_Line (Config.Help_Msg.all); else Display_Section_Help (""); if Config.Sections /= null and then Config.Switches /= null then for S in Config.Sections'Range loop Display_Section_Help (Config.Sections (S).all); end loop; end if; end if; end Display_Help; ------------ -- Getopt -- ------------ procedure Getopt (Config : Command_Line_Configuration; Callback : Switch_Handler := null; Parser : Opt_Parser := Command_Line_Parser; Concatenate : Boolean := True; Quiet : Boolean := False) is Local_Config : Command_Line_Configuration := Config; Getopt_Switches : String_Access; C : Character := ASCII.NUL; Empty_Name : aliased constant String := ""; Current_Section : Integer := -1; Section_Name : not null access constant String := Empty_Name'Access; procedure Simple_Callback (Simple_Switch : String; Separator : String; Parameter : String; Index : Integer); -- Needs comments ??? procedure Do_Callback (Switch, Parameter : String; Index : Integer); ----------------- -- Do_Callback -- ----------------- procedure Do_Callback (Switch, Parameter : String; Index : Integer) is begin -- Do automatic handling when possible if Index /= -1 then case Local_Config.Switches (Index).Typ is when Switch_Untyped => null; -- no automatic handling when Switch_Boolean => Local_Config.Switches (Index).Boolean_Output.all := Local_Config.Switches (Index).Boolean_Value; return; when Switch_Integer => begin if Parameter = "" then Local_Config.Switches (Index).Integer_Output.all := Local_Config.Switches (Index).Integer_Default; else Local_Config.Switches (Index).Integer_Output.all := Integer'Value (Parameter); end if; exception when Constraint_Error => raise Invalid_Parameter with "Expected integer parameter for '" & Switch & "'"; end; return; when Switch_String => Free (Local_Config.Switches (Index).String_Output.all); Local_Config.Switches (Index).String_Output.all := new String'(Parameter); return; when Switch_Callback => Local_Config.Switches (Index).Callback (Switch, Parameter); return; end case; end if; -- Otherwise calls the user callback if one was defined if Callback /= null then Callback (Switch => Switch, Parameter => Parameter, Section => Section_Name.all); end if; end Do_Callback; procedure For_Each_Simple is new For_Each_Simple_Switch (Simple_Callback); --------------------- -- Simple_Callback -- --------------------- procedure Simple_Callback (Simple_Switch : String; Separator : String; Parameter : String; Index : Integer) is pragma Unreferenced (Separator); begin Do_Callback (Switch => Simple_Switch, Parameter => Parameter, Index => Index); end Simple_Callback; -- Start of processing for Getopt begin -- We work with a local copy of Config, because Config can be null, for -- example if Define_Switch was never called. We could modify Config -- itself, but then we would have to make it into an 'in out' parameter, -- which would be incompatible. if Local_Config = null then Local_Config := new Command_Line_Configuration_Record; end if; if Local_Config.Switches = null then Local_Config.Switches := new Switch_Definitions (1 .. 0); end if; -- Initialize sections if Local_Config.Sections = null then Local_Config.Sections := new Argument_List'(1 .. 0 => null); end if; Internal_Initialize_Option_Scan (Parser => Parser, Switch_Char => Parser.Switch_Character, Stop_At_First_Non_Switch => Parser.Stop_At_First, Section_Delimiters => Section_Delimiters (Local_Config)); Getopt_Switches := new String' (Get_Switches (Local_Config, Parser.Switch_Character, Section_Name.all) & " h -help"); -- Initialize output values for automatically handled switches for S in Local_Config.Switches'Range loop case Local_Config.Switches (S).Typ is when Switch_Untyped | Switch_Callback => null; -- Nothing to do when Switch_Boolean => Local_Config.Switches (S).Boolean_Output.all := not Local_Config.Switches (S).Boolean_Value; when Switch_Integer => Local_Config.Switches (S).Integer_Output.all := Local_Config.Switches (S).Integer_Initial; when Switch_String => if Local_Config.Switches (S).String_Output.all = null then Local_Config.Switches (S).String_Output.all := new String'(""); end if; end case; end loop; -- For all sections, and all switches within those sections loop C := Getopt (Switches => Getopt_Switches.all, Concatenate => Concatenate, Parser => Parser); if C = '*' then -- Full_Switch already includes the leading '-' Do_Callback (Switch => Full_Switch (Parser), Parameter => Parameter (Parser), Index => -1); elsif C /= ASCII.NUL then if Full_Switch (Parser) = "h" or else Full_Switch (Parser) = "-help" then Display_Help (Local_Config); raise Exit_From_Command_Line; end if; -- Do switch expansion if needed For_Each_Simple (Local_Config, Section => Section_Name.all, Switch => Parser.Switch_Character & Full_Switch (Parser), Parameter => Parameter (Parser)); else if Current_Section = -1 then Current_Section := Local_Config.Sections'First; else Current_Section := Current_Section + 1; end if; exit when Current_Section > Local_Config.Sections'Last; Section_Name := Local_Config.Sections (Current_Section); Goto_Section (Section_Name.all, Parser); Free (Getopt_Switches); Getopt_Switches := new String' (Get_Switches (Local_Config, Parser.Switch_Character, Section_Name.all)); end if; end loop; Free (Getopt_Switches); exception when Invalid_Switch => Free (Getopt_Switches); -- Message inspired by "ls" on Unix if not Quiet then Put_Line (Standard_Error, Base_Name (Ada.Command_Line.Command_Name) & ": unrecognized option '" & Full_Switch (Parser) & "'"); Try_Help; end if; raise; when others => Free (Getopt_Switches); raise; end Getopt; ----------- -- Build -- ----------- procedure Build (Line : in out Command_Line; Args : out GNAT.OS_Lib.Argument_List_Access; Expanded : Boolean := False; Switch_Char : Character := '-') is Iter : Command_Line_Iterator; Count : Natural := 0; begin Start (Line, Iter, Expanded => Expanded); while Has_More (Iter) loop if Is_New_Section (Iter) then Count := Count + 1; end if; Count := Count + 1; Next (Iter); end loop; Args := new Argument_List (1 .. Count); Count := Args'First; Start (Line, Iter, Expanded => Expanded); while Has_More (Iter) loop if Is_New_Section (Iter) then Args (Count) := new String'(Switch_Char & Current_Section (Iter)); Count := Count + 1; end if; Args (Count) := new String'(Current_Switch (Iter) & Current_Separator (Iter) & Current_Parameter (Iter)); Count := Count + 1; Next (Iter); end loop; end Build; -------------- -- Try_Help -- -------------- -- Note: Any change to the message displayed should also be done in -- gnatbind.adb that does not use this interface. procedure Try_Help is begin Put_Line (Standard_Error, "try """ & Base_Name (Ada.Command_Line.Command_Name, Suffix => ".exe") & " --help"" for more information."); end Try_Help; end CLIC.Command_Line; alire-1.2.1/deps/clic/src/clic-command_line.ads000066400000000000000000001511761424570375700213220ustar00rootroot00000000000000-- This package is imported from GNAT FSF 11.2 source to have a common -- implementation of Command_Line parsing across any version of GNAT. ------------------------------------------------------------------------------ -- -- -- GNAT COMPILER COMPONENTS -- -- -- -- G N A T . C O M M A N D _ L I N E -- -- -- -- S p e c -- -- -- -- Copyright (C) 1999-2020, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 3, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- High level package for command line parsing and manipulation ---------------------------------------- -- Simple Parsing of the Command Line -- ---------------------------------------- -- This package provides an interface for parsing command line arguments, -- when they are either read from Ada.Command_Line or read from a string list. -- As shown in the example below, one should first retrieve the switches -- (special command line arguments starting with '-' by default) and their -- parameters, and then the rest of the command line arguments. -- -- While it may appear easy to parse the command line arguments with -- Ada.Command_Line, there are in fact lots of special cases to handle in some -- applications. Those are fully managed by GNAT.Command_Line. Among these are -- switches with optional parameters, grouping switches (for instance "-ab" -- might mean the same as "-a -b"), various characters to separate a switch -- and its parameter (or none: "-a 1" and "-a1" are generally the same, which -- can introduce confusion with grouped switches),... -- -- begin -- loop -- case Getopt ("a b: ad") is -- Accepts '-a', '-ad', or '-b argument' -- when ASCII.NUL => exit; -- when 'a' => -- if Full_Switch = "a" then -- Put_Line ("Got a"); -- else -- Put_Line ("Got ad"); -- end if; -- when 'b' => Put_Line ("Got b + " & Parameter); -- when others => -- raise Program_Error; -- cannot occur -- end case; -- end loop; -- loop -- declare -- S : constant String := Get_Argument (Do_Expansion => True); -- begin -- exit when S'Length = 0; -- Put_Line ("Got " & S); -- end; -- end loop; -- exception -- when Invalid_Switch => Put_Line ("Invalid Switch " & Full_Switch); -- when Invalid_Parameter => Put_Line ("No parameter for " & Full_Switch); -- end; -------------- -- Sections -- -------------- -- A more complicated example would involve the use of sections for the -- switches, as for instance in gnatmake. The same command line is used to -- provide switches for several tools. Each tool recognizes its switches by -- separating them with special switches that act as section separators. -- Each section acts as a command line of its own. -- begin -- Initialize_Option_Scan ('-', False, "largs bargs cargs"); -- loop -- -- Same loop as above to get switches and arguments -- end loop; -- Goto_Section ("bargs"); -- loop -- -- Same loop as above to get switches and arguments -- -- The supported switches in Getopt might be different -- end loop; -- Goto_Section ("cargs"); -- loop -- -- Same loop as above to get switches and arguments -- -- The supported switches in Getopt might be different -- end loop; -- end; ------------------------------- -- Parsing a List of Strings -- ------------------------------- -- The examples above show how to parse the command line when the arguments -- are read directly from Ada.Command_Line. However, these arguments can also -- be read from a list of strings. This can be useful in several contexts, -- either because your system does not support Ada.Command_Line, or because -- you are manipulating other tools and creating their command lines by hand, -- or for any other reason. -- To create the list of strings, it is recommended to use -- GNAT.OS_Lib.Argument_String_To_List. -- The example below shows how to get the parameters from such a list. Note -- also the use of '*' to get all the switches, and not report errors when an -- unexpected switch was used by the user -- declare -- Parser : Opt_Parser; -- Args : constant Argument_List_Access := -- GNAT.OS_Lib.Argument_String_To_List ("-g -O1 -Ipath"); -- begin -- Initialize_Option_Scan (Parser, Args); -- while Getopt ("* g O! I=", Parser) /= ASCII.NUL loop -- Put_Line ("Switch " & Full_Switch (Parser) -- & " param=" & Parameter (Parser)); -- end loop; -- Free (Parser); -- end; ------------------------------------------- -- High-Level Command Line Configuration -- ------------------------------------------- -- As shown above, the code is still relatively low-level. For instance, there -- is no way to indicate which switches are related (thus if "-l" and "--long" -- should have the same effect, your code will need to test for both cases). -- Likewise, it is difficult to handle more advanced constructs, like: -- * Specifying -gnatwa is the same as specifying -gnatwu -gnatwv, but -- shorter and more readable -- * All switches starting with -gnatw can be grouped, for instance one -- can write -gnatwcd instead of -gnatwc -gnatwd. -- Of course, this can be combined with the above and -gnatwacd is the -- same as -gnatwc -gnatwd -gnatwu -gnatwv -- * The switch -T is the same as -gnatwAB (same as -gnatwA -gnatwB) -- With the above form of Getopt, you would receive "-gnatwa", "-T" or -- "-gnatwcd" in the examples above, and thus you require additional manual -- parsing of the switch. -- Instead, this package provides the type Command_Line_Configuration, which -- stores all the knowledge above. For instance: -- Config : Command_Line_Configuration; -- Define_Alias (Config, "-gnatwa", "-gnatwu -gnatwv"); -- Define_Prefix (Config, "-gnatw"); -- Define_Alias (Config, "-T", "-gnatwAB"); -- You then need to specify all possible switches in your application by -- calling Define_Switch, for instance: -- Define_Switch (Config, "-gnatwu", Help => "warn on unused entities"); -- Define_Switch (Config, "-gnatwv", Help => "warn on unassigned var"); -- ... -- Specifying the help message is optional, but makes it easy to then call -- the function: -- Display_Help (Config); -- that will display a properly formatted help message for your application, -- listing all possible switches. That way you have a single place in which -- to maintain the list of switches and their meaning, rather than maintaining -- both the string to pass to Getopt and a subprogram to display the help. -- Both will properly stay synchronized. -- Once you have this Config, you just have to call: -- Getopt (Config, Callback'Access); -- to parse the command line. The Callback will be called for each switch -- found on the command line (in the case of our example, that is "-gnatwu" -- and then "-gnatwv", not "-gnatwa" itself). This simplifies command line -- parsing a lot. -- In fact, this can be further automated for the most command case where the -- parameter passed to a switch is stored in a variable in the application. -- When a switch is defined, you only have to indicate where to store the -- value, and let Getopt do the rest. For instance: -- Optimization : aliased Integer; -- Verbose : aliased Boolean; -- Define_Switch (Config, Verbose'Access, -- "-v", Long_Switch => "--verbose", -- Help => "Output extra verbose information"); -- Define_Switch (Config, Optimization'Access, -- "-O?", Help => "Optimization level"); -- Getopt (Config); -- No callback -- Since all switches are handled automatically, we don't even need to pass -- a callback to Getopt. Once getopt has been called, the two variables -- Optimization and Verbose have been properly initialized, either to the -- default value or to the value found on the command line. ------------------------------------------------ -- Creating and Manipulating the Command Line -- ------------------------------------------------ -- This package provides mechanisms to create and modify command lines by -- adding or removing arguments from them. The resulting command line is kept -- as short as possible by coalescing arguments whenever possible. -- Complex command lines can thus be constructed, for example from a GUI -- (although this package does not by itself depend upon any specific GUI -- toolkit). -- Using the configuration defined earlier, one can then construct a command -- line for the tool with: -- Cmd : Command_Line; -- Set_Configuration (Cmd, Config); -- Config created earlier -- Add_Switch (Cmd, "-bar"); -- Add_Switch (Cmd, "-gnatwu"); -- Add_Switch (Cmd, "-gnatwv"); -- will be grouped with the above -- Add_Switch (Cmd, "-T"); -- The resulting command line can be iterated over to get all its switches, -- There are two modes for this iteration: either you want to get the -- shortest possible command line, which would be: -- -bar -gnatwaAB -- or on the other hand you want each individual switch (so that your own -- tool does not have to do further complex processing), which would be: -- -bar -gnatwu -gnatwv -gnatwA -gnatwB -- Of course, we can assume that the tool you want to spawn would understand -- both of these, since they are both compatible with the description we gave -- above. However, the first result is useful if you want to show the user -- what you are spawning (since that keeps the output shorter), and the second -- output is more useful for a tool that would check whether -gnatwu was -- passed (which isn't obvious in the first output). Likewise, the second -- output is more useful if you have a graphical interface since each switch -- can be associated with a widget, and you immediately know whether -gnatwu -- was selected. -- -- Some command line arguments can have parameters, which on a command line -- appear as a separate argument that must immediately follow the switch. -- Since the subprograms in this package will reorganize the switches to group -- them, you need to indicate what is a command line parameter, and what is a -- switch argument. -- This is done by passing an extra argument to Add_Switch, as in: -- Add_Switch (Cmd, "-foo", Parameter => "arg1"); -- This ensures that "arg1" will always be treated as the argument to -foo, -- and will not be grouped with other parts of the command line. with Ada.Command_Line; with GNAT.Directory_Operations; with GNAT.OS_Lib; with GNAT.Regexp; with GNAT.Strings; package CLIC.Command_Line is ------------- -- Parsing -- ------------- type Opt_Parser is private; Command_Line_Parser : constant Opt_Parser; -- This object is responsible for parsing a list of arguments, which by -- default are the standard command line arguments from Ada.Command_Line. -- This is really a pointer to actual data, which must therefore be -- initialized through a call to Initialize_Option_Scan, and must be freed -- with a call to Free. -- -- As a special case, Command_Line_Parser does not need to be either -- initialized or free-ed. procedure Initialize_Option_Scan (Switch_Char : Character := '-'; Stop_At_First_Non_Switch : Boolean := False; Section_Delimiters : String := ""); procedure Initialize_Option_Scan (Parser : out Opt_Parser; Command_Line : GNAT.OS_Lib.Argument_List_Access; Switch_Char : Character := '-'; Stop_At_First_Non_Switch : Boolean := False; Section_Delimiters : String := ""); -- The first procedure resets the internal state of the package to prepare -- to rescan the parameters. It does not need to be called before the -- first use of Getopt (but it could be), but it must be called if you -- want to start rescanning the command line parameters from the start. -- The optional parameter Switch_Char can be used to reset the switch -- character, e.g. to '/' for use in DOS-like systems. -- -- The second subprogram initializes a parser that takes its arguments -- from an array of strings rather than directly from the command line. In -- this case, the parser is responsible for freeing the strings stored in -- Command_Line. If you pass null to Command_Line, this will in fact create -- a second parser for Ada.Command_Line, which doesn't share any data with -- the default parser. This parser must be free'ed. -- -- The optional parameter Stop_At_First_Non_Switch indicates if Getopt is -- to look for switches on the whole command line, or if it has to stop as -- soon as a non-switch argument is found. -- -- Example: -- -- Arguments: my_application file1 -c -- -- If Stop_At_First_Non_Switch is False, then -c will be considered -- as a switch (returned by getopt), otherwise it will be considered -- as a normal argument (returned by Get_Argument). -- -- If Section_Delimiters is set, then every following subprogram -- (Getopt and Get_Argument) will only operate within a section, which -- is delimited by any of these delimiters or the end of the command line. -- -- Example: -- Initialize_Option_Scan (Section_Delimiters => "largs bargs cargs"); -- -- Arguments on command line : my_application -c -bargs -d -e -largs -f -- This line contains three sections, the first one is the default one -- and includes only the '-c' switch, the second one is between -bargs -- and -largs and includes '-d -e' and the last one includes '-f'. procedure Free (Parser : in out Opt_Parser); -- Free the memory used by the parser. Calling this is not mandatory for -- the Command_Line_Parser procedure Goto_Section (Name : String := ""; Parser : Opt_Parser := Command_Line_Parser); -- Change the current section. The next Getopt or Get_Argument will start -- looking at the beginning of the section. An empty name ("") refers to -- the first section between the program name and the first section -- delimiter. If the section does not exist in Section_Delimiters, then -- Invalid_Section is raised. If the section does not appear on the command -- line, then it is treated as an empty section. function Full_Switch (Parser : Opt_Parser := Command_Line_Parser) return String; -- Returns the full name of the last switch found (Getopt only returns the -- first character). Does not include the Switch_Char ('-' by default), -- unless the "*" option of Getopt is used (see below). function Current_Section (Parser : Opt_Parser := Command_Line_Parser) return String; -- Return the name of the current section. -- The list of valid sections is defined through Initialize_Option_Scan function Getopt (Switches : String; Concatenate : Boolean := True; Parser : Opt_Parser := Command_Line_Parser) return Character; -- This function moves to the next switch on the command line (defined as -- switch character followed by a character within Switches, casing being -- significant). The result returned is the first character of the switch -- that is located. If there are no more switches in the current section, -- returns ASCII.NUL. If Concatenate is True (the default), the switches do -- not need to be separated by spaces (they can be concatenated if they do -- not require an argument, e.g. -ab is the same as two separate arguments -- -a -b). -- -- Switches is a string of all the possible switches, separated by -- spaces. A switch can be followed by one of the following characters: -- -- ':' The switch requires a parameter. There can optionally be a space -- on the command line between the switch and its parameter. -- -- '=' The switch requires a parameter. There can either be a '=' or a -- space on the command line between the switch and its parameter. -- -- '!' The switch requires a parameter, but there can be no space on the -- command line between the switch and its parameter. -- -- '?' The switch may have an optional parameter. There can be no space -- between the switch and its argument. -- -- e.g. if Switches has the following value : "a? b", -- The command line can be: -- -- -afoo : -a switch with 'foo' parameter -- -a foo : -a switch and another element on the -- command line 'foo', returned by Get_Argument -- -- Example: if Switches is "-a: -aO:", you can have the following -- command lines: -- -- -aarg : 'a' switch with 'arg' parameter -- -a arg : 'a' switch with 'arg' parameter -- -aOarg : 'aO' switch with 'arg' parameter -- -aO arg : 'aO' switch with 'arg' parameter -- -- Example: -- -- Getopt ("a b: ac ad?") -- -- accept either 'a' or 'ac' with no argument, -- accept 'b' with a required argument -- accept 'ad' with an optional argument -- -- If the first item in switches is '*', then Getopt will catch -- every element on the command line that was not caught by any other -- switch. The character returned by GetOpt is '*', but Full_Switch -- contains the full command line argument, including leading '-' if there -- is one. If this character was not returned, there would be no way of -- knowing whether it is there or not. -- -- Example -- Getopt ("* a b") -- If the command line is '-a -c toto.o -b', Getopt will return -- successively 'a', '*', '*' and 'b', with Full_Switch returning -- "a", "-c", "toto.o", and "b". -- -- When Getopt encounters an invalid switch, it raises the exception -- Invalid_Switch and sets Full_Switch to return the invalid switch. -- When Getopt cannot find the parameter associated with a switch, it -- raises Invalid_Parameter, and sets Full_Switch to return the invalid -- switch. -- -- Note: in case of ambiguity, e.g. switches a ab abc, then the longest -- matching switch is returned. -- -- Arbitrary characters are allowed for switches, although it is -- strongly recommended to use only letters and digits for portability -- reasons. -- -- When Concatenate is False, individual switches need to be separated by -- spaces. -- -- Example -- Getopt ("a b", Concatenate => False) -- If the command line is '-ab', exception Invalid_Switch will be -- raised and Full_Switch will return "ab". function Get_Argument (Do_Expansion : Boolean := False; Parser : Opt_Parser := Command_Line_Parser) return String; -- Returns the next element on the command line that is not a switch. This -- function should be called either after Getopt has returned ASCII.NUL or -- after Getopt procedure call. -- -- If Do_Expansion is True, then the parameter on the command line will -- be considered as a filename with wildcards, and will be expanded. The -- matching file names will be returned one at a time. This is useful in -- non-Unix systems for obtaining normal expansion of wildcard references. -- When there are no more arguments on the command line, this function -- returns an empty string. function Get_Argument (Do_Expansion : Boolean := False; Parser : Opt_Parser := Command_Line_Parser; End_Of_Arguments : out Boolean) return String; -- The same as above but able to distinguish empty element in argument list -- from end of arguments. -- End_Of_Arguments is True if the end of the command line has been reached -- (i.e. all available arguments have been returned by previous calls to -- Get_Argument). function Parameter (Parser : Opt_Parser := Command_Line_Parser) return String; -- Returns parameter associated with the last switch returned by Getopt. -- If no parameter was associated with the last switch, or no previous call -- has been made to Get_Argument, raises Invalid_Parameter. If the last -- switch was associated with an optional argument and this argument was -- not found on the command line, Parameter returns an empty string. function Separator (Parser : Opt_Parser := Command_Line_Parser) return Character; -- The separator that was between the switch and its parameter. This is -- useful if you want to know exactly what was on the command line. This -- is in general a single character, set to ASCII.NUL if the switch and -- the parameter were concatenated. A space is returned if the switch and -- its argument were in two separate arguments. Invalid_Section : exception; -- Raised when an invalid section is selected by Goto_Section Invalid_Switch : exception; -- Raised when an invalid switch is detected in the command line Invalid_Parameter : exception; -- Raised when a parameter is missing, or an attempt is made to obtain a -- parameter for a switch that does not allow a parameter. ----------------------------------------- -- Expansion of command line arguments -- ----------------------------------------- -- These subprograms take care of expanding globbing patterns on the -- command line. On Unix, such expansion is done by the shell before your -- application is called. But on Windows you must do this expansion -- yourself. type Expansion_Iterator is limited private; -- Type used during expansion of file names procedure Start_Expansion (Iterator : out Expansion_Iterator; Pattern : String; Directory : String := ""; Basic_Regexp : Boolean := True); -- Initialize a wildcard expansion. The next calls to Expansion will -- return the next file name in Directory which match Pattern (Pattern -- is a regular expression, using only the Unix shell and DOS syntax if -- Basic_Regexp is True). When Directory is an empty string, the current -- directory is searched. -- -- Pattern may contain directory separators (as in "src/*/*.ada"). -- Subdirectories of Directory will also be searched, up to one -- hundred levels deep. -- -- When Start_Expansion has been called, function Expansion should -- be called repeatedly until it returns an empty string, before -- Start_Expansion can be called again with the same Expansion_Iterator -- variable. function Expansion (Iterator : Expansion_Iterator) return String; -- Returns the next file in the directory matching the parameters given -- to Start_Expansion and updates Iterator to point to the next entry. -- Returns an empty string when there are no more files. -- -- If Expansion is called again after an empty string has been returned, -- then the exception GNAT.Directory_Operations.Directory_Error is raised. ----------------- -- Configuring -- ----------------- -- The following subprograms are used to manipulate a command line -- represented as a string (for instance "-g -O2"), as well as parsing -- the switches from such a string. They provide high-level configurations -- to define aliases (a switch is equivalent to one or more other switches) -- or grouping of switches ("-gnatyac" is equivalent to "-gnatya" and -- "-gnatyc"). -- See the top of this file for examples on how to use these subprograms type Command_Line_Configuration is private; procedure Define_Section (Config : in out Command_Line_Configuration; Section : String); -- Indicates a new switch section. All switches belonging to the same -- section are ordered together, preceded by the section. They are placed -- at the end of the command line (as in "gnatmake somefile.adb -cargs -g") -- -- The section name should not include the leading '-'. So for instance in -- the case of gnatmake we would use: -- -- Define_Section (Config, "cargs"); -- Define_Section (Config, "bargs"); procedure Define_Alias (Config : in out Command_Line_Configuration; Switch : String; Expanded : String; Section : String := ""); -- Indicates that whenever Switch appears on the command line, it should -- be expanded as Expanded. For instance, for the GNAT compiler switches, -- we would define "-gnatwa" as an alias for "-gnatwcfijkmopruvz", ie some -- default warnings to be activated. -- -- This expansion is only done within the specified section, which must -- have been defined first through a call to [Define_Section]. procedure Define_Prefix (Config : in out Command_Line_Configuration; Prefix : String); -- Indicates that all switches starting with the given prefix should be -- grouped. For instance, for the GNAT compiler we would define "-gnatw" as -- a prefix, so that "-gnatwu -gnatwv" can be grouped into "-gnatwuv" It is -- assumed that the remainder of the switch ("uv") is a set of characters -- whose order is irrelevant. In fact, this package will sort them -- alphabetically. -- -- When grouping switches that accept arguments (for instance "-gnatyL!" -- as the definition, and "-gnatyaL12b" as the command line), only -- numerical arguments are accepted. The above is equivalent to -- "-gnatya -gnatyL12 -gnatyb". procedure Define_Switch (Config : in out Command_Line_Configuration; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG"); -- Indicates a new switch. The format of this switch follows the getopt -- format (trailing ':', '?', etc for defining a switch with parameters). -- -- Switch should also start with the leading '-' (or any other characters). -- If this character is not '-', you need to call Initialize_Option_Scan to -- set the proper character for the parser. -- -- The switches defined in the command_line_configuration object are used -- when ungrouping switches with more that one character after the prefix. -- -- Switch and Long_Switch (when specified) are aliases and can be used -- interchangeably. There is no check that they both take an argument or -- both take no argument. Switch can be set to "*" to indicate that any -- switch is supported (in which case Getopt will return '*', see its -- documentation). -- -- Help is used by the Display_Help procedure to describe the supported -- switches. -- -- In_Section indicates in which section the switch is valid (you need to -- first define the section through a call to Define_Section). -- -- Argument is the name of the argument, as displayed in the automatic -- help message. It is always capitalized for consistency. procedure Define_Switch (Config : in out Command_Line_Configuration; Output : access Boolean; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Value : Boolean := True); -- See Define_Switch for a description of the parameters. -- When the switch is found on the command line, Getopt will set -- Output.all to Value. -- -- Output is always initially set to "not Value", so that if the switch is -- not found on the command line, Output still has a valid value. -- The switch must not take any parameter. -- -- Output must exist at least as long as Config, otherwise an erroneous -- memory access may occur. procedure Define_Switch (Config : in out Command_Line_Configuration; Output : access Integer; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Initial : Integer := 0; Default : Integer := 1; Argument : String := "ARG"); -- See Define_Switch for a description of the parameters. When the -- switch is found on the command line, Getopt will set Output.all to the -- value of the switch's parameter. If the parameter is not an integer, -- Invalid_Parameter is raised. -- Output is always initialized to Initial. If the switch has an optional -- argument which isn't specified by the user, then Output will be set to -- Default. The switch must accept an argument. procedure Define_Switch (Config : in out Command_Line_Configuration; Output : access GNAT.Strings.String_Access; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG"); -- Set Output to the value of the switch's parameter when the switch is -- found on the command line. Output is always initialized to the empty -- string if it does not have a value already (otherwise it is left as is -- so that you can specify the default value directly in the declaration -- of the variable). The switch must accept an argument. type Value_Callback is access procedure (Switch, Value : String); procedure Define_Switch (Config : in out Command_Line_Configuration; Callback : not null Value_Callback; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG"); -- Call Callback for each instance of Switch. The callback is given the -- actual switch and the corresponding value. The switch must accept -- an argument. procedure Set_Usage (Config : in out Command_Line_Configuration; Usage : String := "[switches] [arguments]"; Help : String := ""; Help_Msg : String := ""); -- Defines the general format of the call to the application, and a short -- help text. These are both displayed by Display_Help. When a non-empty -- Help_Msg is given, it is used by Display_Help instead of the -- automatically generated list of supported switches. procedure Display_Help (Config : Command_Line_Configuration); -- Display the help for the tool (i.e. its usage, and its supported -- switches). function Get_Switches (Config : Command_Line_Configuration; Switch_Char : Character := '-'; Section : String := "") return String; -- Get the switches list as expected by Getopt, for a specific section of -- the command line. This list is built using all switches defined -- previously via Define_Switch above. function Section_Delimiters (Config : Command_Line_Configuration) return String; -- Return a string suitable for use in Initialize_Option_Scan procedure Free (Config : in out Command_Line_Configuration); -- Free the memory used by Config type Switch_Handler is access procedure (Switch : String; Parameter : String; Section : String); -- Called when a switch is found on the command line. Switch includes -- any leading '-' that was specified in Define_Switch. This is slightly -- different from the functional version of Getopt above, for which -- Full_Switch omits the first leading '-'. Exit_From_Command_Line : exception; -- Raised when the program should exit because Getopt below has seen -- a -h or --help switch. procedure Getopt (Config : Command_Line_Configuration; Callback : Switch_Handler := null; Parser : Opt_Parser := Command_Line_Parser; Concatenate : Boolean := True; Quiet : Boolean := False); -- Similar to the standard Getopt function. For each switch found on the -- command line, this calls Callback, if the switch is not handled -- automatically. -- -- The list of valid switches are the ones from the configuration. The -- switches that were declared through Define_Switch with an Output -- parameter are never returned (and result in a modification of the Output -- variable). This function will in fact never call [Callback] if all -- switches were handled automatically and there is nothing left to do. -- -- The option Concatenate is identical to the one of the standard Getopt -- function. -- -- This procedure automatically adds -h and --help to the valid switches, -- to display the help message and raises Exit_From_Command_Line. -- If an invalid switch is specified on the command line, this procedure -- will display an error message and raises Invalid_Switch again. -- If the Quiet parameter is True then the error message is not displayed. -- -- This function automatically expands switches: -- -- If Define_Prefix was called (for instance "-gnaty") and the user -- specifies "-gnatycb" on the command line, then Getopt returns -- "-gnatyc" and "-gnatyb" separately. -- -- If Define_Alias was called (for instance "-gnatya = -gnatycb") then -- the latter is returned (in this case it also expands -gnaty as per -- the above. -- -- The goal is to make handling as easy as possible by leaving as much -- work as possible to this package. -- -- As opposed to the standard Getopt, this one will analyze all sections -- as defined by Define_Section, and automatically jump from one section to -- the next. ------------------------------ -- Generating command lines -- ------------------------------ -- Once the command line configuration has been created, you can build your -- own command line. This will be done in general because you need to spawn -- external tools from your application. -- Although it could be done by concatenating strings, the following -- subprograms will properly take care of grouping switches when possible, -- so as to keep the command line as short as possible. They also provide a -- way to remove a switch from an existing command line. -- For instance: -- declare -- Config : Command_Line_Configuration; -- Line : Command_Line; -- Args : Argument_List_Access; -- begin -- Define_Switch (Config, "-gnatyc"); -- Define_Switch (Config, ...); -- for all valid switches -- Define_Prefix (Config, "-gnaty"); -- Set_Configuration (Line, Config); -- Add_Switch (Line, "-O2"); -- Add_Switch (Line, "-gnatyc"); -- Add_Switch (Line, "-gnatyd"); -- -- Build (Line, Args); -- -- Args is now ["-O2", "-gnatycd"] -- end; type Command_Line is private; procedure Set_Configuration (Cmd : in out Command_Line; Config : Command_Line_Configuration); function Get_Configuration (Cmd : Command_Line) return Command_Line_Configuration; -- Set or retrieve the configuration used for that command line. The Config -- must have been initialized first, by calling one of the Define_Switches -- subprograms. procedure Set_Command_Line (Cmd : in out Command_Line; Switches : String; Getopt_Description : String := ""; Switch_Char : Character := '-'); -- Set the new content of the command line, by replacing the current -- version with Switches. -- -- The parsing of Switches is done through calls to Getopt, by passing -- Getopt_Description as an argument. (A "*" is automatically prepended so -- that all switches and command line arguments are accepted). If a config -- was defined via Set_Configuration, the Getopt_Description parameter will -- be ignored. -- -- To properly handle switches that take parameters, you should document -- them in Getopt_Description. Otherwise, the switch and its parameter will -- be recorded as two separate command line arguments as returned by a -- Command_Line_Iterator (which might be fine depending on your -- application). -- -- If the command line has sections (such as -bargs -cargs), then they -- should be listed in the Sections parameter (as "-bargs -cargs"). -- -- This function can be used to reset Cmd by passing an empty string -- -- If an invalid switch is found on the command line (i.e. wasn't defined -- in the configuration via Define_Switch), and the configuration wasn't -- set to accept all switches (by defining "*" as a valid switch), then an -- exception Invalid_Switch is raised. The exception message indicates the -- invalid switch. procedure Add_Switch (Cmd : in out Command_Line; Switch : String; Parameter : String := ""; Separator : Character := ASCII.NUL; Section : String := ""; Add_Before : Boolean := False); -- Add a new switch to the command line, and combine/group it with existing -- switches if possible. Nothing is done if the switch already exists with -- the same parameter. -- -- If the Switch takes a parameter, the latter should be specified -- separately, so that the association between the two is always correctly -- recognized even if the order of switches on the command line changes. -- For instance, you should pass "--check=full" as ("--check", "full") so -- that Remove_Switch below can simply take "--check" in parameter. That -- will automatically remove "full" as well. The value of the parameter is -- never modified by this package. -- -- On the other hand, you could decide to simply pass "--check=full" as -- the Switch above, and then pass no parameter. This means that you need -- to pass "--check=full" to Remove_Switch as well. -- -- A Switch with a parameter will never be grouped with another switch to -- avoid ambiguities as to what the parameter applies to. -- -- If the switch is part of a section, then it should be specified so that -- the switch is correctly placed in the command line, and the section -- added if not already present. For example, to add the -g switch into the -- -cargs section, you need to call (Cmd, "-g", Section => "-cargs"). -- -- [Separator], if specified, overrides the separator that was defined -- through Define_Switch. For instance, if the switch was defined as -- "-from:", the separator defaults to a space. But if your application -- uses unusual separators not supported by GNAT.Command_Line (for instance -- it requires ":"), you can specify this separator here. -- -- For instance, -- Add_Switch(Cmd, "-from", "bar", ':') -- -- results in -- -from:bar -- -- rather than the default -- -from bar -- -- Note however that Getopt doesn't know how to handle ":" as a separator. -- So the recommendation is to declare the switch as "-from!" (i.e. no -- space between the switch and its parameter). Then Getopt will return -- ":bar" as the parameter, and you can trim the ":" in your application. -- -- Invalid_Section is raised if Section was not defined in the -- configuration of the command line. -- -- Add_Before allows insertion of the switch at the beginning of the -- command line. procedure Add_Switch (Cmd : in out Command_Line; Switch : String; Parameter : String := ""; Separator : Character := ASCII.NUL; Section : String := ""; Add_Before : Boolean := False; Success : out Boolean); -- Same as above, returning the status of the operation procedure Remove_Switch (Cmd : in out Command_Line; Switch : String; Remove_All : Boolean := False; Has_Parameter : Boolean := False; Section : String := ""); -- Remove Switch from the command line, and ungroup existing switches if -- necessary. -- -- The actual parameter to the switches are ignored. If for instance -- you are removing "-foo", then "-foo param1" and "-foo param2" can -- be removed. -- -- If Remove_All is True, then all matching switches are removed, otherwise -- only the first matching one is removed. -- -- If Has_Parameter is set to True, then only switches having a parameter -- are removed. -- -- If the switch belongs to a section, then this section should be -- specified: Remove_Switch (Cmd_Line, "-g", Section => "-cargs") called -- on the command line "-g -cargs -g" will result in "-g", while if -- called with (Cmd_Line, "-g") this will result in "-cargs -g". -- If Remove_All is set, then both "-g" will be removed. procedure Remove_Switch (Cmd : in out Command_Line; Switch : String; Remove_All : Boolean := False; Has_Parameter : Boolean := False; Section : String := ""; Success : out Boolean); -- Same as above, reporting the success of the operation (Success is False -- if no switch was removed). procedure Remove_Switch (Cmd : in out Command_Line; Switch : String; Parameter : String; Section : String := ""); -- Remove a switch with a specific parameter. If Parameter is the empty -- string, then only a switch with no parameter will be removed. procedure Free (Cmd : in out Command_Line); -- Free the memory used by Cmd --------------- -- Iteration -- --------------- -- When a command line was created with the above, you can then iterate -- over its contents using the following iterator. type Command_Line_Iterator is private; procedure Start (Cmd : in out Command_Line; Iter : in out Command_Line_Iterator; Expanded : Boolean := False); -- Start iterating over the command line arguments. If Expanded is true, -- then the arguments are not grouped and no alias is used. For instance, -- "-gnatwv" and "-gnatwu" would be returned instead of "-gnatwuv". -- -- The iterator becomes invalid if the command line is changed through a -- call to Add_Switch, Remove_Switch or Set_Command_Line. function Current_Switch (Iter : Command_Line_Iterator) return String; function Is_New_Section (Iter : Command_Line_Iterator) return Boolean; function Current_Section (Iter : Command_Line_Iterator) return String; function Current_Separator (Iter : Command_Line_Iterator) return String; function Current_Parameter (Iter : Command_Line_Iterator) return String; -- Return the current switch and its parameter (or the empty string if -- there is no parameter or the switch was added through Add_Switch -- without specifying the parameter. -- -- Separator is the string that goes between the switch and its separator. -- It could be the empty string if they should be concatenated, or a space -- for instance. When printing, you should not add any other character. function Has_More (Iter : Command_Line_Iterator) return Boolean; -- Return True if there are more switches to be returned procedure Next (Iter : in out Command_Line_Iterator); -- Move to the next switch procedure Build (Line : in out Command_Line; Args : out GNAT.OS_Lib.Argument_List_Access; Expanded : Boolean := False; Switch_Char : Character := '-'); -- This is a wrapper using the Command_Line_Iterator. It provides a simple -- way to get all switches (grouped as much as possible), and possibly -- create an Opt_Parser. -- -- Args must be freed by the caller. -- -- Expanded has the same meaning as in Start. procedure Try_Help; -- Output a message on standard error to indicate how to get the usage for -- the executable. This procedure should only be called when the executable -- accepts switch --help. When this procedure is called by executable xxx, -- the following message is displayed on standard error: -- try "xxx --help" for more information. private Max_Depth : constant := 100; -- Maximum depth of subdirectories Max_Path_Length : constant := 1024; -- Maximum length of relative path type Depth is range 1 .. Max_Depth; type Level is record Name_Last : Natural := 0; Dir : GNAT.Directory_Operations.Dir_Type; end record; type Level_Array is array (Depth) of Level; type Section_Number is new Natural range 0 .. 65534; for Section_Number'Size use 16; type Parameter_Type is record Arg_Num : Positive; First : Positive; Last : Natural; Extra : Character; end record; type Is_Switch_Type is array (Natural range <>) of Boolean; pragma Pack (Is_Switch_Type); type Section_Type is array (Natural range <>) of Section_Number; pragma Pack (Section_Type); type Expansion_Iterator is limited record Start : Positive := 1; -- Position of the first character of the relative path to check against -- the pattern. Dir_Name : String (1 .. Max_Path_Length); Current_Depth : Depth := 1; Levels : Level_Array; Regexp : GNAT.Regexp.Regexp; -- Regular expression built with the pattern Maximum_Depth : Depth := 1; -- The maximum depth of directories, reflecting the number of directory -- separators in the pattern. end record; type Opt_Parser_Data (Arg_Count : Natural) is record Arguments : GNAT.OS_Lib.Argument_List_Access; -- null if reading from the command line The_Parameter : Parameter_Type; The_Separator : Character; The_Switch : Parameter_Type; -- This type and this variable are provided to store the current switch -- and parameter. Is_Switch : Is_Switch_Type (1 .. Arg_Count) := (others => False); -- Indicates wich arguments on the command line are considered not be -- switches or parameters to switches (leaving e.g. filenames,...) Section : Section_Type (1 .. Arg_Count) := (others => 1); -- Contains the number of the section associated with the current -- switch. If this number is 0, then it is a section delimiter, which is -- never returned by GetOpt. Current_Argument : Natural := 1; -- Number of the current argument parsed on the command line Current_Index : Natural := 1; -- Index in the current argument of the character to be processed Current_Section : Section_Number := 1; Expansion_It : aliased Expansion_Iterator; -- When Get_Argument is expanding a file name, this is the iterator used In_Expansion : Boolean := False; -- True if we are expanding a file Switch_Character : Character := '-'; -- The character at the beginning of the command line arguments, -- indicating the beginning of a switch. Stop_At_First : Boolean := False; -- If it is True then Getopt stops at the first non-switch argument end record; Command_Line_Parser_Data : aliased Opt_Parser_Data (Ada.Command_Line.Argument_Count); -- The internal data used when parsing the command line type Opt_Parser is access all Opt_Parser_Data; Command_Line_Parser : constant Opt_Parser := Command_Line_Parser_Data'Access; type Switch_Type is (Switch_Untyped, Switch_Boolean, Switch_Integer, Switch_String, Switch_Callback); type Switch_Definition (Typ : Switch_Type := Switch_Untyped) is record Switch : GNAT.OS_Lib.String_Access; Long_Switch : GNAT.OS_Lib.String_Access; Section : GNAT.OS_Lib.String_Access; Help : GNAT.OS_Lib.String_Access; Argument : GNAT.OS_Lib.String_Access; -- null if "ARG". -- Name of the argument for this switch. case Typ is when Switch_Untyped => null; when Switch_Boolean => Boolean_Output : access Boolean; Boolean_Value : Boolean; -- will set Output to that value when Switch_Integer => Integer_Output : access Integer; Integer_Initial : Integer; Integer_Default : Integer; when Switch_String => String_Output : access GNAT.Strings.String_Access; when Switch_Callback => Callback : Value_Callback; end case; end record; type Switch_Definitions is array (Natural range <>) of Switch_Definition; type Switch_Definitions_List is access all Switch_Definitions; -- [Switch] includes the leading '-' type Alias_Definition is record Alias : GNAT.OS_Lib.String_Access; Expansion : GNAT.OS_Lib.String_Access; Section : GNAT.OS_Lib.String_Access; end record; type Alias_Definitions is array (Natural range <>) of Alias_Definition; type Alias_Definitions_List is access all Alias_Definitions; type Command_Line_Configuration_Record is record Prefixes : GNAT.OS_Lib.Argument_List_Access; -- The list of prefixes Sections : GNAT.OS_Lib.Argument_List_Access; -- The list of sections Star_Switch : Boolean := False; -- Whether switches not described in this configuration should be -- returned to the user (True). If False, an exception Invalid_Switch -- is raised. Aliases : Alias_Definitions_List; Usage : GNAT.OS_Lib.String_Access; Help : GNAT.OS_Lib.String_Access; Help_Msg : GNAT.OS_Lib.String_Access; Switches : Switch_Definitions_List; -- List of expected switches (Used when expanding switch groups) end record; type Command_Line_Configuration is access Command_Line_Configuration_Record; type Command_Line is record Config : Command_Line_Configuration; Expanded : GNAT.OS_Lib.Argument_List_Access; Params : GNAT.OS_Lib.Argument_List_Access; -- Parameter for the corresponding switch in Expanded. The first -- character is the separator (or ASCII.NUL if there is no separator). Sections : GNAT.OS_Lib.Argument_List_Access; -- The list of sections Coalesce : GNAT.OS_Lib.Argument_List_Access; Coalesce_Params : GNAT.OS_Lib.Argument_List_Access; Coalesce_Sections : GNAT.OS_Lib.Argument_List_Access; -- Cached version of the command line. This is recomputed every time -- the command line changes. Switches are grouped as much as possible, -- and aliases are used to reduce the length of the command line. The -- parameters are not allocated, they point into Params, so they must -- not be freed. end record; type Command_Line_Iterator is record List : GNAT.OS_Lib.Argument_List_Access; Sections : GNAT.OS_Lib.Argument_List_Access; Params : GNAT.OS_Lib.Argument_List_Access; Current : Natural; end record; end CLIC.Command_Line; alire-1.2.1/deps/clic/src/clic-config-edit.adb000066400000000000000000000124001424570375700210260ustar00rootroot00000000000000with Ada.Text_IO; with Ada.Directories; with AAA.Strings; with AAA.Directories; with CLIC.Config.Load; with Simple_Logging; with TOML; package body CLIC.Config.Edit is package Trace renames Simple_Logging; use TOML; procedure Write_Config_File (Table : TOML_Value; Path : String) with Pre => Table.Kind = TOML_Table; function Remove_From_Table (Table : TOML_Value; Key : Config_Key) return Boolean with Pre => Table.Kind = TOML_Table; function Add_In_Table (Table : TOML_Value; Key : Config_Key; Val : TOML_Value) return Boolean with Pre => Table.Kind = TOML_Table; ----------------------- -- Write_Config_File -- ----------------------- procedure Write_Config_File (Table : TOML_Value; Path : String) is use Ada.Text_IO; use Ada.Directories; File : File_Type; begin -- Create the directory for the config file, in case it doesn't exists Create_Path (Containing_Directory (Path)); Create (File, Out_File, Path); Trace.Debug ("Write config: '" & TOML.Dump_As_String (Table) & "'"); Put (File, TOML.Dump_As_String (Table)); Close (File); end Write_Config_File; ----------------------- -- Remove_From_Table -- ----------------------- function Remove_From_Table (Table : TOML_Value; Key : Config_Key) return Boolean is use AAA.Strings; Id : constant String := Split (Key, '.', Raises => False); Leaf : constant Boolean := Id = Key; begin if not Table.Has (Id) then -- The key doesn't exist Trace.Error ("Configuration key not defined"); return False; end if; if Leaf then Table.Unset (Id); return True; else declare Sub : constant TOML_Value := Table.Get (Id); begin if Sub.Kind = TOML_Table then return Remove_From_Table (Sub, Split (Key, '.', Tail)); else Trace.Error ("Configuration key not defined"); return False; end if; end; end if; end Remove_From_Table; ------------------ -- Add_In_Table -- ------------------ function Add_In_Table (Table : TOML_Value; Key : Config_Key; Val : TOML_Value) return Boolean is use AAA.Strings; Id : constant String := Split (Key, '.', Raises => False); Leaf : constant Boolean := Id = Key; begin if Leaf then Table.Set (Id, Val); return True; end if; if not Table.Has (Id) then -- The subkey doesn't exist, create a table for it Table.Set (Id, Create_Table); end if; declare Sub : constant TOML_Value := Table.Get (Id); begin if Sub.Kind = TOML_Table then return Add_In_Table (Sub, Split (Key, '.', Tail), Val); else Trace.Error ("Configuration key already defined"); return False; end if; end; end Add_In_Table; ----------- -- Unset -- ----------- function Unset (Path : String; Key : Config_Key) return Boolean is use AAA.Directories; Tmp : Replacer := New_Replacement (File => Path, Backup => False, Allow_No_Original => True); Table : constant TOML_Value := Load.Load_TOML_File (Tmp.Editable_Name); begin if Table.Is_Null then -- The configuration file doesn't exist or is not valid Trace.Error ("configuration file doesn't exist or is not valid"); return False; end if; if not Remove_From_Table (Table, Key) then return False; end if; Write_Config_File (Table, Tmp.Editable_Name); Tmp.Replace; return True; end Unset; --------- -- Set -- --------- function Set (Path : String; Key : Config_Key; Value : String; Check : Check_Import := null) return Boolean is use AAA.Directories; Tmp : Replacer := New_Replacement (File => Path, Backup => False, Allow_No_Original => True); Table : TOML_Value := Load.Load_TOML_File (Tmp.Editable_Name); To_Add : constant TOML_Value := To_TOML_Value (Value); begin if To_Add.Is_Null then Trace.Error ("Invalid configuration value: '" & Value & "'"); return False; end if; if Check /= null and then not Check (Key, To_Add) then return False; end if; if Table.Is_Null then -- The configuration file doesn't exist or is not valid. Create an -- empty table. Table := TOML.Create_Table; end if; if not Add_In_Table (Table, Key, To_Add) then return False; end if; Write_Config_File (Table, Tmp.Editable_Name); Tmp.Replace; return True; end Set; end CLIC.Config.Edit; alire-1.2.1/deps/clic/src/clic-config-edit.ads000066400000000000000000000016551424570375700210610ustar00rootroot00000000000000package CLIC.Config.Edit is function Unset (Path : String; Key : Config_Key) return Boolean; -- Unset/Remove a key from a configuration file. Return True in case of -- success or False when the configuration file or the key don't exist. function Set (Path : String; Key : Config_Key; Value : String; Check : Check_Import := null) return Boolean; -- Set a key in a configuration file. Return True in case of success or -- False when the value is invalid or rejected by the Check function. -- -- When a Check function is provided, it will be called on the -- config key/value. If Check return False, Set returns False and the -- configuration file is not modified. In addition the Check function -- can print an error message explaining why the key/value is invalid. end CLIC.Config.Edit; alire-1.2.1/deps/clic/src/clic-config-info.adb000066400000000000000000000030261424570375700210400ustar00rootroot00000000000000with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with GNAT.Regpat; package body CLIC.Config.Info is ---------- -- List -- ---------- function List (This : CLIC.Config.Instance; Filter : String := ".*"; Show_Origin : Boolean := False) return AAA.Strings.Vector is Result : AAA.Strings.Vector; begin for Key of List_Keys (This, Filter) loop declare Val : constant Config_Value := This.Config_Map (+Key); Line : Unbounded_String; begin if Show_Origin then Line := Val.Origin & ": "; end if; Append (Line, Key & "="); Append (Line, Image (Val.Value)); Result.Append (To_String (Line)); end; end loop; return Result; end List; --------------- -- List_Keys -- --------------- function List_Keys (This : CLIC.Config.Instance; Filter : String := ".*") return AAA.Strings.Vector is use GNAT.Regpat; Re : constant Pattern_Matcher := Compile (Filter); Result : AAA.Strings.Vector; begin for C in This.Config_Map.Iterate loop declare Key : constant String := To_String (Config_Maps.Key (C)); begin if Match (Re, Key) then Result.Append (Key); end if; end; end loop; return Result; end List_Keys; end CLIC.Config.Info; alire-1.2.1/deps/clic/src/clic-config-info.ads000066400000000000000000000014201424570375700210550ustar00rootroot00000000000000package CLIC.Config.Info is function List (This : CLIC.Config.Instance; Filter : String := ".*"; Show_Origin : Boolean := False) return AAA.Strings.Vector; -- Return a Vector of String that contains a list of configuration -- key/value as seen in the configuration. When Show_Origin is true, -- the configuration file where each key was loaded is also listed. -- -- The keys not matching the Filter regular expression (see GNAT.Regpat) -- are ignored. function List_Keys (This : CLIC.Config.Instance; Filter : String := ".*") return AAA.Strings.Vector; -- Same as above but only return the config keys end CLIC.Config.Info; alire-1.2.1/deps/clic/src/clic-config-load.adb000066400000000000000000000031421424570375700210230ustar00rootroot00000000000000with GNAT.OS_Lib; with TOML.File_IO; with Simple_Logging; package body CLIC.Config.Load is package Trace renames Simple_Logging; use TOML; --------------- -- From_TOML -- --------------- procedure From_TOML (C : in out CLIC.Config.Instance; Origin : String; Path : String; Check : Check_Import := null) is Table : constant TOML_Value := Load_TOML_File (Path); begin C.Import (Table, Origin, Check => Check); end From_TOML; -------------------- -- Load_TOML_File -- -------------------- function Load_TOML_File (Path : String) return TOML.TOML_Value is begin if GNAT.OS_Lib.Is_Read_Accessible_File (Path) then declare Config : constant TOML.Read_Result := TOML.File_IO.Load_File (Path); begin if Config.Success then if Config.Value.Kind /= TOML.TOML_Table then Trace.Error ("Bad config file '" & Path & "': TOML table expected."); else return Config.Value; end if; else Trace.Detail ("error while loading '" & Path & "':"); Trace.Detail (Ada.Strings.Unbounded.To_String (Config.Message)); end if; end; else Trace.Detail ("Config file is not readable or doesn't exist: '" & Path & "'"); end if; return No_TOML_Value; end Load_TOML_File; end CLIC.Config.Load; alire-1.2.1/deps/clic/src/clic-config-load.ads000066400000000000000000000005411424570375700210440ustar00rootroot00000000000000with TOML; package CLIC.Config.Load is procedure From_TOML (C : in out CLIC.Config.Instance; Origin : String; Path : String; Check : Check_Import := null); function Load_TOML_File (Path : String) return TOML.TOML_Value; end CLIC.Config.Load; alire-1.2.1/deps/clic/src/clic-config.adb000066400000000000000000000201631424570375700201100ustar00rootroot00000000000000with Ada.Strings.Unbounded; with Simple_Logging; package body CLIC.Config is use Ada.Strings.Unbounded; use TOML; package Trace renames Simple_Logging; function Image (F : TOML.Any_Float) return String; ---------------------- -- Import_Recursive -- ---------------------- procedure Import_Recursive (This : in out Instance; Table : TOML.TOML_Value; Origin : String; Check : Check_Import := null; Prefix : String := "") is begin if Table = No_TOML_Value or else Table.Kind /= TOML_Table then return; end if; for Ent of Iterate_On_Table (Table) loop declare Key : constant String := (if Prefix = "" then "" else Prefix & ".") & To_String (Ent.Key); begin if not Is_Valid_Config_Key (Key) then Trace.Error ("Invalid configuration key '" & Key & "' in " & "'" & Origin & "'"); elsif Ent.Value.Kind = TOML_Table then -- Recursive call on the table Import_Recursive (This, Ent.Value, Origin, Check, Key); else Trace.Debug ("Load config key: '" & Key & "' = '" & Ent.Value.Kind'Img & "'"); if Ent.Value.Kind not in TOML_String | TOML_Float | TOML_Integer | TOML_Boolean then Trace.Error ("Invalid type '" & Ent.Value.Kind'Img & "' for key '" & Key & "' in configuration file '" & Origin & "'"); Trace.Error ("'" & Key & "' is ignored"); elsif Check /= null and then not Check (Key, Ent.Value) then Trace.Error ("'" & Key & "' is ignored"); else -- Insert the config value, potentially replacing a previous -- definition. This.Config_Map.Include (To_Unbounded_String (Key), (Value => Ent.Value, Origin => To_Unbounded_String (Origin))); end if; end if; end; end loop; end Import_Recursive; ------------ -- Import -- ------------ procedure Import (This : in out Instance; Table : TOML.TOML_Value; Origin : String; Check : Check_Import := null) is begin Import_Recursive (This, Table, Origin, Check); end Import; ------------- -- Defined -- ------------- function Defined (This : Instance; Key : Config_Key) return Boolean is begin return This.Config_Map.Contains (+Key); end Defined; ------------------- -- Get_As_String -- ------------------- function Get_As_String (This : Instance; Key : Config_Key) return String is begin if This.Defined (Key) then return Image (This.Get (Key).Value); else return ""; end if; end Get_As_String; --------- -- Get -- --------- function Get (This : Instance; Key : Config_Key) return Config_Value is begin if This.Defined (Key) then return This.Config_Map.Element (+Key); else return No_Config_Value; end if; end Get; --------- -- Get -- --------- function Get (This : Instance; Key : Config_Key; Default : Boolean) return Boolean is function Get_With_Default_Bool is new Get_With_Default_Gen (Boolean, TOML_Boolean, "Boolean", TOML.As_Boolean, Boolean'Image); begin return Get_With_Default_Bool (This, Key, Default); end Get; --------- -- Get -- --------- function Get (This : Instance; Key : Config_Key; Default : String) return String is function Id (Str : String) return String is (Str); function Get_With_Default_Str is new Get_With_Default_Gen (String, TOML_String, "String", TOML.As_String, Id); begin return Get_With_Default_Str (This, Key, Default); end Get; --------- -- Get -- --------- function Get (This : Instance; Key : Config_Key; Default : TOML.Any_Integer) return TOML.Any_Integer is function Get_With_Default_Int is new Get_With_Default_Gen (TOML.Any_Integer, TOML_Integer, "Integer", TOML.As_Integer, Any_Integer'Image); begin return Get_With_Default_Int (This, Key, Default); end Get; --------- -- Get -- --------- function Get (This : Instance; Key : Config_Key; Default : TOML.Any_Float) return TOML.Any_Float is function Get_With_Default_Int is new Get_With_Default_Gen (TOML.Any_Float, TOML_Float, "Float", TOML.As_Float, Image); begin return Get_With_Default_Int (This, Key, Default); end Get; ----------- -- Clear -- ----------- procedure Clear (This : in out Instance) is begin This.Config_Map.Clear; end Clear; -------------------------- -- Get_With_Default_Gen -- -------------------------- function Get_With_Default_Gen (This : Instance; Key : Config_Key; Default : Return_Type) return Return_Type is Val : constant Config_Value := This.Get (Key); begin if Val.Value.Is_Null then Trace.Detail ("Using default value for configuration '" & Key & "': '" & Image (Default) & "'"); return Default; elsif Val.Value.Kind /= Expected_TOML_Kind then Trace.Error ("Invalid type ('" & Val.Value.Kind'Img & "') for configuration '" & Key & "'"); Trace.Error ("in '" & To_String (Val.Origin) & "'"); Trace.Error (Type_Name & " expected"); Trace.Error ("Using default: '" & Image (Default) & "'"); return Default; else return TOML_As_Return_Type (Val.Value); end if; end Get_With_Default_Gen; ------------------- -- To_TOML_Value -- ------------------- function To_TOML_Value (Str : String) return TOML.TOML_Value is Result : constant TOML.Read_Result := TOML.Load_String ("key=" & Str); begin if not Result.Success or else Result.Value.Kind /= TOML_Table or else not Result.Value.Has ("key") then -- Conversion failed -- Interpret as a string return Create_String (Str); else return Result.Value.Get ("key"); end if; end To_TOML_Value; --------------------- -- No_Config_Value -- --------------------- function No_Config_Value return Config_Value is (Value => TOML.No_TOML_Value, Origin => Null_Unbounded_String); ----------- -- Image -- ----------- function Image (F : TOML.Any_Float) return String is begin case F.Kind is when Regular => return AAA.Strings.Trim (F.Value'Image); when NaN | Infinity => return (if F.Positive then "" else "-") & (if F.Kind = NaN then "nan" else "inf"); end case; end Image; ----------- -- Image -- ----------- function Image (Val : TOML.TOML_Value) return String is begin case Val.Kind is when TOML_Boolean => return (if Val.As_Boolean then "true" else "false"); when TOML_Integer => return AAA.Strings.Trim (Val.As_Integer'Img); when TOML_Float => return Image (Val.As_Float); when TOML_String => return Val.As_String; when others => return ""; end case; end Image; end CLIC.Config; alire-1.2.1/deps/clic/src/clic-config.ads000066400000000000000000000130441424570375700201310ustar00rootroot00000000000000with AAA.Strings; with TOML; private with Ada.Containers.Hashed_Maps; private with Ada.Strings.Unbounded.Hash; package CLIC.Config with Preelaborate is function Is_Valid_Config_Key (Key : String) return Boolean is ((for all C of Key => C in '0' .. '9' | 'a' .. 'z' | 'A' .. 'Z' | '-' | '.' | '_') and then Key (Key'First) not in '-' | '.' | '_' and then Key (Key'Last) not in '-' | '.' | '_' and then not AAA.Strings.Contains (Key, "..")); -- Rule that define a valid configuration key. Dots are used to separate -- levels of configuration groups. -- eg: -- user.login -- user.email subtype Config_Key is String with Dynamic_Predicate => Is_Valid_Config_Key (Config_Key); type Instance is tagged limited private; pragma Preelaborable_Initialization (Instance); type Check_Import is access function (Key : Config_Key; Value : TOML.TOML_Value) return Boolean; -- Return False when a Key/Value combination is not valid. Can be used to -- check formating of string value like email address for instance. procedure Import (This : in out Instance; Table : TOML.TOML_Value; Origin : String; Check : Check_Import := null); -- Import configuration from the TOML table. -- -- The Origin parameter is used in error messages and when listing config -- values to help the user identify the origin of the value. It can be just -- a word (e.g. local vs global), or the full path to the config file. -- -- When a Check function is provided, it will be called for each imported -- config key/value. If Check return False, the value is ignored and not -- imported in the configuration. Import will print an Error message saying -- that the key/value is ignored. In addition the Check function can also -- print an error message explaining why the key/value is invalid. function Defined (This : Instance; Key : Config_Key) return Boolean; -- Return True if a value is defined for the given key function Get_As_String (This : Instance; Key : Config_Key) return String; -- Return a string representation of the value for the given configuration -- Key. If the key is not defined, an empty string is returned. function Get (This : Instance; Key : Config_Key; Default : Boolean) return Boolean; -- Return the Boolean value for the given configuration Key. If the key is -- not defined, the Default value is returned. If the key is defined but -- not as a Boolean, an error message is displayed and the Default value -- is returned. function Get (This : Instance; Key : Config_Key; Default : String) return String; -- Return the String value for the given configuration Key. If the key is -- not defined, the Default value is returned. If the key is defined but -- not as a String, an error message is displayed and the Default value -- is returned. function Get (This : Instance; Key : Config_Key; Default : TOML.Any_Integer) return TOML.Any_Integer; -- Return the Integer value for the given configuration Key. If the key is -- not defined, the Default value is returned. If the key is defined but -- not as an Integer, an error message is displayed and the Default value -- is returned. function Get (This : Instance; Key : Config_Key; Default : TOML.Any_Float) return TOML.Any_Float; -- Return the Float value for the given configuration Key. If the key is -- not defined, the Default value is returned. If the key is defined but -- not as an Float, an error message is displayed and the Default value -- is returned. procedure Clear (This : in out Instance); -- Remove all configuration keys function Image (Val : TOML.TOML_Value) return String; private generic type Return_Type (<>) is private; Expected_TOML_Kind : TOML.Any_Value_Kind; Type_Name : String; with function TOML_As_Return_Type (Value : TOML.TOML_Value) return Return_Type; with function Image (V : Return_Type) return String; function Get_With_Default_Gen (This : Instance; Key : Config_Key; Default : Return_Type) return Return_Type; function To_TOML_Value (Str : String) return TOML.TOML_Value; -- Use the TOML parser to convert the string Str. If Str is not a valid -- TOML value, No_TOML_Value is returned. type Config_Value is record Value : TOML.TOML_Value; Origin : Ada.Strings.Unbounded.Unbounded_String; end record; function No_Config_Value return Config_Value; package Config_Maps is new Ada.Containers.Hashed_Maps (Key_Type => Ada.Strings.Unbounded.Unbounded_String, Element_Type => Config_Value, Hash => Ada.Strings.Unbounded.Hash, Equivalent_Keys => Ada.Strings.Unbounded."="); function "+" (Source : String) return Ada.Strings.Unbounded.Unbounded_String renames Ada.Strings.Unbounded.To_Unbounded_String; type Instance is tagged limited record Config_Map : Config_Maps.Map; end record; function Get (This : Instance; Key : Config_Key) return Config_Value; end CLIC.Config; alire-1.2.1/deps/clic/src/clic-subcommand-instance.adb000066400000000000000000000772161424570375700226100ustar00rootroot00000000000000with Ada.Command_Line; with Ada.Exceptions; with GNAT.OS_Lib; with GNAT.Strings; with Ada.Containers.Hashed_Maps; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Strings.Unbounded.Hash; with AAA.Table_IO; with AAA.Text_IO; with CLIC.Config.Info; with CLIC.Command_Line; use CLIC.Command_Line; package body CLIC.Subcommand.Instance is package Command_Maps is new Ada.Containers.Hashed_Maps (Key_Type => Ada.Strings.Unbounded.Unbounded_String, Element_Type => Command_Access, Hash => Ada.Strings.Unbounded.Hash, Equivalent_Keys => Ada.Strings.Unbounded."="); package Topic_Maps is new Ada.Containers.Hashed_Maps (Key_Type => Ada.Strings.Unbounded.Unbounded_String, Element_Type => Help_Topic_Access, Hash => Ada.Strings.Unbounded.Hash, Equivalent_Keys => Ada.Strings.Unbounded."="); package Group_Maps is new Ada.Containers.Hashed_Maps (Key_Type => Ada.Strings.Unbounded.Unbounded_String, Element_Type => AAA.Strings.Vector, "=" => AAA.Strings."=", Hash => Ada.Strings.Unbounded.Hash, Equivalent_Keys => Ada.Strings.Unbounded."="); package Alias_Maps is new Ada.Containers.Hashed_Maps (Key_Type => Ada.Strings.Unbounded.Unbounded_String, Element_Type => AAA.Strings.Vector, "=" => AAA.Strings."=", Hash => Ada.Strings.Unbounded.Hash, Equivalent_Keys => Ada.Strings.Unbounded."="); Registered_Commands : Command_Maps.Map; -- A map of commands based on their names Registered_Topics : Topic_Maps.Map; -- A map of topics based on their names Registered_Groups : Group_Maps.Map; -- A map of list of commands based on their group names Registered_Aliases : Alias_Maps.Map; -- A map of aliases and their replacement args Not_In_A_Group : AAA.Strings.Vector; -- List of commands that are not in a group Global_Arguments : AAA.Strings.Vector; -- Vector of arguments for the global command, the first one should be the -- command name, otherwise there is an invalid global switch on the command -- line. Help_Requested : Boolean; Global_Config : Switches_Configuration; Global_Parsing_Done : Boolean := False; procedure Display_Options (Config : Switches_Configuration; Title : String); procedure Display_Global_Options; function Highlight_Switches (Line : String) return String; function What_Command (Str : String := "") return not null Command_Access; procedure Put_Line_For_Access (Str : String); function To_Argument_List (V : AAA.Strings.Vector) return GNAT.OS_Lib.Argument_List_Access; function To_Vector (List : GNAT.OS_Lib.Argument_List_Access) return AAA.Strings.Vector; procedure Process_Aliases with Pre => not Global_Arguments.Is_Empty; procedure Split_At_Double_Dash (Args : AAA.Strings.Vector; Before, After : out AAA.Strings.Vector) with Post => (if not Args.Contains ("--") then Before."=" (Args)) and then not Before.Contains ("--"); -- Split a vector of command line arguments, everything before a potential -- first "--" (double dash) is added to the Before output, the arguments -- after the "--" are added to the After output. The first "--" is not -- added to either the Before or After output. -- -- When there is no "--" argument, Before is equal to Args. -------------------------- -- Split_At_Double_Dash -- -------------------------- procedure Split_At_Double_Dash (Args : AAA.Strings.Vector; Before, After : out AAA.Strings.Vector) is Before_Double_Dash : Boolean := True; begin for Elt of Args loop if Before_Double_Dash then if Elt = "--" then Before_Double_Dash := False; else Before.Append (Elt); end if; else After.Append (Elt); end if; end loop; end Split_At_Double_Dash; ------------------------- -- Put_Line_For_Access -- ------------------------- procedure Put_Line_For_Access (Str : String) is begin Put_Line (Str); end Put_Line_For_Access; ---------------------- -- To_Argument_List -- ---------------------- function To_Argument_List (V : AAA.Strings.Vector) return GNAT.OS_Lib.Argument_List_Access is List : constant GNAT.OS_Lib.Argument_List_Access := new GNAT.Strings.String_List (1 .. V.Count); begin for Index in List.all'Range loop List (Index) := new String'(V (Index)); end loop; return List; end To_Argument_List; --------------- -- To_Vector -- --------------- function To_Vector (List : GNAT.OS_Lib.Argument_List_Access) return AAA.Strings.Vector is use GNAT.OS_Lib; Result : AAA.Strings.Vector; begin if List /= null then for Elt of List.all loop if Elt /= null then Result.Append (Elt.all); end if; end loop; end if; return Result; end To_Vector; -------------- -- Register -- -------------- procedure Register (Cmd : not null Command_Access) is Name : constant Unbounded_String := To_Unbounded_String (Cmd.Name); begin if Registered_Commands.Contains (Name) then raise Command_Already_Defined with Cmd.Name; else -- Register the command Registered_Commands.Insert (Name, Cmd); -- This command is not in a group Not_In_A_Group.Append (Cmd.Name); end if; end Register; -------------- -- Register -- -------------- procedure Register (Group : String; Cmd : not null Command_Access) is Name : constant Unbounded_String := To_Unbounded_String (Cmd.Name); Ugroup : constant Unbounded_String := To_Unbounded_String (Group); begin if Registered_Commands.Contains (Name) then raise Command_Already_Defined with Cmd.Name; else -- Register the command Registered_Commands.Insert (Name, Cmd); -- Create the group if it doesn't exist yet if not Registered_Groups.Contains (Ugroup) then Registered_Groups.Insert (Ugroup, AAA.Strings.Empty_Vector); end if; -- Add this command to the list of commands for the group Registered_Groups.Reference (Ugroup).Append (Cmd.Name); end if; end Register; -------------- -- Register -- -------------- procedure Register (Topic : not null Help_Topic_Access) is Name : constant Unbounded_String := To_Unbounded_String (Topic.Name); begin if Registered_Topics.Contains (Name) then raise Program_Error; else Registered_Topics.Insert (Name, Topic); end if; end Register; --------------- -- Set_Alias -- --------------- procedure Set_Alias (Alias : Identifier; Replacement : AAA.Strings.Vector) is Name : constant Unbounded_String := To_Unbounded_String (Alias); begin Registered_Aliases.Include (Name, Replacement); end Set_Alias; ------------------ -- Load_Aliases -- ------------------ procedure Load_Aliases (Conf : CLIC.Config.Instance; Root_Key : String := "alias") is Keys : constant AAA.Strings.Vector := CLIC.Config.Info.List_Keys (Conf, "^" & Root_Key & "\.[^.]+$"); begin for Key of Keys loop declare Alias : constant String := AAA.Strings.Tail (Key, '.'); Value : constant String := Conf.Get (Key, Default => ""); List : GNAT.OS_Lib.String_List_Access := GNAT.OS_Lib.Argument_String_To_List (Value); begin if Value /= "" then Set_Alias (Alias, To_Vector (List)); end if; GNAT.OS_Lib.Free (List); end; end loop; end Load_Aliases; ------------------ -- What_Command -- ------------------ function What_Command (Str : String := "") return not null Command_Access is Name : constant Unbounded_String := To_Unbounded_String (if Str = "" then What_Command else Str); begin if Registered_Commands.Contains (Name) then return Registered_Commands.Element (Name); else raise Error_No_Command; end if; end What_Command; ------------------ -- What_Command -- ------------------ function What_Command return String is begin if Global_Arguments.Is_Empty or else AAA.Strings.Has_Prefix (Global_Arguments.First_Element, "-") then raise Error_No_Command; else return Global_Arguments.First_Element; end if; end What_Command; ---------------------------- -- Display_Valid_Commands -- ---------------------------- procedure Display_Valid_Commands is use Command_Maps; use Group_Maps; Tab : constant String (1 .. 1) := (others => ' '); Table : AAA.Table_IO.Table; ----------------- -- Add_Command -- ----------------- procedure Add_Command (Cmd : not null Command_Access) is begin Table.New_Row; Table.Append (Tab); Table.Append (TTY_Description (Cmd.Name)); Table.Append (Tab); Table.Append (Cmd.Short_Description); end Add_Command; First_Group : Boolean := Not_In_A_Group.Is_Empty; begin if Registered_Commands.Is_Empty then return; end if; Put_Line (""); Put_Line (TTY_Chapter ("COMMANDS")); for Name of Not_In_A_Group loop Add_Command (Registered_Commands (To_Unbounded_String (Name))); end loop; for Iter in Registered_Groups.Iterate loop if not First_Group then Table.New_Row; Table.Append (Tab); else First_Group := False; end if; declare Group : constant String := To_String (Key (Iter)); begin Table.New_Row; Table.Append (Tab); Table.Append (TTY_Underline (Group)); for Name of Element (Iter) loop Add_Command (Registered_Commands (To_Unbounded_String (Name))); end loop; end; end loop; Table.Print (Separator => " ", Put_Line => Put_Line_For_Access'Access); end Display_Valid_Commands; -------------------------- -- Display_Valid_Topics -- -------------------------- procedure Display_Valid_Topics is Tab : constant String (1 .. 1) := (others => ' '); Table : AAA.Table_IO.Table; use Topic_Maps; begin if Registered_Topics.Is_Empty then return; end if; Put_Line (""); Put_Line (TTY_Chapter ("TOPICS")); for Elt in Registered_Topics.Iterate loop Table.New_Row; Table.Append (Tab); Table.Append (TTY_Description (To_String (Key (Elt)))); Table.Append (Tab); Table.Append (Element (Elt).Title); end loop; Table.Print (Separator => " ", Put_Line => Put_Line_For_Access'Access); end Display_Valid_Topics; --------------------- -- Display_Aliases -- --------------------- procedure Display_Aliases is Tab : constant String (1 .. 1) := (others => ' '); Table : AAA.Table_IO.Table; use Alias_Maps; begin if Registered_Aliases.Is_Empty then return; end if; Put_Line (TTY_Chapter ("ALIASES")); for Elt in Registered_Aliases.Iterate loop Table.New_Row; Table.Append (Tab); Table.Append (TTY_Description (To_String (Key (Elt)))); Table.Append (Tab); Table.Append (Element (Elt).Flatten); end loop; Table.Print (Separator => " ", Put_Line => Put_Line_For_Access'Access); end Display_Aliases; ------------------- -- Display_Usage -- ------------------- procedure Display_Usage (Cmd : not null Command_Access) is Config : Switches_Configuration; Canary1 : Switches_Configuration; Canary2 : Switches_Configuration; begin Put_Line (TTY_Chapter ("SUMMARY")); Put_Line (" " & Cmd.Short_Description); Put_Line (""); Put_Line (TTY_Chapter ("USAGE")); Put (" "); Put_Line (TTY_Underline (Main_Command_Name) & " " & TTY_Underline (Cmd.Name) & " [options] " & Cmd.Usage_Custom_Parameters); -- We use the following two canaries to detect if a command is adding -- its own switches, in which case we need to show their specific help. Set_Global_Switches (Canary1); -- For comparison Set_Global_Switches (Canary2); -- For comparison Cmd.Setup_Switches (Canary1); if Get_Switches (Canary1.GNAT_Cfg) /= Get_Switches (Canary2.GNAT_Cfg) then Cmd.Setup_Switches (Config); end if; -- Without the following line, GNAT.Display_Help causes a segfault for -- reasons I'm unable to pinpoint. This way it prints a harmless blank -- line that we want anyway. Define_Switch (Config, " ", " ", " ", " ", " "); Display_Options (Config, "OPTIONS"); Display_Global_Options; -- Format and print the long command description Put_Line (""); Put_Line (TTY_Chapter ("DESCRIPTION")); for Line of Cmd.Long_Description loop AAA.Text_IO.Put_Paragraph (Highlight_Switches (Line), Line_Prefix => " "); -- GNATCOLL.Paragraph_Filling seems buggy at the moment, otherwise -- it would be the logical choice. end loop; end Display_Usage; ------------------- -- Display_Usage -- ------------------- procedure Display_Usage (Displayed_Error : Boolean := False) is begin if not Displayed_Error then Put_Line (Main_Command_Name & " " & TTY_Version (Version)); Put_Line (""); end if; Put_Line (TTY_Chapter ("USAGE")); Put_Line (" " & TTY_Underline (Main_Command_Name) & " [global options] " & " [command options] []"); Put_Line (""); Put_Line (" " & TTY_Underline (Main_Command_Name) & " " & TTY_Underline ("help") & " [|]"); Put_Line (""); Put_Line (TTY_Chapter ("ARGUMENTS")); declare Tab : constant String (1 .. 1) := (others => ' '); Table : AAA.Table_IO.Table; begin Table.New_Row; Table.Append (Tab); Table.Append (TTY_Description ("")); Table.Append ("Command to execute"); Table.New_Row; Table.Append (Tab); Table.Append (TTY_Description ("")); Table.Append ("List of arguments for the command"); Table.Print (Separator => " ", Put_Line => Put_Line_For_Access'Access); end; Display_Global_Options; Display_Valid_Commands; Display_Valid_Topics; Display_Aliases; end Display_Usage; --------------------------- -- Parse_Global_Switches -- --------------------------- procedure Parse_Global_Switches (Command_Line : AAA.Strings.Vector := AAA.Strings.Empty_Vector) is ---------------------- -- Ada_Command_Line -- ---------------------- function Ada_Command_Line return AAA.Strings.Vector is use Ada.Command_Line; Result : AAA.Strings.Vector; begin for I in 1 .. Argument_Count loop Result.Append (Ada.Command_Line.Argument (I)); end loop; return Result; end Ada_Command_Line; ---------------------- -- Filter_Arguments -- ---------------------- function Filter_Arguments return GNAT.OS_Lib.Argument_List_Access is Arguments : AAA.Strings.Vector; Cmd_Line : constant AAA.Strings.Vector := (if Command_Line.Is_Empty then Ada_Command_Line else Command_Line); begin -- GNAT switch handling intercepts -h/--help. To have the same output -- for '
-h command' and '
help command', we do manual for Arg of Cmd_Line loop if Arg not in "-h" | "--help" then Arguments.Append (Arg); else Help_Requested := True; end if; end loop; return To_Argument_List (Arguments); end Filter_Arguments; Arguments : GNAT.OS_Lib.Argument_List_Access; Parser : Opt_Parser; begin -- Only do the global parsing once if Global_Parsing_Done and then Command_Line.Is_Empty then return; else Global_Arguments.Clear; Help_Requested := False; Clear (Global_Config); Global_Parsing_Done := True; end if; -- We filter the command line arguments to remove -h/--help that would -- trigger the Getopt automatic help system. Arguments := Filter_Arguments; Set_Global_Switches (Global_Config); -- Run the parser first with only the global switches. With the -- Stop_At_First_Non_Switch => True the parser will stop at the first -- argument, witch is supposed to be a sub-command, topic, or alias. -- The rest of the command line args are added to the Global_Arguments. Initialize_Option_Scan (Parser, Arguments, Stop_At_First_Non_Switch => True); Getopt (Global_Config.GNAT_Cfg, Parser => Parser, Quiet => True); -- Make a vector of arguments starting from the first non switch loop declare Arg : constant String := CLIC.Command_Line.Get_Argument (Parser => Parser); begin exit when Arg = ""; Global_Arguments.Append (Arg); end; end loop; GNAT.OS_Lib.Free (Arguments); -- At this point the command and all unknown switches are in -- Global_Arguments. exception -- Getopt should never raise Exit_From_Command_Line because we filtered -- the -h/--help switches from the command line. when E : Invalid_Switch | Invalid_Parameter => Put_Error (Ada.Exceptions.Exception_Message (E) & " (global)."); Put_Error ("try """ & Main_Command_Name & " --help"" for more information."); Error_Exit (1); end Parse_Global_Switches; --------------------- -- Process_Aliases -- --------------------- procedure Process_Aliases is Name : constant String := Global_Arguments.First_Element; Uname : constant Unbounded_String := To_Unbounded_String (Name); begin -- If we have a valid alias if Registered_Aliases.Contains (Uname) then -- Remove the alias from the arguments Global_Arguments.Delete_First; -- And replace it by the alias value Global_Arguments.Prepend (Registered_Aliases (Uname)); end if; end Process_Aliases; ------------- -- Execute -- ------------- procedure Execute (Command_Line : AAA.Strings.Vector := AAA.Strings.Empty_Vector) is Parser : Opt_Parser; -- Subcommand parser, declared here so it is available to the exception -- handler below. begin Parse_Global_Switches (Command_Line); if Global_Arguments.Is_Empty then -- We should at least have the sub-command name in the arguments Display_Usage; Error_Exit (1); elsif Help_Requested then Display_Help (Global_Arguments.First_Element); Error_Exit (0); end if; -- Take care of a potential alias Process_Aliases; -- Dispatch to the appropriate command declare Cmd : constant not null Command_Access := What_Command; -- Might raise if invalid, if so we are done Command_Config : Switches_Configuration; Sub_Cmd_Line : GNAT.OS_Lib.String_List_Access; To_Parse, Sub_Arguments : AAA.Strings.Vector; begin -- Add command specific switches to the config. We don't need the -- global switches because they have been parsed before. Cmd.Setup_Switches (Command_Config); case Cmd.Switch_Parsing is when Parse_All => -- Parse all global arguments To_Parse := Global_Arguments; Sub_Arguments := AAA.Strings.Empty_Vector; when Before_Double_Dash => -- Only parse the arguments before a potential "--" Split_At_Double_Dash (Global_Arguments, Before => To_Parse, After => Sub_Arguments); when All_As_Args => -- Skip all sub-command switch parsing To_Parse := AAA.Strings.Empty_Vector; Sub_Arguments := Global_Arguments; end case; if not To_Parse.Is_Empty then -- Make a new command line argument list from the remaining -- arguments and switches after global parsing. Sub_Cmd_Line := To_Argument_List (To_Parse); -- Initialize a new switch parser that will only see the new -- sub-command line (i.e. the remaining args and switches after -- global parsing). Initialize_Option_Scan (Parser, Sub_Cmd_Line); -- Parse sub-command line, invalid switches will raise an -- exception Getopt (Command_Config.GNAT_Cfg, Parser => Parser, Quiet => True); -- Make a vector of arguments for the sub-command (every element -- that was not a switch in the sub-command line). declare Args_After_Parsing : AAA.Strings.Vector; begin loop declare Arg : constant String := CLIC.Command_Line.Get_Argument (Parser => Parser); begin exit when Arg = ""; Args_After_Parsing.Append (Arg); end; end loop; Sub_Arguments.Prepend (Args_After_Parsing); end; -- We don't need this anymore GNAT.OS_Lib.Free (Sub_Cmd_Line); end if; pragma Assert (not Sub_Arguments.Is_Empty, "Should have at least the command name"); -- Remove the sub-command name from the list Sub_Arguments.Delete_First; Cmd.Execute (Sub_Arguments); end; exception -- Getopt should never raise Exit_From_Command_Line because we filtered -- the -h/--help switches from the command line. when E : Invalid_Switch | Invalid_Parameter => Put_Error (Ada.Exceptions.Exception_Message (E) & " (command/topic """ & What_Command & """)."); Put_Error ("try """ & Main_Command_Name & " help " & What_Command & """ for more information."); if Is_Global_Switch (Full_Switch (Parser)) then Put_Line ("Option '" & Full_Switch (Parser) & "' is a valid global option, to use it as such please" & " give it before the subcommand."); end if; Error_Exit (1); when Error_No_Command => Put_Error ("Unrecognized command: " & Global_Arguments.First_Element); Put_Line (""); Display_Usage (Displayed_Error => True); Error_Exit (1); end Execute; ------------------------ -- Highlight_Switches -- ------------------------ function Highlight_Switches (Line : String) return String is use AAA.Strings.Vectors; use AAA.Strings; --------------- -- Highlight -- --------------- -- Avoid highlighting non-alphanumeric characters function Highlight (Word : String) return String is subtype Valid_Chars is Character with Dynamic_Predicate => Valid_Chars in '0' .. '9' | 'a' .. 'z'; I : Natural := Word'Last; -- last char to highlight begin while I >= Word'First and then Word (I) not in Valid_Chars loop I := I - 1; end loop; return TTY_Emph (Word (Word'First .. I)) & Word (I + 1 .. Word'Last); end Highlight; Words : AAA.Strings.Vector := AAA.Strings.Split (Line, Separator => ' '); I, J : Vectors.Cursor; begin I := Words.First; while Has_Element (I) loop declare Word : constant String := Element (I); begin J := Next (I); if Has_Prefix (Word, "--") and then Word'Length > 2 then Words.Insert (Before => J, New_Item => Highlight (Word)); Words.Delete (I); end if; I := J; end; end loop; return Flatten (Words); end Highlight_Switches; --------------------- -- Display_Options -- --------------------- procedure Display_Options (Config : Switches_Configuration; Title : String) is Tab : constant String (1 .. 1) := (others => ' '); Table : AAA.Table_IO.Table; Has_Printable_Rows : Boolean := False; ----------------- -- Without_Arg -- ----------------- function Without_Arg (Value : String) return String is Required_Character : constant Character := Value (Value'Last); begin return (if Required_Character in '=' | ':' | '!' | '?' then Value (Value'First .. Value'Last - 1) else Value); end Without_Arg; -------------- -- With_Arg -- -------------- function With_Arg (Value, Arg : String) return String is Required_Character : constant Character := Value (Value'Last); begin return (if Required_Character in '=' | ':' | '!' | '?' then AAA.Strings.Replace (Value, "" & Required_Character, (case Required_Character is when '=' => "=" & Arg, when ':' => "[ ] " & Arg, when '!' => Arg, when '?' => "[" & Arg & "]", when others => raise Program_Error)) else Value); end With_Arg; --------------- -- Print_Row -- --------------- procedure Print_Row (Short_Switch, Long_Switch, Arg, Help : String) is Has_Short : constant Boolean := Short_Switch not in " " | ""; Has_Long : constant Boolean := Long_Switch not in " " | ""; begin if not Has_Short and then not Has_Long then return; end if; Table.New_Row; Table.Append (Tab); if Has_Short and Has_Long then Table.Append (TTY_Description (Without_Arg (Short_Switch)) & " (" & With_Arg (Long_Switch, Arg) & ")"); elsif not Has_Short and Has_Long then Table.Append (TTY_Description (With_Arg (Long_Switch, Arg))); elsif Has_Short and not Has_Long then Table.Append (TTY_Description (With_Arg (Short_Switch, Arg))); end if; Table.Append (Help); Has_Printable_Rows := True; end Print_Row; begin for Elt of Config.Info loop Print_Row (To_String (Elt.Switch), To_String (Elt.Long_Switch), To_String (Elt.Argument), To_String (Elt.Help)); end loop; if Has_Printable_Rows then Put_Line (""); Put_Line (TTY_Chapter (Title)); Table.Print (Separator => " ", Put_Line => Put_Line_For_Access'Access); end if; end Display_Options; ---------------------------- -- Display_Global_Options -- ---------------------------- procedure Display_Global_Options is Global_Config : Switches_Configuration; begin Set_Global_Switches (Global_Config); Display_Options (Global_Config, "GLOBAL OPTIONS"); end Display_Global_Options; ------------------ -- Display_Help -- ------------------ procedure Display_Help (Keyword : String) is ------------ -- Format -- ------------ procedure Format (Text : AAA.Strings.Vector) is begin for Line of Text loop AAA.Text_IO.Put_Paragraph (Highlight_Switches (Line), Line_Prefix => " "); end loop; end Format; Ukey : constant Unbounded_String := To_Unbounded_String (Keyword); begin if Registered_Commands.Contains (Ukey) then Display_Usage (What_Command (Keyword)); elsif Registered_Topics.Contains (Ukey) then Put_Line (TTY_Chapter (Registered_Topics.Element (Ukey).Title)); Format (Registered_Topics.Element (Ukey).Content); elsif Registered_Aliases.Contains (Ukey) then Put_Line ("'" & Keyword & "' is an alias for: '" & Main_Command_Name & " " & Registered_Aliases.Element (Ukey).Flatten & "'"); else Put_Error ("No help found for: " & Keyword); Display_Global_Options; Display_Valid_Commands; Display_Valid_Topics; Display_Aliases; Error_Exit (1); end if; end Display_Help; ------------- -- Execute -- ------------- overriding procedure Execute (This : in out Builtin_Help; Args : AAA.Strings.Vector) is pragma Unreferenced (This); begin if Args.Count /= 1 then if Args.Count > 1 then Put_Error ("Please specify a single help keyword"); Put_Line (""); end if; Put_Line (TTY_Chapter ("USAGE")); Put_Line (" " & TTY_Underline (Main_Command_Name) & " " & TTY_Underline ("help") & " [|]"); Put_Line (""); Put_Line (TTY_Chapter ("ARGUMENTS")); declare Tab : constant String (1 .. 1) := (others => ' '); Table : AAA.Table_IO.Table; begin Table.New_Row; Table.Append (Tab); Table.Append (TTY_Description ("")); Table.Append ("Command for which to show a description"); Table.New_Row; Table.Append (Tab); Table.Append (TTY_Description ("")); Table.Append ("Topic for which to show a description"); Table.Print (Separator => " ", Put_Line => Put_Line_For_Access'Access); end; Display_Global_Options; Display_Valid_Commands; Display_Valid_Topics; Display_Aliases; Error_Exit (1); end if; Display_Help (Args (1)); end Execute; ---------------------- -- Is_Global_Switch -- ---------------------- function Is_Global_Switch (Switch : String) return Boolean is Parser : Opt_Parser; Command_Line : GNAT.OS_Lib.Argument_List_Access := GNAT.OS_Lib.Argument_String_To_List (Switch); Result : Boolean := False; begin Initialize_Option_Scan (Parser, Command_Line => Command_Line, Stop_At_First_Non_Switch => True); begin Getopt (Config => Global_Config.GNAT_Cfg, Parser => Parser, Quiet => True); Result := True; exception when Invalid_Switch => Result := False; end; GNAT.OS_Lib.Free (Command_Line); return Result; end Is_Global_Switch; end CLIC.Subcommand.Instance; alire-1.2.1/deps/clic/src/clic-subcommand-instance.ads000066400000000000000000000123431424570375700226170ustar00rootroot00000000000000-- Instantiate this package to create a sub-command parser/executor with CLIC.Config; generic Main_Command_Name : String; -- Name of the main command or program Version : String; -- Version of the program with procedure Set_Global_Switches (Config : in out CLIC.Subcommand.Switches_Configuration); -- This procedure should define the global switches using the -- Register_Switch procedures of the CLIC.Subcommand package. with procedure Put (Str : String); -- Used to print help and usage with procedure Put_Line (Str : String); -- Used to print help and usage with procedure Put_Error (Str : String); -- Used to print errors with procedure Error_Exit (Code : Integer); -- Used to signal that the program should terminate with the give error -- code. Typicaly use GNAT.OS_Lib.OS_Exit. -- The procedures below are used to format the output such as usage and -- help. Use CLIC.Subcommand.No_TTY if you don't want or need formating. with function TTY_Chapter (Str : String) return String; with function TTY_Description (Str : String) return String; with function TTY_Version (Str : String) return String; with function TTY_Underline (Str : String) return String; with function TTY_Emph (Str : String) return String; package CLIC.Subcommand.Instance is procedure Register (Cmd : not null Command_Access); -- Register a sub-command procedure Register (Group : String; Cmd : not null Command_Access); -- Register a sub-command in a group procedure Register (Topic : not null Help_Topic_Access); -- Register a help topic procedure Set_Alias (Alias : Identifier; Replacement : AAA.Strings.Vector); -- Define Alias such that " " will -- be replaced by " ". -- If Alias is already set, it will be silently replaced. procedure Load_Aliases (Conf : CLIC.Config.Instance; Root_Key : String := "alias"); -- Load aliases from the given configuration. -- -- All the config keys in the format "." are -- processed. If the value of a key is a (not null) String, -- is registered as an alias for the value (parsed into a list with -- GNAT.OS_Lib.Argument_String_To_List). -- -- For instance when Root_Key := "alias" (default): -- alias.test1 = "cmd arg1 arg2" # Valid: test1 -> ["cmd", "arg1", "arg2"] -- alias.test2 = "cmd" # Valid: test2 -> ["cmd"] -- alias.test3 = "" # Ignored -- alias.test4.test = "cmd arg1" # Ignored -- alias.test5 = 20 # Ignored -- alias.test6 = ["cmd", "arg1"] # Ignored procedure Execute (Command_Line : AAA.Strings.Vector := AAA.Strings.Empty_Vector); -- Parse the command line and execute a sub-command or display help/usage -- depending on command line args. -- -- If Command_Line is not empty it will be used instead of the actual -- command line arguments from Ada.Command_Line. procedure Parse_Global_Switches (Command_Line : AAA.Strings.Vector := AAA.Strings.Empty_Vector); -- Optional. Call this procedure before Execute to get only global switches -- parsed. This can be useful to check the values of global switches before -- running a sub-command or change the behavior of your program based on -- these (e.g. verbosity, output color, etc.). -- -- If Command_Line is not empty it will be used instead of the actual -- command line arguments from Ada.Command_Line. function What_Command return String; procedure Display_Usage (Displayed_Error : Boolean := False); procedure Display_Help (Keyword : String); Error_No_Command : exception; Command_Already_Defined : exception; type Builtin_Help is new Command with private; -- Use Register (new Builtin_Help); to provide a build-in help command function Is_Global_Switch (Switch : String) return Boolean; -- Say if the switch has been defined as global private -- Built-in Help Command -- type Builtin_Help is new Command with null record; overriding function Name (This : Builtin_Help) return Identifier is ("help"); overriding function Switch_Parsing (This : Builtin_Help) return Switch_Parsing_Kind is (Parse_All); overriding procedure Execute (This : in out Builtin_Help; Args : AAA.Strings.Vector); overriding function Long_Description (This : Builtin_Help) return AAA.Strings.Vector is (AAA.Strings.Empty_Vector .Append ("Shows information about commands and topics.") .Append ("See available commands with '" & Main_Command_Name & " help commands'") .Append ("See available topics with '" & Main_Command_Name & " help topics'.")); overriding procedure Setup_Switches (This : in out Builtin_Help; Config : in out CLIC.Subcommand.Switches_Configuration) is null; overriding function Short_Description (This : Builtin_Help) return String is ("Shows help on the given command/topic"); overriding function Usage_Custom_Parameters (This : Builtin_Help) return String is ("[|]"); end CLIC.Subcommand.Instance; alire-1.2.1/deps/clic/src/clic-subcommand.adb000066400000000000000000000123501424570375700207720ustar00rootroot00000000000000with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package body CLIC.Subcommand is ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Switches_Configuration; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG") is begin CLIC.Command_Line.Define_Switch (Config.GNAT_Cfg, Switch => Switch, Long_Switch => Long_Switch, Help => Help, Section => Section, Argument => Argument); Add (Config.Info, Switch, Long_Switch, Help, Argument); end Define_Switch; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Switches_Configuration; Output : access Boolean; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Value : Boolean := True) is begin CLIC.Command_Line.Define_Switch (Config.GNAT_Cfg, Output => Output, Switch => Switch, Long_Switch => Long_Switch, Help => Help, Section => Section, Value => Value); Add (Config.Info, Switch, Long_Switch, Help, ""); end Define_Switch; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Switches_Configuration; Output : access Integer; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Initial : Integer := 0; Default : Integer := 1; Argument : String := "ARG") is begin CLIC.Command_Line.Define_Switch (Config.GNAT_Cfg, Switch => Switch, Output => Output, Long_Switch => Long_Switch, Help => Help, Section => Section, Initial => Initial, Default => Default, Argument => Argument); Add (Config.Info, Switch, Long_Switch, Help, Argument); end Define_Switch; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Switches_Configuration; Output : access GNAT.Strings.String_Access; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG") is begin CLIC.Command_Line.Define_Switch (Config.GNAT_Cfg, Output => Output, Switch => Switch, Long_Switch => Long_Switch, Help => Help, Section => Section, Argument => Argument); Add (Config.Info, Switch, Long_Switch, Help, Argument); end Define_Switch; ------------------- -- Define_Switch -- ------------------- procedure Define_Switch (Config : in out Switches_Configuration; Callback : not null CLIC.Command_Line.Value_Callback; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG") is begin CLIC.Command_Line.Define_Switch (Config.GNAT_Cfg, Callback => Callback, Switch => Switch, Long_Switch => Long_Switch, Help => Help, Section => Section, Argument => Argument); Add (Config.Info, Switch, Long_Switch, Help, Argument); end Define_Switch; --------- -- Add -- --------- procedure Add (Vect : in out Switch_Info_Vectors.Vector; Switch, Long_Switch, Help, Argument : String) is begin Vect.Append (Switch_Info'(To_Unbounded_String (Switch), To_Unbounded_String (Long_Switch), To_Unbounded_String (Help), To_Unbounded_String (Argument))); end Add; ----------- -- Clear -- ----------- procedure Clear (This : in out Switches_Configuration) is begin CLIC.Command_Line.Free (This.GNAT_Cfg); This.Info.Clear; end Clear; end CLIC.Subcommand; alire-1.2.1/deps/clic/src/clic-subcommand.ads000066400000000000000000000157031424570375700210200ustar00rootroot00000000000000with AAA.Strings; with GNAT.Strings; with CLIC.Command_Line; private with Ada.Strings.Unbounded; private with Ada.Containers.Vectors; package CLIC.Subcommand is -- This root package defines the interface types to be used in the -- Subcommand. See CLIC.Subcommand.Instance to create the parser/executor. type Switches_Configuration is limited private; -- This is a wrapper around GNAT.Command_Line.Command_Line_Configuration -- to provide extra features such as duplicate switch detection and custom -- usage format. The "Define_Switch" procedure below work exactly like the -- GNAT.Command_Line ones. procedure Define_Switch (Config : in out Switches_Configuration; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG"); procedure Define_Switch (Config : in out Switches_Configuration; Output : access Boolean; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Value : Boolean := True); procedure Define_Switch (Config : in out Switches_Configuration; Output : access Integer; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Initial : Integer := 0; Default : Integer := 1; Argument : String := "ARG"); procedure Define_Switch (Config : in out Switches_Configuration; Output : access GNAT.Strings.String_Access; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG"); procedure Define_Switch (Config : in out Switches_Configuration; Callback : not null CLIC.Command_Line.Value_Callback; Switch : String := ""; Long_Switch : String := ""; Help : String := ""; Section : String := ""; Argument : String := "ARG"); subtype Identifier is String with Predicate => (for all C of Identifier => C in 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '-' | '.' | '_'); ------------- -- Command -- ------------- type Command is limited interface; -- This type encapsulates configuration and execution of a specific -- command. It also has help-related subprograms. type Command_Access is access all Command'Class; function Name (Cmd : Command) return Identifier is abstract; -- Commands must override this procedure to provide the sub-command name. -- This name is used to identify the sub-command in usage and command line. -- E.g. "my_app " will exectute the command. type Switch_Parsing_Kind is (Parse_All, -- All the sub-command arguments are parsed for switches Before_Double_Dash, -- Only the arguments before a potential "--" are parsed for switches. -- The remaining switches and arguments are passed to the Args parameter -- of the Execute primitive. All_As_Args -- Sub-command arguments parsing is disabled, both the sub-command -- switches and arguments passed to the Args parameter of the Execute -- primitive. ); function Switch_Parsing (Cmd : Command) return Switch_Parsing_Kind is abstract; -- Return True to skip sub-command switches parsing and get both the -- sub-command switches and arguments passed to the Args parameter of -- the Execute primitive. procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is abstract; -- Commands must override this procedure to provide the command -- functionality. function Long_Description (Cmd : Command) return AAA.Strings.Vector is abstract; -- Return a detailed description of the command. Each string in the vector -- is a paragraph that will be reformatted into appropriate length lines. procedure Setup_Switches (Cmd : in out Command; Config : in out Switches_Configuration) is null; -- Gets called once the command has been identified, but before the call to -- Execute. Config must be set up with the switches used by the command. function Short_Description (Cmd : Command) return String is abstract; -- One-liner displayed in the list of commands that alr understands that -- gets shown when no command or unknown command is given. Also shown as -- SUMMARY in the help of a specific command. function Usage_Custom_Parameters (Cmd : Command) return String is abstract; -- The part after "
[global options] command [command options] " that -- gets shown in USAGE in the command help summary. That is, it is the -- specific command-line part that is not managed via Gnat.Command_Line ----------------- -- Help_Topic -- ----------------- type Help_Topic is limited interface; -- This type encapsulate the content of an "help topic", i.e. a piece of -- documentation that can displayed from the command line. type Help_Topic_Access is access all Help_Topic'Class; function Name (This : Help_Topic) return Identifier is abstract; -- This name is used to identify the topic in usage and command line. -- E.g. "my_app help " will display the content of the topic. function Title (This : Help_Topic) return String is abstract; -- Descriptive title for the topic content. Unlike the Name, the Title can -- containt whitespaces. function Content (This : Help_Topic) return AAA.Strings.Vector is abstract; -- Return the content of the help topic. Each string in the vector is a -- paragraph that will be reformatted into appropriate length lines. ----------- -- Utils -- ----------- function No_TTY (Str : String) return String is (Str); -- Use this function for the TTY_* generic parameters of -- CLIC.Subcommand.Instance if you don't want or need TTY formating. private type Switch_Info is record Switch : Ada.Strings.Unbounded.Unbounded_String; Long_Switch : Ada.Strings.Unbounded.Unbounded_String; Help : Ada.Strings.Unbounded.Unbounded_String; Argument : Ada.Strings.Unbounded.Unbounded_String; end record; -- Used internaly to store informations about the switches package Switch_Info_Vectors is new Ada.Containers.Vectors (Natural, Switch_Info); procedure Add (Vect : in out Switch_Info_Vectors.Vector; Switch, Long_Switch, Help, Argument : String); type Switches_Configuration is limited record GNAT_Cfg : CLIC.Command_Line.Command_Line_Configuration; -- Still use GNAT.Command_Line to do the actual parsing Info : Switch_Info_Vectors.Vector; end record; procedure Clear (This : in out Switches_Configuration); end CLIC.Subcommand; alire-1.2.1/deps/clic/src/clic-tty.adb000066400000000000000000000115041424570375700174620ustar00rootroot00000000000000with Interfaces.C_Streams; with Simple_Logging; use Simple_Logging; with Simple_Logging.Decorators; package body CLIC.TTY is use all type ANSI.Colors; use all type ANSI.Styles; Use_Color : Boolean := False; -- Err on the safe side function Regular_Decorator (Level : Simple_Logging.Levels; Message : String) return String; function Verbose_Decorator (Level : Simple_Logging.Levels; Message : String) return String; Disabled_By_User : Boolean := False; ----------------------- -- Force_Disable_TTY -- ----------------------- procedure Force_Disable_TTY is begin Disabled_By_User := True; end Force_Disable_TTY; --------------- -- Check_TTY -- --------------- function Check_TTY return Boolean is use Interfaces.C_Streams; begin return isatty (fileno (stdout)) /= 0; end Check_TTY; ------------ -- Is_TTY -- ------------ function Is_TTY return Boolean is (if Disabled_By_User then False else Check_TTY); ------------------- -- Color_Enabled -- ------------------- function Color_Enabled return Boolean is (Use_Color); ------------------- -- Disable_Color -- ------------------- procedure Disable_Color is begin Use_Color := False; end Disable_Color; ------------------ -- Enable_Color -- ------------------ procedure Enable_Color (Force : Boolean := False) is begin -- Enable when appropriate if Force or else Is_TTY then Use_Color := True; Simple_Logging.Debug ("Color output enabled"); else Simple_Logging.Debug ("Color output was requested but not enabled:" & " force=" & Force'Img & "; Is_TTY=" & Is_TTY'Img); end if; -- Set debug colors. When Detail/Debug are also enabled, we add the -- "info:" prefix to otherwise normal output, so it's seen more easily. if Use_Color then case Simple_Logging.Level is when Always .. Info => Decorators.Level_Decorator := Regular_Decorator'Access; when others => Decorators.Level_Decorator := Verbose_Decorator'Access; end case; end if; end Enable_Color; ------------ -- Format -- ------------ function Format (Text : String; Fore : ANSI.Colors := ANSI.Default; Back : ANSI.Colors := ANSI.Default; Style : ANSI.Styles := ANSI.Default) return String is use ANSI; begin if not Use_Color then return Text; end if; return ((if Fore /= Default then Foreground (Fore) else "") & (if Back /= Default then Background (Fore) else "") & (if Style /= Default then ANSI.Style (Style, On) else "") & Text & (if Fore /= Default then Foreground (Default) else "") & (if Back /= Default then Background (Default) else "") & (if Style /= Default then ANSI.Style (Style, Off) else "")); end Format; ----------------------- -- Regular_Decorator -- ----------------------- function Regular_Decorator (Level : Simple_Logging.Levels; Message : String) return String is (case Level is when Info => Message, when others => Verbose_Decorator (Level, Message)); ----------------------- -- Verbose_Decorator -- ----------------------- function Verbose_Decorator (Level : Simple_Logging.Levels; Message : String) return String is use ANSI; begin return (case Level is when Always => Message, when Error => ANSI.Wrap (Text => "error:", Style => Bright, Foreground => ANSI.Foreground (Red)) & " " & Message, when Warning => ANSI.Wrap (Text => "warn:", Style => Bright, Foreground => ANSI.Foreground (Yellow)) & " " & Message, when Info => ANSI.Wrap (Text => "info:", Style => Bright, Foreground => ANSI.Foreground (Green)) & " " & Message, when Detail => ANSI.Wrap (Text => "detail:", Style => Bright, Foreground => ANSI.Foreground (Cyan)) & " " & Message, when Debug => ANSI.Wrap (Text => "debug:", Style => Default, Foreground => ANSI.Foreground (Grey)) & " " & ANSI.Wrap (Text => Message, Style => Dim)); end Verbose_Decorator; end CLIC.TTY; alire-1.2.1/deps/clic/src/clic-tty.ads000066400000000000000000000117201424570375700175030ustar00rootroot00000000000000with ANSI; package CLIC.TTY with Preelaborate is -- Color/Formatting related subprograms. These won't have any -- effect if a redirection of output is detected, or if global -- flag Simple_Logging.Is_TTY is false. -- Re-expose for clients package ANSI renames Standard.ANSI; function Is_TTY return Boolean; procedure Force_Disable_TTY with Post => not Is_TTY; -- Disable TTY support even if availabe -------------------- -- Color enabling -- -------------------- function Color_Enabled return Boolean; procedure Disable_Color; -- Disables color/formatting output even when TTY is capable procedure Enable_Color (Force : Boolean := False); -- Prepares colors for the logging messages. Unless Force, will do nothing -- if a console redirection is detected. function Format (Text : String; Fore : ANSI.Colors := ANSI.Default; Back : ANSI.Colors := ANSI.Default; Style : ANSI.Styles := ANSI.Default) return String; -- Wrap text with the appropriate ANSI sequences. Following text will be -- unaffected. Default colors are interpreted as no change of color (will -- result in no color sequences), not as setting the default color (which -- is always set after a color change). ------------------------ -- Predefined formats -- ------------------------ function Text_With_Fallback (Text : String; Fallback : String) return String with Post => Text_With_Fallback'Result = (if Color_Enabled and then Is_TTY then Text else Fallback); -- Intended to have a rich text and a safe alternative function Info (Text : String := "") return String; -- Prepends Text with a Emph ("🛈") or "Note: " if no tty color enabled function Success (Text : String := "") return String; -- Prepends Text (in normal formatting) with a green check mark, or a -- simple Success: text if no tty or color enabled. function OK (Text : String) return String; -- Bold Light_Green function Emph (Text : String) return String; -- Something to highlight not negatively, bold cyan function Error (Text : String) return String; -- Bold Red function Warn (Text : String) return String; -- Bold Yellow function Bold (Text : String) return String; function Dim (Text : String) return String; function Italic (Text : String) return String; function Underline (Text : String) return String; function Description (Text : String) return String; -- Not bold cyan for crate descriptions function Terminal (Text : String) return String; -- For showing commands that the user can run; mimics old amber displays. function URL (Text : String) return String; function Version (Text : String) return String; -- For versions/version sets, bold magenta private function Text_With_Fallback (Text : String; Fallback : String) return String is (if Color_Enabled and then Is_TTY then Text else Fallback); function Info (Text : String := "") return String is (if Color_Enabled and then Is_TTY then Emph ("ⓘ") & " " & Text else "Note: " & Text); function Success (Text : String := "") return String is (if Color_Enabled and then Is_TTY then OK ("✓") & " " & Text else "Success: " & Text); function OK (Text : String) return String is (Format (Text, Fore => ANSI.Light_Green, Style => ANSI.Bright)); function Emph (Text : String) return String is (Format (Text, Fore => ANSI.Cyan, Style => ANSI.Bright)); function Error (Text : String) return String is (Format (Text, Fore => ANSI.Red, Style => ANSI.Bright)); function Warn (Text : String) return String is (Format (Text, Fore => ANSI.Yellow, Style => ANSI.Bright)); function Bold (Text : String) return String is (Format (Text, Style => ANSI.Bright)); function Dim (Text : String) return String is (Format (Text, Style => ANSI.Dim)); function Italic (Text : String) return String is (Format (Text, Style => ANSI.Italic)); function Underline (Text : String) return String is (Format (Text, Style => ANSI.Underline)); function Name (Text : String) return String is (Bold (Text)); function Description (Text : String) return String is (Format (Text, Fore => ANSI.Light_Cyan)); function Terminal (Text : String) return String is (if Color_Enabled and then Is_TTY then ANSI.Color_Wrap (Text, ANSI.Palette_Fg (5, 3, 0)) else Text); function URL (Text : String) return String renames Version; function Version (Text : String) return String is (Format (Text, Fore => ANSI.Magenta, Style => ANSI.Bright)); end CLIC.TTY; alire-1.2.1/deps/clic/src/clic-user_input.adb000066400000000000000000000272271424570375700210500ustar00rootroot00000000000000with Ada.Text_IO; with Ada.Characters.Handling; with Simple_Logging; with CLIC.TTY; package body CLIC.User_Input is package TIO renames Ada.Text_IO; package Char renames Ada.Characters.Handling; User_Input_Error : exception; Answer_Char : constant array (Answer_Kind) of Character := (Yes => 'Y', No => 'N', Always => 'A'); ----------------- -- Answer_Kind -- ----------------- function Answer_String (Kind : Answer_Kind) return String is (case Kind is when Yes => "yes", when No => "no", when Always => "always"); --------------- -- Flush_TTY -- --------------- procedure Flush_TTY is C : Character; Available : Boolean; begin loop TIO.Get_Immediate (C, Available); exit when not Available; end loop; exception when TIO.End_Error => null; end Flush_TTY; ------------------------- -- Print_Valid_Answers -- ------------------------- procedure Print_Valid_Answers (Valid : Answer_Set; Default : Answer_Kind) is begin for Kind in Answer_Kind loop if Valid (Kind) then TIO.Put ("[" & (if Kind = Default then TTY.Bold ("" & Answer_Char (Kind)) else "" & Answer_Char (Kind)) & "] " & Img (Kind) & " "); end if; end loop; TIO.Put ("(default is " & TTY.Bold (Img (Default)) & ") "); end Print_Valid_Answers; ----------- -- Query -- ----------- function Query (Question : String; Valid : Answer_Set; Default : Answer_Kind) return Answer_Kind is ----------------- -- Use_Default -- ----------------- function Use_Default return Answer_Kind is begin TIO.Put_Line ("Using default: " & Img (Default)); return Default; end Use_Default; begin loop TIO.Put_Line (Question); if Not_Interactive or else not TTY.Is_TTY then return Use_Default; end if; -- Flush the input that the user may have entered by mistake before -- the question is asked. Flush_TTY; Print_Valid_Answers (Valid, Default); -- Get user input declare Input : constant String := TIO.Get_Line; begin -- Empty line means the user pressed enter without any answer if Input'Length = 0 then return Use_Default; end if; if Input'Length = 1 then for Kind in Answer_Kind loop if Valid (Kind) and then Char.To_Upper (Input (Input'First)) = Answer_Char (Kind) then -- We got a valid answer return Kind; end if; end loop; end if; --- Check if the user input the whole answer for Kind in Answer_Kind loop if Valid (Kind) and then Char.To_Lower (Input) = Answer_String (Kind) then return Kind; end if; end loop; TIO.Put_Line ("Invalid answer."); end; end loop; exception when TIO.End_Error => -- This happens on the user hitting Ctrl-D, and no further -- input can be obtained as stdin is closed raise User_Interrupt; end Query; ----------------- -- Query_Multi -- ----------------- function Query_Multi (Question : String; Choices : AAA.Strings.Vector; Page_Size : Positive := 10) return Positive is Answers : constant array (Positive range <>) of Character := ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); pragma Assert (Answers'First = Positive'First); Use_Pager : constant Boolean := Natural (Choices.Length) > Page_Size; Page_Start : Positive := 1; Page_End : Positive; -- Points always to the last valid choice; there can be an extra choice -- if Use_Pager, to move forward the list. ------------------- -- Print_Choices -- ------------------- procedure Print_Choices is begin Page_End := Positive'Min (Choices.Last_Index, Page_Start + Page_Size - 1); -- Print the choices proper for I in Page_Start .. Page_End loop TIO.Put_Line (" " & (if I = Page_Start then TTY.Bold ("" & Answers (I - Page_Start + 1)) else TTY.Emph ("" & Answers (I - Page_Start + 1))) & ". " & Choices (I)); end loop; -- And the pager if needed if Use_Pager then TIO.Put_Line (TTY.Emph (" " & Answers (Page_End - Page_Start + 2)) & ". (See more choices...)"); end if; end Print_Choices; begin loop begin TIO.Put_Line (Question); if Not_Interactive then Simple_Logging.Info ("Using default choice in non-interactive mode: " & Choices.First_Element); Simple_Logging.Warning (TTY.Is_TTY'Img); return Choices.First_Index; end if; -- Flush the input that the user may have entered by mistake -- before the question is asked. Flush_TTY; Print_Choices; TIO.Put_Line ("Enter your choice index (first is default): "); TIO.Put ("> "); declare Answer_Line : constant String := TIO.Get_Line; Answer_Char : Character; Answer_Pos : Natural := 0; Extra : constant Natural := (if Use_Pager then 1 else 0); -- We have an extra entry in the list in this case begin if Answer_Line = "" then return Page_Start; elsif Answer_Line'Length > 1 then raise User_Input_Error with "answer too long"; end if; Answer_Char := Answer_Line (Answer_Line'First); -- Find the user's choice, and correct it with the actual page -- we are showing to them. for I in Answers'Range loop if Answer_Char = Answers (I) then Answer_Pos := I; end if; end loop; if Answer_Pos = 0 then raise User_Input_Error with "Choice out of range"; end if; Answer_Pos := Answer_Pos + Page_Start - 1; if Answer_Pos not in Page_Start .. Page_End + Extra then raise User_Input_Error with "Choice out of range"; end if; -- We have a valid choice; either change pages or return choice if Answer_Pos = Page_End + 1 then Page_Start := Page_Start + Page_Size; if Page_Start > Choices.Last_Index then Page_Start := Choices.First_Index; end if; else return Answer_Pos; end if; end; exception when TIO.End_Error => -- This happens on the user hitting Ctrl-D, and no further -- input can be obtained as stdin is closed Simple_Logging.Debug ("End_Error caught."); raise User_Interrupt; when User_Input_Error => Simple_Logging.Info (TTY.Error ("✗ ") & "Not a valid choice, please use a line index."); when E : others => Simple_Logging.Warning ("Unexpected input, exiting."); raise User_Interrupt; end; end loop; end Query_Multi; --------- -- Img -- --------- function Img (Kind : Answer_Kind) return String is (case Kind is when Yes => "Yes", when No => "No", when Always => "Always"); ------------------ -- Query_String -- ------------------ function Query_String (Question : String; Default : String; Validation : String_Validation_Access) return String is ----------------- -- Use_Default -- ----------------- function Use_Default return String is begin TIO.Put_Line ("Using default: '" & Default & "'"); return Default; end Use_Default; -------------- -- Is_Valid -- -------------- function Is_Valid (Str : String) return Boolean is (Validation = null or else Validation (Str)); begin loop TIO.Put_Line (Question & " (" & "default: '" & Default & "')"); if Not_Interactive or else not TTY.Is_TTY then return Use_Default; end if; -- Print a prompt TIO.Put ("> "); -- Flush the input that the user may have entered by mistake before -- the question is asked. Flush_TTY; -- Get user input declare Input : constant String := TIO.Get_Line; begin -- Empty line means the user pressed enter without any answer if Input'Length = 0 and then Is_Valid (Default) then return Use_Default; end if; if Is_Valid (Input) then -- We got a valid answer return Input; end if; TIO.Put_Line ("Invalid answer."); end; end loop; exception when TIO.End_Error => -- This happens on the user hitting Ctrl-D, and no further -- input can be obtained as stdin is closed raise User_Interrupt; end Query_String; ----------------------- -- Continue_Or_Abort -- ----------------------- procedure Continue_Or_Abort is Foo : String := "bar"; Bar : Integer; begin if Not_Interactive then Simple_Logging.Detail ("Non-interactive session, continuing"); else Flush_TTY; TIO.Put_Line ("Press Enter to continue or Ctrl-C to abort"); TIO.Get_Line (Foo, Bar); end if; end Continue_Or_Abort; --------------------- -- Validated_Input -- --------------------- function Validated_Input (Question : String; Prompt : String; Valid : Answer_Set; Default : access function (User_Input : String) return Answer_Kind; Confirm : String := "Is this information correct?"; Is_Valid : access function (User_Input : String) return Boolean) return Answer_With_Input is begin TIO.Put_Line (Question); loop TIO.Put (Prompt); declare Input : constant String := TIO.Get_Line; begin if Is_Valid (Input) then declare Result : Answer_With_Input := (Input'Length, Input, No); begin Result.Answer := Query (Confirm, Valid, Default (Input)); if Result.Answer /= No then return Result; end if; end; end if; end; end loop; end Validated_Input; end CLIC.User_Input; alire-1.2.1/deps/clic/src/clic-user_input.ads000066400000000000000000000053131424570375700210610ustar00rootroot00000000000000with AAA.Strings; package CLIC.User_Input is ------------------- -- Interactivity -- ------------------- Not_Interactive : aliased Boolean := False; -- When not Interactive, instead of asking the user something, use default. User_Interrupt : exception; -- Raised when the user hits Ctrl-D and no further input can be obtained as -- stdin is closed. type Answer_Kind is (Yes, No, Always); type Answer_Set is array (Answer_Kind) of Boolean; function Query (Question : String; Valid : Answer_Set; Default : Answer_Kind) return Answer_Kind; -- If interactive, ask the user for one of the valid answer. -- Otherwise return the Default answer. function Query_Multi (Question : String; Choices : AAA.Strings.Vector; Page_Size : Positive := 10) return Positive with Pre => Page_Size >= 2 and then Page_Size < 36; -- Present the Choices in a numbered list 1-9-0-a-z, with paging if -- Choices.Length > Page_Size. Default is always First of Choices. type Answer_With_Input (Length : Natural) is record Input : String (1 .. Length); Answer : Answer_Kind; end record; function Validated_Input (Question : String; Prompt : String; Valid : Answer_Set; Default : access function (User_Input : String) return Answer_Kind; Confirm : String := "Is this information correct?"; Is_Valid : access function (User_Input : String) return Boolean) return Answer_With_Input; -- Interactive prompt for information from the user, with confirmation: -- Put_Line (Question) -- loop -- Put (Prompt); Get_Line (User_Input); -- if Is_Valid (User_Input) then -- exit when Query (Confirm, Valid, Default (User_Input)) /= No; -- end if; -- end loop function Img (Kind : Answer_Kind) return String; type String_Validation_Access is access function (Str : String) return Boolean; function Query_String (Question : String; Default : String; Validation : String_Validation_Access) return String with Pre => Validation = null or else Validation (Default); -- If interactive, ask the user to provide a valid string. -- Otherwise return the Default value. -- -- If Validation is null, any input is accepted. -- -- The Default value has to be a valid input. procedure Continue_Or_Abort; -- If interactive, ask the user to press Enter or Ctrl-C to stop. -- Output a log trace otherwise and continue. end CLIC.User_Input; alire-1.2.1/deps/clic/src/clic.ads000066400000000000000000000000551424570375700166640ustar00rootroot00000000000000package CLIC with Preelaborate is end CLIC; pax_global_header00006660000000000000000000000064142546524320014521gustar00rootroot0000000000000052 comment=92bb91130a9ec628b4c48b7ef9fe7f24d9dc25fa alire-1.2.1/deps/gnatcoll-slim/000077500000000000000000000000001425465243200163165ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/.gitattributes000066400000000000000000000013621425465243200212130ustar00rootroot00000000000000README.md no-precommit-check testsuite/*/*/* no-precommit-check testsuite/*/*/*/* no-precommit-check testsuite/*/*/*/*/* no-precommit-check # Third-party package src/getRSS.c no-precommit-check src/sqlite/amalgamation/* no-precommit-check src/dborm.py no-precommit-check src/xref.generated/* no-precommit-check distrib/gnatcoll/runtime.py no-precommit-check # ??? Workaround bug in style checker, which complains that # Finalization_Size is an unrecognized attribute src/gnatcoll-storage_pools-headers.adb no-precommit-check alire-1.2.1/deps/gnatcoll-slim/.gitignore000066400000000000000000000003731425465243200203110ustar00rootroot00000000000000/alire.lock b__* docs/_build examples/library/obj gnat/ /gnat_src gnatinspect.* lib/ makefile.setup obj/ src/sqlite/amalgamation/sqlite3_for_gps *.cgpr *.bexch *.a *.d *.stdout *.stderr *.ali *.gli *.exe *.gcda *.gcno *.gcov *.bexch *.o *.deps *.pyc alire-1.2.1/deps/gnatcoll-slim/.gitreview000066400000000000000000000001341425465243200203220ustar00rootroot00000000000000[gerrit] host = git.adacore.com port = 29418 project = gnatcoll-core defaultbranch = master alire-1.2.1/deps/gnatcoll-slim/.travis.yml000066400000000000000000000030021425465243200204220ustar00rootroot00000000000000# Global variables language: python python: - "2.7" env: global: - TOOLS_DIR=$HOME/build_tools - GNAT_TAR_PATH=$TOOLS_DIR/gpl-2017-compiler.tar.gz - LINUX_GNAT_URL=http://mirrors.cdn.adacore.com/art/591c6d80c7a447af2deed1d7 - DARWIN_GNAT_URL=http://mirrors.cdn.adacore.com/art/591c9045c7a447af2deed24e os: - linux # Cache directory that allows us to not download GNAT GPL every time, speeding # up the process. cache: directories: - /home/travis/build_tools - /Users/travis/build_tools install: # Check if the GNAT package is already available in the cache directory. If # not, download it. - > test -f $GNAT_TAR_PATH || (mkdir -p $TOOLS_DIR && if [ "$TRAVIS_OS_NAME" = "osx" ]; then wget $DARWIN_GNAT_URL -O $GNAT_TAR_PATH else wget $LINUX_GNAT_URL -O $GNAT_TAR_PATH fi ) # Extract GNAT from its package - (mkdir -p ada-compiler && cd ada-compiler && tar --strip-components 1 -xzf $GNAT_TAR_PATH) # Add GNAT to $PATH - export PATH=$PWD/ada-compiler/bin:$PATH # Checkout gprbuild - git clone https://github.com/AdaCore/gprbuild libgpr-src # Add e3-testsuite - pip install git+https://github.com/AdaCore/e3-testsuite.git script: # Show GNAT version for the record - $PWD/ada-compiler/bin/gprbuild --version - (cd libgpr-src && make libgpr.build && make libgpr.install) # Build gnatcoll-core - make all - (cd testsuite; ./run-tests --gcov) after_success: - bash <(curl -s https://codecov.io/bash) alire-1.2.1/deps/gnatcoll-slim/COPYING.RUNTIME000066400000000000000000000064601425465243200205010ustar00rootroot00000000000000GCC RUNTIME LIBRARY EXCEPTION Version 3.1, 31 March 2009 Copyright (c) 2009 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This GCC Runtime Library Exception ("Exception") is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). It applies to a given file (the "Runtime Library") that bears a notice placed by the copyright holder of the file stating that the file is governed by GPLv3 along with this Exception. When you use GCC to compile a program, GCC may combine portions of certain GCC header files and runtime libraries with the compiled program. The purpose of this Exception is to allow compilation of non-GPL (including proprietary) programs to use, in this way, the header files and runtime libraries covered by this Exception. 0. Definitions. A file is an "Independent Module" if it either requires the Runtime Library for execution after a Compilation Process, or makes use of an interface provided by the Runtime Library, but is not otherwise based on the Runtime Library. "GCC" means a version of the GNU Compiler Collection, with or without modifications, governed by version 3 (or a specified later version) of the GNU General Public License (GPL) with the option of using any subsequent versions published by the FSF. "GPL-compatible Software" is software whose conditions of propagation, modification and use would permit combination with GCC in accord with the license of GCC. "Target Code" refers to output from any compiler for a real or virtual target processor architecture, in executable form or suitable for input to an assembler, loader, linker and/or execution phase. Notwithstanding that, Target Code does not include data in any format that is used as a compiler intermediate representation, or used for producing a compiler intermediate representation. The "Compilation Process" transforms code entirely represented in non-intermediate languages designed for human-written code, and/or in Java Virtual Machine byte code, into Target Code. Thus, for example, use of source code generators and preprocessors need not be considered part of the Compilation Process, since the Compilation Process can be understood as starting with the output of the generators or preprocessors. A Compilation Process is "Eligible" if it is done using GCC, alone or with other GPL-compatible software, or if it is done without using any work based on GCC. For example, using non-GPL-compatible Software to optimize any GCC intermediate representations would not qualify as an Eligible Compilation Process. 1. Grant of Additional Permission. You have permission to propagate a work of Target Code formed by combining the Runtime Library with Independent Modules, even if such propagation would otherwise violate the terms of GPLv3, provided that all Target Code was generated by Eligible Compilation Processes. You may then convey such a combination under terms of your choice, consistent with the licensing of the Independent Modules. 2. No Weakening of GCC Copyleft. The availability of this Exception does not imply any general presumption that third-party software is unaffected by the copyleft requirements of the license of GCC. alire-1.2.1/deps/gnatcoll-slim/COPYING3000066400000000000000000001045131425465243200174400ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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. This program 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. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . alire-1.2.1/deps/gnatcoll-slim/Makefile000066400000000000000000000141211425465243200177550ustar00rootroot00000000000000############################################################################## ## ## ## GNATCOLL LIBRARY ## ## ## ## Copyright (C) 2017, AdaCore. ## ## ## ## This library is free software; you can redistribute it and/or modify it ## ## under terms of the GNU General Public License as published by the Free ## ## Software Foundation; either version 3, or (at your option) any later ## ## version. This library is distributed in the hope that it will be useful, ## ## but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN# ## ## TABILITY or FITNESS FOR A PARTICULAR PURPOSE. ## ## ## ## As a special exception under Section 7 of GPL version 3, you are granted ## ## additional permissions described in the GCC Runtime Library Exception, ## ## version 3.1, as published by the Free Software Foundation. ## ## ## ## You should have received a copy of the GNU General Public License and ## ## a copy of the GCC Runtime Library Exception along with this program; ## ## see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ## ## . ## ## ## ############################################################################## # Makefile targets # ---------------- # # Setup: make [VAR=VALUE] setup (see below) # Build: make # Install: make install # Variables which can be set: # # General: # # prefix : root install directory # ENABLE_SHARED : yes / no (or empty) # BUILD : DEBUG PROD # PROCESSORS : nb parallel compilations (0 to use all cores) # TARGET : target triplet for cross-compilation # INTEGRATED : installs the project as part of the compiler installation; # this adds NORMALIZED_TARGET subdir to prefix # # Project specific: # # GNATCOLL_MMAP : whether MMAP is supported (yes/no) # default is "yes"; has no effect on Windows # GNATCOLL_MADVISE : whether MADVISE is supported (yes/no) # default is "yes"; has no effect on Windows # GNATCOLL_ATOMICS : atomic model (intrinsic/mutex) # default is "intrinsic" # helper programs CAT := cat ECHO := echo WHICH := which # check for out-of-tree build SOURCE_DIR := $(dir $(MAKEFILE_LIST)) ifeq ($(SOURCE_DIR),./) RBD= GNATCOLL_GPR=gnatcoll.gpr MAKEPREFIX= else RBD=--relocate-build-tree GNATCOLL_GPR=$(SOURCE_DIR)/gnatcoll.gpr MAKEPREFIX=$(SOURCE_DIR)/ endif TARGET := $(shell gcc -dumpmachine) NORMALIZED_TARGET := $(subst normalized_target:,,$(wordlist 6,6,$(shell gprconfig --config=ada --target=$(TARGET) --mi-show-compilers))) ifeq ($(NORMALIZED_TARGET),) $(error No toolchain found for target "$(TARGET)") endif GNATCOLL_OS := $(if $(findstring darwin,$(NORMALIZED_TARGET)),osx,$(if $(findstring windows,$(NORMALIZED_TARGET)),windows,unix)) prefix := $(dir $(shell $(WHICH) gnatls)).. GNATCOLL_VERSION := $(shell $(CAT) $(SOURCE_DIR)/version_information) GNATCOLL_MMAP := yes GNATCOLL_MADVISE := yes GNATCOLL_ATOMICS := intrinsic BUILD = PROD PROCESSORS = 0 BUILD_DIR = ENABLE_SHARED = yes INTEGRATED = no all: build # Load current setup if any -include makefile.setup GTARGET=--target=$(NORMALIZED_TARGET) ifeq ($(ENABLE_SHARED), yes) LIBRARY_TYPES=static relocatable static-pic else LIBRARY_TYPES=static endif ifeq ($(INTEGRATED), yes) integrated_install=/$(NORMALIZED_TARGET) endif GPR_VARS=-XGNATCOLL_MMAP=$(GNATCOLL_MMAP) \ -XGNATCOLL_MADVISE=$(GNATCOLL_MADVISE) \ -XGNATCOLL_ATOMICS=$(GNATCOLL_ATOMICS) \ -XGNATCOLL_VERSION=$(GNATCOLL_VERSION) \ -XGNATCOLL_OS=$(GNATCOLL_OS) \ -XBUILD=$(BUILD) # Used to pass extra options to GPRBUILD, like -d for instance GPRBUILD_OPTIONS= BUILDER=gprbuild -p -m $(GTARGET) $(RBD) -j$(PROCESSORS) $(GPR_VARS) \ $(GPRBUILD_OPTIONS) INSTALLER=gprinstall -p -f $(GTARGET) $(GPR_VARS) \ $(RBD) --sources-subdir=include/gnatcoll --prefix=$(prefix)$(integrated_install) CLEANER=gprclean -q $(RBD) $(GTARGET) UNINSTALLER=$(INSTALLER) -p -f --install-name=gnatcoll --uninstall ######### # build # ######### build: $(LIBRARY_TYPES:%=build-%) build-%: $(BUILDER) -XLIBRARY_TYPE=$* -XXMLADA_BUILD=$* -XGPR_BUILD=$* \ $(GPR_VARS) $(GNATCOLL_GPR) ########### # Install # ########### uninstall: ifneq (,$(wildcard $(prefix)$(integrated_install)/share/gpr/manifests/gnatcoll)) $(UNINSTALLER) $(GNATCOLL_GPR) endif install: uninstall $(LIBRARY_TYPES:%=install-%) install-%: $(INSTALLER) -XLIBRARY_TYPE=$* -XXMLADA_BUILD=$* -XGPR_BUILD=$* \ --build-name=$* $(GPR_VARS) \ --build-var=LIBRARY_TYPE --build-var=GNATCOLL_BUILD \ --build-var=GNATCOLL_CORE_BUILD $(GNATCOLL_GPR) ########### # Cleanup # ########### clean: $(LIBRARY_TYPES:%=clean-%) clean-%: -$(CLEANER) -XLIBRARY_TYPE=$* -XXMLADA_BUILD=$* -XGPR_BUILD=$* \ $(GPR_VARS) $(GNATCOLL_GPR) ######### # setup # ######### .SILENT: setup setup: $(ECHO) "prefix=$(prefix)" > makefile.setup $(ECHO) "ENABLE_SHARED=$(ENABLE_SHARED)" >> makefile.setup $(ECHO) "INTEGRATED=$(INTEGRATED)" >> makefile.setup $(ECHO) "BUILD=$(BUILD)" >> makefile.setup $(ECHO) "PROCESSORS=$(PROCESSORS)" >> makefile.setup $(ECHO) "TARGET=$(TARGET)" >> makefile.setup $(ECHO) "SOURCE_DIR=$(SOURCE_DIR)" >> makefile.setup $(ECHO) "GNATCOLL_OS=$(GNATCOLL_OS)" >> makefile.setup $(ECHO) "GNATCOLL_VERSION=$(GNATCOLL_VERSION)" >> makefile.setup $(ECHO) "GNATCOLL_MMAP=$(GNATCOLL_MMAP)" >> makefile.setup $(ECHO) "GNATCOLL_MADVISE=$(GNATCOLL_MADVISE)" >> makefile.setup $(ECHO) "GNATCOLL_ATOMICS=$(GNATCOLL_ATOMICS)" >> makefile.setup alire-1.2.1/deps/gnatcoll-slim/README.md000066400000000000000000000047641425465243200176100ustar00rootroot00000000000000The GNAT Components Collection (GNATcoll) - Core packages ========================================================= This is the core module of the GNAT Components Collection. Please refer to the documentation in the `docs/` directory. Code status =========== Build status with GNAT GPL 2017 Platform | Status ---------|------- Linux | [![Build Status](https://travis-ci.org/AdaCore/gnatcoll-core.svg?branch=master)](https://travis-ci.org/AdaCore/gnatcoll-core) Windows | [![Build status](https://ci.appveyor.com/api/projects/status/31a7dh523xto7b9f/branch/master?svg=true)](https://ci.appveyor.com/project/github-integration-adacore/gnatcoll-core/branch/master) Dependencies ------------ This module depends on the following external components, that should be available on your system: - GPRbuild Configuring the build process ----------------------------- The following variables can be used to configure the build process: General: * `prefix`: location of the installation, the default is the running GNAT installation root. * `BUILD`: control the build options: `PROD` (default) or `DEBUG` * `PROCESSORS` : parallel compilation (default is 0, which uses all available cores) * `TARGET`: for cross-compilation, auto-detected for native platforms * `SOURCE_DIR`: for out-of-tree build * `INTEGRATED`: treat prefix as compiler installation (yes/no) this is so that installed gnatcoll project can later be referenced as predefined project of this compiler; this adds a normalized target subdir to prefix default is "no" Module-specific: * `GNATCOLL_MMAP`: whether MMAP is supported (yes/no) default is "yes"; has no effect on Windows * `GNATCOLL_MADVISE`: whether MADVISE is supported (yes/no) default is "yes"; has no effect on Windows * `GNATCOLL_ATOMICS`: atomic model (intrinsic/mutex) default is "intrinsic" To use the default options: ```sh $ make setup ``` For example, to setup GNATcoll to install a debug version in `/opt/libgnatcoll`: ```sh $ make prefix=/opt/libgnatcoll BUILD=DEBUG install ``` Building -------- GNATcoll Core Module is built using a GPR project file, to build it is as simple as: ```sh $ gprbuild gnatcoll.gpr ``` Though, to build all versions of the library (static, relocatable and static-pic) it is simpler to use the provided Makefile: ```sh $ make ``` Then, to install it: ```sh $ make install ``` Bug reports ----------- Please send questions and bug reports to report@adacore.com following the same procedures used to submit reports with the GNAT toolset itself. alire-1.2.1/deps/gnatcoll-slim/alire.toml000066400000000000000000000005111425465243200203040ustar00rootroot00000000000000name = "gnatcoll" version = "0.0" # Not really intended for distribution description = "Slim, outdated version of gnatcoll-core" [gpr-set-externals] BUILD="DEBUG" LIBRARY_TYPE="static-pic" [gpr-set-externals."case(os)"] linux = { GNATCOLL_OS = "unix" } macos = { GNATCOLL_OS = "osx" } windows = { GNATCOLL_OS = "windows" } alire-1.2.1/deps/gnatcoll-slim/appveyor.yml000066400000000000000000000026151425465243200207120ustar00rootroot00000000000000version: 1.0.{build} environment: PYTHON: C:\Python27 cache: - C:\AdaDownloads install: - ps: $env:COMPILER_DIR = "C:\AdaCompiler" - ps: $env:CACHE_DIR = "C:\AdaDownloads" - ps: $env:COMPILER_INSTALLER = $env:CACHE_DIR + "\gnat-gpl-2017.exe" - ps: md -f $env:COMPILER_DIR - ps: md -f $env:CACHE_DIR - ps: > If (Test-Path $env:COMPILER_INSTALLER) { echo compiler already in cache } Else { (new-object net.webclient).DownloadFile( 'http://mirrors.cdn.adacore.com/art/591c97f0a3f5d779ee51082d', $env:COMPILER_INSTALLER) } - ps: dir $env:CACHE_DIR - cmd: cmd /c start /wait %COMPILER_INSTALLER% /S /D=%COMPILER_DIR% - ps: $env:Path = $env:COMPILER_DIR + "\bin;" + $env:Path - cmd: cd - cmd: dir - cmd: git clone https://github.com/AdaCore/gprbuild libgpr-src - cmd: cd libgpr-src - cmd: gprbuild -p -m -j0 -XBUILD=production -XLIBRARY_TYPE=relocatable -XXMLADA_BUILD=relocatable -P gpr/gpr.gpr - cmd: gprinstall -p -f -XBUILD=production --install-name=gpr --build-var=LIBRARY_TYPE -XLIBRARY_TYPE=relocatable -XXMLADA_BUILD=relocatable --build-name=relocatable -P gpr/gpr.gpr - cmd: cd .. - cmd: > gprbuild.exe -p -m -j0 -XGNATCOLL_OS=windows -XGNATCOLL_VERSION=0.0 -XBUILD=PROD -XLIBRARY_TYPE=relocatable -XXMLADA_BUILD=relocatable -P gnatcoll.gpr build: off alire-1.2.1/deps/gnatcoll-slim/distrib/000077500000000000000000000000001425465243200177565ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/distrib/gen_gps.py000066400000000000000000000032631425465243200217560ustar00rootroot00000000000000#!/usr/bin/env python import os import os.path import re pkg_re = re.compile("^(private)?\s*package\s*(\S+)") def recursive_ls(dir): """Return the list of ads files in dir and its subdirs""" result = set() for f in os.listdir(dir): if f.endswith(".ads") \ and f.startswith("gnatcoll-"): private = False pkg = "" for l in file(os.path.join(dir, f)).readlines(): m = pkg_re.search(l) if m: private = m.group(1) pkg = m.group(2) break if not private: result.add((pkg, os.path.splitext(f)[0])) elif os.path.isdir(os.path.join(dir, f)): result = result.union(recursive_ls(os.path.join(dir, f))) return result list = recursive_ls("../src") out = file("gnatcoll/runtime.py", "wb") out.write("""XML = r''' """) for pkg, f in sorted(list): if '__' in f: # An internal package with a specific naming scheme continue menu = pkg.replace(".", "/").replace("_", "__") # Do we have a submenu ? in_front = False for pkg2, b in list: if b.startswith(f + "-"): item = menu[menu.rfind("/") + 1:] menu = menu + "/<" + item + ">" break out.write(""" Editor.edit "%(file)s.ads" %(package)s /Help/GNAT Runtime/%(menu)s GNAT Components Collection """ % {"file": f, "menu": menu, "package": pkg}) out.write("""''' import GPS GPS.parse_xml(XML) """) out.close() alire-1.2.1/deps/gnatcoll-slim/distrib/gnatcoll/000077500000000000000000000000001425465243200215615ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/distrib/gnatcoll/__init__.py000066400000000000000000000007321425465243200236740ustar00rootroot00000000000000""" This file makes the GNATCOLL documentation available from GPS """ import GPS from . import runtime XML = r""" share/doc/gnatcoll html/index.html Gnat Reusable Components User's Guide GNAT /Help/Gnat Components/Gnat Components User's Guide """ GPS.parse_xml(XML) alire-1.2.1/deps/gnatcoll-slim/distrib/gnatcoll/runtime.py000066400000000000000000000606511425465243200236260ustar00rootroot00000000000000XML = r''' Editor.edit "gnatcoll-format_columns_vertical.ads" /Help/GNAT Runtime/ GNAT Components Collection Editor.edit "gnatcoll-format_columns_vertical_xstring.ads" /Help/GNAT Runtime/ GNAT Components Collection Editor.edit "gnatcoll-any_types.ads" GNATCOLL.Any_Types /Help/GNAT Runtime/GNATCOLL/Any__Types/<Any__Types> GNAT Components Collection Editor.edit "gnatcoll-any_types-python.ads" GNATCOLL.Any_Types.Python /Help/GNAT Runtime/GNATCOLL/Any__Types/Python GNAT Components Collection Editor.edit "gnatcoll-arg_lists.ads" GNATCOLL.Arg_Lists /Help/GNAT Runtime/GNATCOLL/Arg__Lists GNAT Components Collection Editor.edit "gnatcoll-asserts.ads" GNATCOLL.Asserts /Help/GNAT Runtime/GNATCOLL/Asserts GNAT Components Collection Editor.edit "gnatcoll-atomic.ads" GNATCOLL.Atomic /Help/GNAT Runtime/GNATCOLL/Atomic GNAT Components Collection Editor.edit "gnatcoll-boyer_moore.ads" GNATCOLL.Boyer_Moore /Help/GNAT Runtime/GNATCOLL/Boyer__Moore GNAT Components Collection Editor.edit "gnatcoll-config.ads" GNATCOLL.Config /Help/GNAT Runtime/GNATCOLL/Config GNAT Components Collection Editor.edit "gnatcoll-email.ads" GNATCOLL.Email /Help/GNAT Runtime/GNATCOLL/Email/<Email> GNAT Components Collection Editor.edit "gnatcoll-email-mailboxes.ads" GNATCOLL.Email.Mailboxes /Help/GNAT Runtime/GNATCOLL/Email/Mailboxes GNAT Components Collection Editor.edit "gnatcoll-email-parser.ads" GNATCOLL.Email.Parser /Help/GNAT Runtime/GNATCOLL/Email/Parser GNAT Components Collection Editor.edit "gnatcoll-email-utils.ads" GNATCOLL.Email.Utils /Help/GNAT Runtime/GNATCOLL/Email/Utils GNAT Components Collection Editor.edit "gnatcoll-formatters.ads" GNATCOLL.Formatters /Help/GNAT Runtime/GNATCOLL/Formatters GNAT Components Collection Editor.edit "gnatcoll-gmp.ads" GNATCOLL.GMP /Help/GNAT Runtime/GNATCOLL/GMP/<GMP> GNAT Components Collection Editor.edit "gnatcoll-gmp-integers.ads" GNATCOLL.GMP.Integers /Help/GNAT Runtime/GNATCOLL/GMP/Integers/<Integers> GNAT Components Collection Editor.edit "gnatcoll-gmp-integers-io.ads" GNATCOLL.GMP.Integers.IO /Help/GNAT Runtime/GNATCOLL/GMP/Integers/IO GNAT Components Collection Editor.edit "gnatcoll-gmp-integers-misc.ads" GNATCOLL.GMP.Integers.Misc /Help/GNAT Runtime/GNATCOLL/GMP/Integers/Misc GNAT Components Collection Editor.edit "gnatcoll-gmp-integers-number_theoretic.ads" GNATCOLL.GMP.Integers.Number_Theoretic /Help/GNAT Runtime/GNATCOLL/GMP/Integers/Number__Theoretic GNAT Components Collection Editor.edit "gnatcoll-gmp-integers-random.ads" GNATCOLL.GMP.Integers.Random /Help/GNAT Runtime/GNATCOLL/GMP/Integers/Random GNAT Components Collection Editor.edit "gnatcoll-gmp-integers-root_extraction.ads" GNATCOLL.GMP.Integers.Root_Extraction /Help/GNAT Runtime/GNATCOLL/GMP/Integers/Root__Extraction GNAT Components Collection Editor.edit "gnatcoll-gmp-lib.ads" GNATCOLL.GMP.Lib /Help/GNAT Runtime/GNATCOLL/GMP/Lib GNAT Components Collection Editor.edit "gnatcoll-gmp-random_state.ads" GNATCOLL.GMP.Random_State /Help/GNAT Runtime/GNATCOLL/GMP/Random__State GNAT Components Collection Editor.edit "gnatcoll-geometry.ads" GNATCOLL.Geometry /Help/GNAT Runtime/GNATCOLL/Geometry GNAT Components Collection Editor.edit "gnatcoll-io-native.ads" GNATCOLL.IO.Native /Help/GNAT Runtime/GNATCOLL/IO/Native GNAT Components Collection Editor.edit "gnatcoll-io-remote.ads" GNATCOLL.IO.Remote /Help/GNAT Runtime/GNATCOLL/IO/Remote/<Remote> GNAT Components Collection Editor.edit "gnatcoll-io-remote-unix.ads" GNATCOLL.IO.Remote.Unix /Help/GNAT Runtime/GNATCOLL/IO/Remote/Unix GNAT Components Collection Editor.edit "gnatcoll-io-remote-windows.ads" GNATCOLL.IO.Remote.Windows /Help/GNAT Runtime/GNATCOLL/IO/Remote/Windows GNAT Components Collection Editor.edit "gnatcoll-iconv.ads" GNATCOLL.Iconv /Help/GNAT Runtime/GNATCOLL/Iconv GNAT Components Collection Editor.edit "gnatcoll-json.ads" GNATCOLL.JSON /Help/GNAT Runtime/GNATCOLL/JSON GNAT Components Collection Editor.edit "gnatcoll-memory.ads" GNATCOLL.Memory /Help/GNAT Runtime/GNATCOLL/Memory GNAT Components Collection Editor.edit "gnatcoll-mmap.ads" GNATCOLL.Mmap /Help/GNAT Runtime/GNATCOLL/Mmap/<Mmap> GNAT Components Collection Editor.edit "gnatcoll-paragraph_filling.ads" GNATCOLL.Paragraph_Filling /Help/GNAT Runtime/GNATCOLL/Paragraph__Filling GNAT Components Collection Editor.edit "gnatcoll-pools.ads" GNATCOLL.Pools /Help/GNAT Runtime/GNATCOLL/Pools GNAT Components Collection Editor.edit "gnatcoll-projects.ads" GNATCOLL.Projects /Help/GNAT Runtime/GNATCOLL/Projects/<Projects> GNAT Components Collection Editor.edit "gnatcoll-projects-aux.ads" GNATCOLL.Projects.Aux /Help/GNAT Runtime/GNATCOLL/Projects/Aux GNAT Components Collection Editor.edit "gnatcoll-promises.ads" GNATCOLL.Promises /Help/GNAT Runtime/GNATCOLL/Promises GNAT Components Collection Editor.edit "gnatcoll-python.ads" GNATCOLL.Python /Help/GNAT Runtime/GNATCOLL/Python GNAT Components Collection Editor.edit "gnatcoll-ravenscar.ads" GNATCOLL.Ravenscar /Help/GNAT Runtime/GNATCOLL/Ravenscar/<Ravenscar> GNAT Components Collection Editor.edit "gnatcoll-ravenscar-multiple_queue_cyclic_server.ads" GNATCOLL.Ravenscar.Multiple_Queue_Cyclic_Server /Help/GNAT Runtime/GNATCOLL/Ravenscar/Multiple__Queue__Cyclic__Server GNAT Components Collection Editor.edit "gnatcoll-ravenscar-multiple_queue_sporadic_server.ads" GNATCOLL.Ravenscar.Multiple_Queue_Sporadic_Server /Help/GNAT Runtime/GNATCOLL/Ravenscar/Multiple__Queue__Sporadic__Server GNAT Components Collection Editor.edit "gnatcoll-ravenscar-simple_cyclic_task.ads" GNATCOLL.Ravenscar.Simple_Cyclic_Task /Help/GNAT Runtime/GNATCOLL/Ravenscar/Simple__Cyclic__Task GNAT Components Collection Editor.edit "gnatcoll-ravenscar-simple_sporadic_task.ads" GNATCOLL.Ravenscar.Simple_Sporadic_Task /Help/GNAT Runtime/GNATCOLL/Ravenscar/Simple__Sporadic__Task GNAT Components Collection Editor.edit "gnatcoll-ravenscar-sporadic_server.ads" GNATCOLL.Ravenscar.Sporadic_Server /Help/GNAT Runtime/GNATCOLL/Ravenscar/Sporadic__Server GNAT Components Collection Editor.edit "gnatcoll-ravenscar-sporadic_server_with_callback.ads" GNATCOLL.Ravenscar.Sporadic_Server_With_Callback /Help/GNAT Runtime/GNATCOLL/Ravenscar/Sporadic__Server__With__Callback GNAT Components Collection Editor.edit "gnatcoll-ravenscar-timed_out_sporadic_server.ads" GNATCOLL.Ravenscar.Timed_Out_Sporadic_Server /Help/GNAT Runtime/GNATCOLL/Ravenscar/Timed__Out__Sporadic__Server GNAT Components Collection Editor.edit "gnatcoll-ravenscar-timers.ads" GNATCOLL.Ravenscar.Timers /Help/GNAT Runtime/GNATCOLL/Ravenscar/Timers/<Timers> GNAT Components Collection Editor.edit "gnatcoll-ravenscar-timers-one_shot_timer.ads" GNATCOLL.Ravenscar.Timers.One_Shot_Timer /Help/GNAT Runtime/GNATCOLL/Ravenscar/Timers/One__Shot__Timer GNAT Components Collection Editor.edit "gnatcoll-ravenscar-utils.ads" GNATCOLL.Ravenscar.Utils /Help/GNAT Runtime/GNATCOLL/Ravenscar/Utils GNAT Components Collection Editor.edit "gnatcoll-readline.ads" GNATCOLL.Readline /Help/GNAT Runtime/GNATCOLL/Readline GNAT Components Collection Editor.edit "gnatcoll-refcount.ads" GNATCOLL.Refcount /Help/GNAT Runtime/GNATCOLL/Refcount/<Refcount> GNAT Components Collection Editor.edit "gnatcoll-refcount-weakref.ads" GNATCOLL.Refcount.Weakref /Help/GNAT Runtime/GNATCOLL/Refcount/Weakref GNAT Components Collection Editor.edit "gnatcoll-remote.ads" GNATCOLL.Remote /Help/GNAT Runtime/GNATCOLL/Remote/<Remote> GNAT Components Collection Editor.edit "gnatcoll-remote-db.ads" GNATCOLL.Remote.Db /Help/GNAT Runtime/GNATCOLL/Remote/Db GNAT Components Collection Editor.edit "gnatcoll-sql.ads" GNATCOLL.SQL /Help/GNAT Runtime/GNATCOLL/SQL/<SQL> GNAT Components Collection Editor.edit "gnatcoll-sql-exec.ads" GNATCOLL.SQL.Exec /Help/GNAT Runtime/GNATCOLL/SQL/Exec/<Exec> GNAT Components Collection Editor.edit "gnatcoll-sql-exec-tasking.ads" GNATCOLL.SQL.Exec.Tasking /Help/GNAT Runtime/GNATCOLL/SQL/Exec/Tasking GNAT Components Collection Editor.edit "gnatcoll-sql-inspect.ads" GNATCOLL.SQL.Inspect /Help/GNAT Runtime/GNATCOLL/SQL/Inspect GNAT Components Collection Editor.edit "gnatcoll-sql-orm.ads" GNATCOLL.SQL.Orm /Help/GNAT Runtime/GNATCOLL/SQL/Orm/<Orm> GNAT Components Collection Editor.edit "gnatcoll-sql-orm-impl.ads" GNATCOLL.SQL.Orm.Impl /Help/GNAT Runtime/GNATCOLL/SQL/Orm/Impl GNAT Components Collection Editor.edit "gnatcoll-sql-postgres.ads" GNATCOLL.SQL.Postgres /Help/GNAT Runtime/GNATCOLL/SQL/Postgres/<Postgres> GNAT Components Collection Editor.edit "gnatcoll-sql-postgres-gnade.ads" GNATCOLL.SQL.Postgres.Gnade /Help/GNAT Runtime/GNATCOLL/SQL/Postgres/Gnade GNAT Components Collection Editor.edit "gnatcoll-sql-ranges.ads" GNATCOLL.SQL.Ranges /Help/GNAT Runtime/GNATCOLL/SQL/Ranges GNAT Components Collection Editor.edit "gnatcoll-sql-sessions.ads" GNATCOLL.SQL.Sessions /Help/GNAT Runtime/GNATCOLL/SQL/Sessions GNAT Components Collection Editor.edit "gnatcoll-sql-sqlite.ads" GNATCOLL.SQL.Sqlite /Help/GNAT Runtime/GNATCOLL/SQL/Sqlite/<Sqlite> GNAT Components Collection Editor.edit "gnatcoll-sql-sqlite-gnade.ads" GNATCOLL.SQL.Sqlite.Gnade /Help/GNAT Runtime/GNATCOLL/SQL/Sqlite/Gnade GNAT Components Collection Editor.edit "gnatcoll-sql_fields.ads" GNATCOLL.SQL_Fields /Help/GNAT Runtime/GNATCOLL/SQL__Fields GNAT Components Collection Editor.edit "gnatcoll-sql_impl.ads" GNATCOLL.SQL_Impl /Help/GNAT Runtime/GNATCOLL/SQL__Impl GNAT Components Collection Editor.edit "gnatcoll-scripts.ads" GNATCOLL.Scripts /Help/GNAT Runtime/GNATCOLL/Scripts/<Scripts> GNAT Components Collection Editor.edit "gnatcoll-scripts-files.ads" GNATCOLL.Scripts.Files /Help/GNAT Runtime/GNATCOLL/Scripts/Files GNAT Components Collection Editor.edit "gnatcoll-scripts-impl.ads" GNATCOLL.Scripts.Impl /Help/GNAT Runtime/GNATCOLL/Scripts/Impl GNAT Components Collection Editor.edit "gnatcoll-scripts-projects.ads" GNATCOLL.Scripts.Projects /Help/GNAT Runtime/GNATCOLL/Scripts/Projects GNAT Components Collection Editor.edit "gnatcoll-scripts-python.ads" GNATCOLL.Scripts.Python /Help/GNAT Runtime/GNATCOLL/Scripts/Python GNAT Components Collection Editor.edit "gnatcoll-scripts-shell.ads" GNATCOLL.Scripts.Shell /Help/GNAT Runtime/GNATCOLL/Scripts/Shell GNAT Components Collection Editor.edit "gnatcoll-scripts-utils.ads" GNATCOLL.Scripts.Utils /Help/GNAT Runtime/GNATCOLL/Scripts/Utils GNAT Components Collection Editor.edit "gnatcoll-storage_pools.ads" GNATCOLL.Storage_Pools /Help/GNAT Runtime/GNATCOLL/Storage__Pools/<Storage__Pools> GNAT Components Collection Editor.edit "gnatcoll-storage_pools-alignment.ads" GNATCOLL.Storage_Pools.Alignment /Help/GNAT Runtime/GNATCOLL/Storage__Pools/Alignment GNAT Components Collection Editor.edit "gnatcoll-storage_pools-headers.ads" GNATCOLL.Storage_Pools.Headers /Help/GNAT Runtime/GNATCOLL/Storage__Pools/Headers GNAT Components Collection Editor.edit "gnatcoll-strings.ads" GNATCOLL.Strings /Help/GNAT Runtime/GNATCOLL/Strings GNAT Components Collection Editor.edit "gnatcoll-strings_impl.ads" GNATCOLL.Strings_Impl /Help/GNAT Runtime/GNATCOLL/Strings__Impl GNAT Components Collection Editor.edit "gnatcoll-symbols.ads" GNATCOLL.Symbols /Help/GNAT Runtime/GNATCOLL/Symbols GNAT Components Collection Editor.edit "gnatcoll-templates.ads" GNATCOLL.Templates /Help/GNAT Runtime/GNATCOLL/Templates GNAT Components Collection Editor.edit "gnatcoll-terminal.ads" GNATCOLL.Terminal /Help/GNAT Runtime/GNATCOLL/Terminal GNAT Components Collection Editor.edit "gnatcoll-traces.ads" GNATCOLL.Traces /Help/GNAT Runtime/GNATCOLL/Traces/<Traces> GNAT Components Collection Editor.edit "gnatcoll-traces-syslog.ads" GNATCOLL.Traces.Syslog /Help/GNAT Runtime/GNATCOLL/Traces/Syslog GNAT Components Collection Editor.edit "gnatcoll-tribooleans.ads" GNATCOLL.Tribooleans /Help/GNAT Runtime/GNATCOLL/Tribooleans GNAT Components Collection Editor.edit "gnatcoll-utils.ads" GNATCOLL.Utils /Help/GNAT Runtime/GNATCOLL/Utils GNAT Components Collection Editor.edit "gnatcoll-vfs.ads" GNATCOLL.VFS /Help/GNAT Runtime/GNATCOLL/VFS GNAT Components Collection Editor.edit "gnatcoll-vfs_types.ads" GNATCOLL.VFS_Types /Help/GNAT Runtime/GNATCOLL/VFS__Types GNAT Components Collection Editor.edit "gnatcoll-vfs_utils.ads" GNATCOLL.VFS_Utils /Help/GNAT Runtime/GNATCOLL/VFS__Utils GNAT Components Collection Editor.edit "gnatcoll-xref.ads" GNATCOLL.Xref /Help/GNAT Runtime/GNATCOLL/Xref/<Xref> GNAT Components Collection Editor.edit "gnatcoll-xref-database.ads" GNATCOLL.Xref.Database /Help/GNAT Runtime/GNATCOLL/Xref/Database GNAT Components Collection Editor.edit "gnatcoll-xref-database_names.ads" GNATCOLL.Xref.Database_Names /Help/GNAT Runtime/GNATCOLL/Xref/Database__Names GNAT Components Collection ''' import GPS GPS.parse_xml(XML) alire-1.2.1/deps/gnatcoll-slim/docs/000077500000000000000000000000001425465243200172465ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/docs/Makefile000066400000000000000000000110351425465243200207060ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GNATColl.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GNATColl.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/GNATColl" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GNATColl" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex LATEXOPTS="-interaction=errorstopmode" all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." alire-1.2.1/deps/gnatcoll-slim/docs/adacore_transparent.png000066400000000000000000000151101425465243200237710ustar00rootroot00000000000000‰PNG  IHDRª3“ tEXtSoftwareAdobe ImageReadyqÉe<êIDATxÚì]xÕµ>3[$Y²dÙ–-Ù8Æ6Œ©ǘ’$ „ÄSbƒß ð¤‘Nz!¼pxÄ”4 <Ó›!‡ÀWܰd«n›yçÌü£½ºº³Ú]Éâ} ó}çÓîìÌ[þ{Îν3ŠÒÜÅôϱþ޵ ß+X?Ïú‡»CÆ%*‹ÑwN›E%1Ê8. ÉàI´ˆk*YG²:Ê1‹õÖ®w©%¬qÔK=öÿM¤ŸªX„îÇZƒ‰ÅDkC_®…ndmjáò{Ö³XÛ•cå¬?býÖÐÜ7ÊÁ¬ X?ÂZ pZùØq€v'ëÖÞ¯hxþ4Ö+à 4p¿Ã‡0ÙC&³þ‘õuÖ+Ye“'HE"¬ãXgä4ÔüäÜ.uëg†°ÙMîb}ƒunŽ~N±6²naÝ̺uF«yzÈõç/3•Ï.:4¢›Çzëû¤û³þ‰õˆß·²ÞÇú ëJÖ] ··à¡êXaÍúIÖѬK‡€šŸHÇ |_Ãz¯ÆKå÷²þó}ÚŸ2‘ÿî]—¿²ÞÆúkKŽ2‚`ê5Ö;пÓT ¹þ±V=()¨ÿ2”ê9˜2}6mбv‚÷®GßåC!,62†lÄXÖÃñW‚ê'‘½ÈU?9¿õ‹`\›P¿5!¼€:ÖÁ>¨|^ˆô\Íý¿÷@ç%§³^®[nø]:úyÖëYïkXˆÈêÕq¬°ƒÉ 9Wû2ë¬÷øV5BÿØÙLK¦Èf ëºÞ2êWATy AÕ`Éñ¬—€fÔ…œ“P…²-w“ ŒñX\'ãpèHë—X¿ð©êw†òdîjÖO¿ØaÇgYë§ uýŸÔbfŽ*·kßź~ªÀÎàüà;)¤Áä:v,n*ò?ŠHZ@t>,a$ÇùÃpŸ»Q¯éžûom£–Öª×uû HÒågƒÐ£žD Q—ãÜèɵäçw¿K~¾—BŒP½©¸F&ô(ü6™‹j 5ÉïUÖ‹r€4À¢ô÷ŸÑçû Ô‹ AT»vìCúäÃtø  g„üî¢óô §‘ŸŸ’Ç=$à™f(w,ÿ›ä/UfBê·”ZCI‡Z:<[¬àþº5kÿÄ €TèÆã¬gÆ1×6¸V]0ßøM5üž4Œqté ÏëVTÊ¿ÔM-û L®eðÈú¸J›$ÅùÁ|]¿E3µ¸7ÄM® uJµTäqwRïeEÐSp¡¯âÕ¬G²žÃ: ®ü0Õ¥ÜK“Ï¡“Rè„Ç•ŽjCÛJQÖ§àJÇ*×ïËúKrœ ·ín¥ý÷#>ØpŸG¤ß†eÔE¨ÊmÈÛp§5è³€¨c.}÷¨Ã6v,òu :FÛÀé«À5 Öð!ôY mðL×+ŽBÇŽµø¸2†²Áè¬'ʘõÔKµïOÀ}šä4‹( Z€™&G‘Ÿ×—eÿ ¹ÖpÍ ¬7a å8œª/Ùˆö,Ëä$1)D—€&¨}[Õ¿®nh¾ÿ„Œ×Ï0”±·—:ç@*“ø  d#,¡¸Ö»@Y™‚¶žªñBÝÊ`¿ý†õ䯬e°ÀX,Öúm&É+!}þT‚òi†R(ÆÕvAÔIÚ±‡sœÿ”XsÁõÂd¡¤2Ð'‡€T•ÑyÍy° ­Dâo!XÐe^:;„£ €Ù¼A*ô§†ã—‡€” mÞœˆVÝ¢ÎB%mü&ý¥,W1n'i€ÿêòcÖ¿02ÉîÃÚé±<Çù†ˆïð “Ì2ðßp¯|÷_¾‚Žß["Êë=)¿}ì–ÖŽáÉTIJ,=8h§ÂWž ‘kبrkH¤&Âréò-ÍC„¥ÿ¾8Å$ã ô9Î7É5”ݤ´.ÉT}'Ô -já¯]}ä`»-“SŠ ZY˜^ÙKÀpz[v«’RéÇ‘ U‰ÁjgöR]&2 mEf<‹Pµ9}\·.?LÎÔŒ›LÜ› ¬ÛzÎŽ êCziIƒ°ÖºšI=wÞyºÓ \eQ.®åC9Ü›*†\l™càÑ>R^ý‘Ù†tÐÝH*­ˆ)L^4—ü|3Wu~×Ó„[ †`&Òin ©SÎá& 7pÇ¥š«8ƒéj7̬§Èe êòj?]t!VSV“ÎBÇ–,¦*‰^Ó³3iËšÿ„²’úŒ“ÑûN¶î N6ÛÐòêѶ^”’ùÙ7™°Ûs”7ÒTÝ€ì Ž\è>è¨é‚c 7ÔwÿH^îÐntÜÊËønÚ¯ÙŸÁÍ÷ÑŽ‘Ú:°Ð÷4YJe¬TÚájí2\$¢ë–1>ÜÞò¤]) ¨U9€š¡Ü+€Õ†I?`|ÝÔ 3I·v-H+@ £ {S"ˆÐyù¿ÉÏ1 íØ•o`–H¥¥ å\òõ{¡þö—gêo5ŒÆ0—A€Çò˜o ì|½ ”¹Cj™!ˆzYs1rá6¸þTˆE×Ó"Âo’¿Ø´ƒgÄwº*§¢O¹æk¬¿*:ðÙíjn§é-Éù^­ýzÊ>åÅp ³Yäíö•ezü2<|‹Òkoí  ;)î§£åÑŒŸΜŒ +ûa?]`ìòDBxÿu†1¼3O° §ý³![ [ÿ ÀD’Ô–l*Ò7æÈŽ*Ù˜2¾Àò‚çØºzžá¤{(¥ògÃñ`çö!îFhÈ °Dâ¢&ÂÍ ç™ƒëRhÂ2êý PT)g—!à û`¦žùÂ*Dð’%¸AI·i¶4È'ºtï›(í8dùO¦Š¥º-$Ý%í…É#.FÛ$ ™z>7 œûX¨Õ `G+–o•Vv5â‰ëA9ª•zVã˜L"YrÕd;ã×K¯BÚÏħWÁΆW«ÃD•%âihç…0BÁ˜Es ÊWhl#:¶m*~¬³š,þ7xeR$·Sø{«œçTqƒ»‘MïiYƒË+ñY2o5K!šÞŽz|i´ ®˜_Ô®ûyÒDŠ.úðatèäñü±;ó2Vnb–ÈEŒ–T ]­L(é³O†”Õ¨x’ [Óf™3˜\¾ˆ3µ”ÞA!Ù ¡x7Sø~ä$ÆÕU KÜ%¾|Ά;ipÙm4ÃÖ¸¨¬õŸªpÈùèøÎz2 .3®åäîÀ›©wB\ÍŠUÿ²ÁÒI§L¡ì#7µ PÖ‹¨÷EÖ}Û-Û°ƒR\)oQyå‰õËgÃL•kåGݕ߂q»Ñàf#Zg@k ïóßÈÂ즽#2QO‚‘Ê„dk*1éª(ûx·.³œ€4bÀ¥â¿À Ͻ…²o®kÄlš§ÍÖ aúe#p®ÓIpØ#` ÒÐm¸W#ePåW Pî•(ñ.—Á¯Ü žÝ¦Ô=k¹#QÚ´±þµ¹ž¢%edÙQr}° YŒÁ e[Ý&ÊýÛAjp)øò× Þà pàïÀ…çJҧѶ«pÍU”;ù¾GÁ…|n2õ›´×ŽÄ¼¿Úu$èÌ ,¬ÝâÑÿ#´8pý£µ ¸ì@®½Ç0{\ë5zÇ2À”å¬y,øÛŠ+®GG/'óû*qŸà¹ÎÁàá O«$Ë{/!Ó‘özÄ-»Ã+ßå‘4Í)k£iãªi⸲ªêÈ.eåÁ³l²œ 9Nw¬'AÌ~à¤û‚/VâNí˜ ;á¶ßB;{l%´,‡Þ) [¨ÃÁñ„rŒÆ¤Ø‰¶I»Þ4MÛŽËJ™”Z®Úæ-V˜²-Çéh¢ÔÖU­C±qþâ¢+™ŒqT¢ŽÓà!†Sv»d#ºÚÙ30x7ßá0LÖŽìÒš.öÖ™Hï̓êv§ ó¿O÷4´²eö¸‡‹cø=ÂãéDzžã±Hu`ß;º™&W´SŸ+®?•f÷/£HiÅËÇÍ TÖP$^N[—A+@°Êk,®·Ë5Û9ß³\ÉN9‹Üã2“ÖÎAÃd‚èïÇr3Þ…n°³J™®¼Ÿ ™©KG3Åk&“뀥^…½ˆÓ¶›:6¿Léæm䦻<à–eü•TPdø(ŠÇ'³wqÂËêK‚>’>‰¾« 劜=º‰®l¡4÷rG:F ‰8Õ'c´5£zÇ¢(¯‹f耲.ϼÞ^æZFű{:”úCFÄviJpÄú’g‘Æ‚K;¶Jùä Æ´}`†QÚ›\ÝèáŠmÿ»]€#–É ´Æò(ùÞ‚ë÷€ÚÆ+áÝ/^.@ezÓÕìyŸ ýö ‚”kxTe;}±¶žêz‚”×#üÛùþ4ˆ·¬¹O À&@‘ëSŠfœì±´$â[G9?Pò÷Ûþ¹ÓÈé®âßÊYkpL¢Sõqœ[p|¸w_¤¥X¬¨WæGã»”½Ñ6»DØ›-Ûó^GNRž_ÅÀYÄfµV¸¬ÍçÉ_±š¢v´¤H+,S3Ñ´™­c«wŽw¾ù8ƒôqÜw²›å|¿¼XnˆR^÷ﮇÔ.-¢-´Ão_ mŠz4HΠÝÉö]ìÚ}:!m¶ý~ˆ&H«K“tJMƒžTo·ù=X®có|iRr¢êîó¤á.%°P×5º¥³°"ÕŽ”Ž h"QV³–NRTKáWV{9UIˆK¾ðý\ä-¯GÙ Q×i¹áñHý i¬Ká=®6¬®¥•쉕m»í ¢–s\Š~úÚ7‰zî³ÐOÉiº8<„‹ºÆÈ¼g"(+aÈ•*©Ãð{ØQ×UB[mBvGƒgQ¹KF ?´ÄÂoû8V™‚§#×RöŸ2•¥Å§¾¸²ûP§ãø,Qþ˜zo –޹Vì‘êz  êÀb°êbõ¾ª¹qU®Â’ ¬½Ýï=]&ÆŸ¨÷žíø;e7‰ŒF’^v!}ÖðBL’;ñ=x=Ï‘†:‡Áý^Ʋm° îBä6·biöë”ýKaTîq1Vüäü›”•Æpî³H¥=¬ÔG&ðJ”±}+nΓEŠÇЖ§‘‚œŠº~YiË/Ñw¥D4ˆ®ßòƒ‘<²³¹ê$ï¸$«FÁFï[)û…Òß X‡äûÛ˜ È+1X_E~3 @¯Â@} Ñ­÷Ñæ_(ûôÀÂ"ze$&Dðb‰]8v øøF¬"ý ¼ãl°J+ïX,–Üe¸×™XÈ)ÅÂëXwÿ2¬çlò_¤ö"úðSË"xƒË°¬^ŠþOV¸äº_ã>ãqý©˜\Wb,Ôïrä«ïÀ÷ïÐ5XÀ°1a/§ì‹ˆ¨N*Q>GÓ'V÷ûm7‹0CoRÈ“°âô :q­’Ô×-jn¿ ç.PŽÎïR–!oU¾Lq{Á4 &ÈðÑg0I&ЩÇéà’‘¿™û&e™øf d3¨… ìÏ01~ƒvOÓU*`ÉMKÑŸÀßo`~ í½„²¥,p‚DÏ£ÁË*jºð<èÎÀ…gb²ß…þ˜¥-™g°.c®ÀÓˆ?¤_åå²×BöQœ€ú<œõÊ#‰îú9ʾ4–¢…µ ~Õ?¶±FÙpÖà³ÇcV AŒn[1ˆ“°r#ß¡ì?ÇPm}\Ño1(û„f„²/» îþHeAª K9m²§´Á¼à‘ëqø«¾Ô"Ø?0L[RÝÏqhȪQö±ôàÿ®Ö .eŸË À¸C‹ TÙ­-·@*#ÛO¦žoô äMe Ó ½çáÚveÂô#˜b¼]T»›Æ”$|—žC$?c~šrŒiXŠÙ€?¢¸ßý ä'8ðù¤~ˆ‰æ(ÿ'p[sp}.r*"þ°€Ã`e…Ž|“òªUÖòÃ^¼€#ØÒ7“D&A°÷´^»æo˜°âuæÃ»TÀ »žN‡<.öi€.¢ÜÓÊÈIUO²å ¼{æQÏý¯a)‡MèϹè¿%¤lÝ,¨ŽEÇT¶Ñ>å”áÏù¼l©KjiMüÕV¢üFI×bê‘9ø4õÞ4ýXùp·Û©çëÁõ{n€•þ®Ò_Á«(/W¬a°Ž}‰²ÛöìmŒäø-¸n%&ÖµhO¼Âï©÷3N‹aÝÏGP¹ùâ‡1‘ÎÇ]€ú¶‚£vá~¶æìc²¸e–Tê÷${.hÉtÅ{DBúXý~/¨Gš´—±EèàÓŠ2h'j¡ véŽ@+-Hàloi®íQtDðªôÇ`5ž‡Å6ØÜ·¡sµøÙ W]‰ÙûWÜ7+¼°x;RTáÜ:tèCPïxßF£—#erIdÞ4üÖ‰¶6(4`@·ÜðÇËQ2'I´gê»AY¶§Þ•ðLi[ƒº§Q‡7•:-ŵóQæã0׃;õ‰º|Ù…1NÚ¼NI»IÛ‚§_¦{Š´§+Š[™bW?¿®žê†u乌8$ï!ùhÏx¥xõÇœ]‚ø€úÏQ‡äý*]°œ XfTFÀºŒ²ÿ&¨[þO€ùòKXWóIEND®B`‚alire-1.2.1/deps/gnatcoll-slim/docs/boyer_moore.rst000066400000000000000000000047741425465243200223350ustar00rootroot00000000000000.. _Searching_strings: ********************************** **Boyer-Moore**: Searching strings ********************************** .. highlight:: ada .. index:: Boyer-Moore .. index:: search Although the Ada standard provides a number of string-searching subprograms (most notably in the `Ada.Strings.Fixed`, `Ada.Strings.Unbounded` and `Ada.Strings.Bounded` packages through the `Index` functions), these subprograms do not in general provide the most efficient algorithms for searching strings. The package **GNATCOLL.Boyer_Moore** provides one such optimize algorithm, although there exists several others which might be more efficient depending on the pattern. It deals with string searching, and does not handle regular expressions for instance. This algorithm needs to preprocess its key (the searched string), but does not need to perform any specific analysis of the string to be searched. Its execution time can be sub-linear: it doesn't need to actually check every character of the string to be searched, and will skip over some of them. The worst case for this algorithm has been proved to need approximately 3 * N comparisons, hence the algorithm has a complexity of O(n). The longer the key, the faster the algorithm in general, since that provides more context as to how many characters can be skipped when a non-matching character is found.. We will not go into the details of the algorithm, although a general description follows: when the pattern is being preprocessed, Boyer-Moore computes how many characters can be skipped if an incorrect match is found at that point, depending on which character was read. In addition, this algorithm tries to match the key starting from its end, which in general provides a greater number of characters to skip. For instance, if you are looking for "ABC" in the string "ABDEFG" at the first position, the algorithm will compare "C" and "D". Since "D" does not appear in the key "ABC", it knows that it can immediately skip 3 characters and start the search after "D". Using this package is extremely easy, and it has only a limited API:: declare Str : constant String := "ABDEABCFGABC"; Key : Pattern; Index : Integer; begin Compile (Key, "ABC"); Index := Search (Key, Str); end `Search` will either return -1 when the pattern did not match, or the index of the first match in the string. In the example above, it will return 5. If you want to find the next match, you have to pass a substring to search, as in:: Index := Search (Key, Str (6 .. Str'Last)); alire-1.2.1/deps/gnatcoll-slim/docs/building.rst000066400000000000000000000056751425465243200216120ustar00rootroot00000000000000.. _Building_GNATColl: ***************** Building GNATColl ***************** In the instructions detailed below, it is assumed that you have unpacked the GNATColl package in a temporary directory and that `installdir` is the directory in which you would like to install the selected components. It is further assumed that you have recent functional GNAT compiler, as well as gprbuild. .. _Configuring_the_build_environment: Configuring the build environment ================================= The first step is to configure the build environment. This is done by running the `make setup` command in the root directory of the GNATColl tree. This step is optional if you are satisfied with default values. On Windows, this requires a properly setup Unix-like environment, to provide Unix-like tools. The following variables can be used to configure the build process: General: *prefix* Location of the installation, the default is the running GNAT installation root. *INTEGRATED* Treat prefix as compiler installation: yes or no (default). This is so that installed gnatcoll project can later be referenced as a predefined project of this compiler; this adds a normalized target subdir to prefix. *BUILD* Controls the build options : PROD (default) or DEBUG *PROCESSORS* Parallel compilation (default is 0, which uses all available cores) *TARGET* For cross-compilation, auto-detected for native platforms *SOURCE_DIR* For out-of-tree build *ENABLE_SHARED* Controls whether shared and static-pic library variants should be built: yes (default) or no. If you only intend to use static libraries, specify 'no'. Module-specific: *GNATCOLL_MMAP* Whether MMAP is supported: yes (default) or no; this has no effect on Windows where embedded MMAP implementation is always provided. *GNATCOLL_MADVISE* Whether MADVISE: yes (default) or no; this has no effect on Windows where MADVISE functionality is unavailable *GNATCOLL_ATOMICS* Selects atomics model: intrinsic (default) or mutex. .. _Building_GNATColl: Building GNATColl ================= GNATCOLL Core Module can be built using a GPR project file, to build it is as simple as: $ gprbuild gnatcoll.gpr Though, to build all versions of the library (static, relocatable and static-pic) it is simpler to use the provided Makefile: $ make .. _Installing_GNATColl: Installing GNATColl =================== Installing the library is done with the following command:: make install Note that this command does not try to recompile GNATColl, so you must build it first. This command will install all library variants that were built. Your application can now use the GNATColl code through a project file, by adding a ``with`` clause to :file:`gnatcoll.gpr`. If you wish to install in a different location than was specified at configure time, you can override the "prefix" variable from the command line, for instance:: make prefix=/alternate/directory install This does not require any recompilation. alire-1.2.1/deps/gnatcoll-slim/docs/classes.png000066400000000000000000000714311425465243200214170ustar00rootroot00000000000000‰PNG  IHDR}φ& IDATxœìg\Ë×Ç'@èH‘&]¤Y)¢bƒ ]l(ED/vQÄvÅ‚í*övízUT¬ˆŠ b±¡‚( Š‚t¤†yŠM¡PhªªÎ&¬µÑÐp}øðBÈÌlB¨ºº–B¡ÉÈ8655mÞ|^]ÝEHhœššóŽ—šuïìÙ?>Üëéi‹úøñ–•`f¶HTÔF^~’Ÿß‘ÆF'Bwï¾22ò¶VVvZ¾üH]]ѪªÖ¹à|&µ€UÇj …F¡ÐÂÂ^"„®^}J¡Ð¬­W´ýWüÁÓ§ï--—KI9P©Vêê.S¦¬old4[êñãx …¦¦æÌ%O~~ …B“”´ç½HKÁª Phùù%mh ú»äê „22òi4_11{ûáýå=`€VJJ†­íªúúF77KEEÙÇãËʪBß¾åìÝ{ÔTII…¦à;/gÍÚ‘²pádÿSÂÂÔg‰Š ;vgË–óFF:‹OÉÌ,øü9“‹ŠÊ’’¾#„ ê‹úô)ÃÁaMïÞÒûö-¾~=úàÁUU…1c“:˜˜îä´ADDxÉ’)11I‡…Ô×7  …scÜ8Vu8ŸããÓˆfͲco WWËë×£n܈ž4iô­[ÏBXè~tä Duu ¿K΄ #ôQSS@ÕÔÔݺõ|̘¥tzù™3uu 6W®:´ôÓ§ó::ª! ¥ììã©©©>Δ¦¦ÒÞ½‹nÞÜÖ«—DAAijjÖìÙö!*UpÃÏU«ÜRR2°Z$%ÅV­r»xq}³î)(LVTœòþ}Ú˜1ƒ}}§!„þù'¢®®ÁÇÇÉËË~ýz„ÐíÛÏ99ô€ÁhZ´hò>7nlF?ÿ 1ñ7p>“ZhhhdoŠC‡– „…½ª¨¨¾ÿ„„è´i­ÿJ€éÈ2ö(¬ˆŽÎÌÅ‹HJÚ«©9?yòséèÑ[}úL•’r3ƇB¡ãÓÒ“ÊÉ¡›˜Ì“”´§R­´µg`Cq-­뛚ÎG}ùò“ÕS'5ÎÅmâxÞo|] Ä]Žøú:geÝøôéü¶mÞ ¥´´òéÓ÷ÙÙE!=\f11aUUyŽí)(( ''…ªªªÁš>}œ°0555kÙ²Ãzz¼Œ3»¸ÐBK–8II‰#„²² BëÖ–’r°³[*,,ãä@^^1BH[»BHSS!TSSgk;Œw7H-””T²7…²²œÝðŠŠê5kNVVþš:Õ\BB´ÙS€®û™¬ì„©S7bÿ§±²˜˜¤É“GÏëXRRÉ>BV]]K4… PÙÛÏÊ*œ5kGc#cáÂÉ!aaê¶mÞ6Ì"IOÏ=~üNuumN}õêã¡çÏ“||”ÚÚãr_âNeå/„ТE“ýü\ëן¹ÿM[ÕHjœ“lBèçÏ„˜˜È”)c¸¸ó™Ô×ÙÁzɧNÝEyyÙ· ½ KÑ‘#dÄÚUTäóòBoßÞŽJOÏE]»…òò²»ysëºu­;) ÷ׯ?ùù%55u¦¦ú _û÷×äÅÃg=~÷òåGW×ͯ_ûãñ'N„]¼øðׯZYY©ÌÌ&“¹fÍ R¼¼ì޽uôèí_¿ê^¾LFÍžm¿téa.nÈÊJ²ûLjJÅ_N“&–“ëURR¡®®hiiÄ{û@—Ã××Ù××9%%#4ôy@ÀY^FȸXè**ª«ªjš}”+%%¦¬,gl¬ƒb0¡üübô_/¼Õ\¸éå(((`iiœ“Cÿü9³©‰ÙV5’çd„5ž·nÝi,7ž×µ€þ.9..´ñãÍèôòÐИüüww›gω‹‹ö‹ŒÜ3zô {÷Þœ8&++%+‹ïäጉIüòå§••É… ëBÂÂÔ½{+(È\ºôèòåÇÆéÇÆ¦œ½v-ÊÉiìõë›yñPPP 8x£´´DBÂ×åËÿ62Ò‰ŒÜcb¢{ãFôáÃ7?}úA£qrÀÄDïÖ­¿tuUOº››[ìëë¼ÿînà|&µ@tRD„jf6!äînÝêÁ.à:r„Œì?19¹^è¿pÕjîÞ}…Ú¶ÍûÑ£}ææ†­«Q@€‚úù³°¬¬ œãbœ“‘fÇóºÐß%ÇÂÂЂä:CÑhFÏŸÿÍžÂd{ÍßÌlóßúWT”IN>‡3âããäããÄÚõövd?J:e@@€¢¬,Çn\SS©¬,‚µkiiliiÌ^$66…“'Žš8q{Š··#Î uuEöêp>-Ͻ¼¼:**ÁLf »Ó‘#dööÛõÇÖvØéÓá‡ßüü9óÇo¼ŸÈ̙ۄ……BÆÆºJJr¡ÒÒÊŠŠêfß³àT£¶¶ B¨¨¨LVv{~R㜌Žç…†nãý¼ø è‚ðùù%Tªñck»ª³]k1W¯>©©©35Õçqðº(9BÆ‹?Ó¦™¯^=]BBôÝ»/FF:!a^ FE%DF¾‹Œ|÷îÝwSSýýû¯»Œ8!”ǵ´”7nœ%..Ú·oŸ;ç³ò“çd„Ëx^W„òÿzD°6ÐØÈ ýÚ«—¸žžzÇû´/èý=ø^›2räb}}õ/_.þ¾5uu+«¡Tª`d们¬Â|–/wæ4–Ö&Hkì#| ¬ɇ §8´9¹^ׯGÕ×7hj*ïÞ½pùrgöÞÙ±²2yüx{ÔØYFø èï@'ý]vzp·½±4¾€BƒqfèT`œÜ‹€î Œ3ÀwPhí´#wà3 ¿ tc(4x:ˆ»Ðq@Ü€Žâ.tlóª`!´3lqæ@Çÿw ‡ïÀgÀ [ó»q7;»H]Ý¥²ò¾¤¤XKËÆÅ¥N˜°6?ÿÖoúÀNpð£Í›Ïgdä+*ÊZ[=sf5QŒèè––Ë™úúYY…cÇ.ÍȸÖlNÞùã ‘öÆÞ€n /ïï6620ùeþ'66eÁ‚}{ö,ÊË ½yskyyU]]÷"¦¦ú g8e0šòóKxÉÙs€Føš»ÙÙEËZdôüù®bb¶krsé\1 Kûõ›yêÔÝèè::3±Ä¸¸T55glC^~Ò‚û¤¤ÔÔœ®Zu,,lGYY„®®š‡ÇvN‰55u'®óö?þDN6ËË« 4RR‚V®t›5kG}=ykð`íØØ”‹²K4'&¦{{ï>v̯¼<ÂÛ{ü÷ïy¡Â²ìì¢Û·ÿbWÜ#Ö¾SD„ZVQVÁ^Qii¥²²\JJЬYv«WŸ@½Ÿ¶~ý™›7·––†/Z4¹E-¦¨(›”t¶ºúAYY„¤¤øÙ³÷~³ ¢AÒ²IIé‹ ÝVZz×Ìl€¯ïaœ‘#B#·k#÷,~[÷¬°°´¶¶žÓѧOßÓhËi4£´´K™™×¼¼ì?Îli/_&ki)ÿŽ“<ºŸ†ý4ˆ-%>>mèP=^²ùù¹üúùõk°««¥§çö{÷bIsþ~#\hû¸{íZÔôéVFF:""Ô-[æDE%•‘&"„šš˜3gn9ràºu\löîÝËÏÏE]]qùr熆ÆÄÄtÒl#vîœïïJVvÂèÑ>!!ÏBÁÁ¦M3·±1öövtt4C)*Ê>¼ÌÜܰW/‰–Ö‚’——^¿ÞS]]ÑÕÕòÛ·„ÐÕ«O-ÌÍ %%Å uZÚh§O‡µDNnâ… ‘YY…¿_Î iÙààÇ3fX ÔW@@`áÂIOž¼Çññq:}z5.™“ÁÖ5rÏ‚ÉDÊïDßqãü23 H•—WϘ±íèÑå¾¾ÎŠŠ²ÊÊrK—N]»v¦ŠÊ´mÛ.z¯\y,%%ÃÎnµœÜDuu—§Oß#„¦Oß*#ã($4nðà9))þþ§‚‚"ƒed#"b‰ùÙ‰Œ|G¡Ð~üÈãÅ \E¡øøÔ¡CõqŸ?gê꺋‹ÛmÞ|3H,˜œüÝÆf¥˜˜­††ëÑ, F“—W ³s§¿&ññ©Ã‡÷QSSð÷w÷ð°=yòn³@tøM8ÆÝââ QQQQ}}Ïïßó°í#5k±  TE¥7¶-++%**\XXFšˆ***‹Oûõ«–Gw)м¼tEÅ/Nüü\²³C’’ÎZXººnþøñG^^qKÿ¸5[ *ƒÁ@åækj*µ¨çÎÝߺ5Èßßýë×`??œ(\+ª $-››K z ¥å¦¥åF£-çÝahdRƒmÛÈÝ&³ÕÑ÷ׯڜºžžéÑK—ªªÊOŸ>Ž=1/¯8?¿$3³`ÿþ%ÎÎŽŽkÿüsFIÉÝ+\Î"„‚ƒ7Ðéaµµ&LyáÂÀ/AAŒŒ«eehó³SQQ=q⨾}û4ë±¢â⊜º¡a?ÖFNN/—••ŠŒÜsúôªíÛ/bCJ¸‚ß¿çÚØ¬œ3Ç¡¬,âðáe••¿rrè%%•ººjÓ¦m”––¸~}³¨¨0±}jkë?}Ê`ïOÔ—N/çÞŽŽf¸£<~Y8NCíÝ»Wmí#„öÈíÛ·Ë>uÀ-QQᘘDl#>>ÕÐP' À !¤¬,çá±½²ò•*„+¸iÓ¹?þ?s¦5BhÊ”1¡°°—ššJNNìì†ýùçLN­—””.!!Ú¯Ÿ +%7—®­Ý‡{#r²ðNÛŒ3WÐéåtzyII…««å•+O¾ÖÕ5œµ´4VP!MÄʪ©)üóÏš ö}ýšÝ¯ŸJn.=:úCRRú–-çYö±jååÕ7žíß_SOOÔÀÀàýû¯§§çÒéå—.=ÊÉ¡3ÄÕÕòúõ¨¨¨„ÚÚú  œžgÖ"--ÑÐÀ(,,mläöo!dk;ìúõ¨ÄÄôoßr.^lþ/!{‹ih(¾x‘œ—W•€ñ^i‹ ’–1Ã*((2**¡±‘ññãyóöàjƒsüåV¡¢"Ol1??œAҲÆ=ºÜÇçPZZ–‚‚Œ——®Æ/_~¾~ý —ܶ 4Û÷õô´õô´EÍ™³sÜ8l›ˆ„„h^^ .1.î Öû¬¨¨./¯Îͽ)..ŠÊÈÈ××÷,.“”«¬üõý{®‰‰îÙ³÷°ÐBÌÏ#D722òïÝ{ƒ«èï¿oZZ#„âãSY¬ŽrXØKGÇ‘?â ê訖–V*(H³ÛOýë/ïôôÜ?ÿ<éà0BP¼7…›{uâD˜  à°a³gïäÔ¤ž·¨5R(LÖEϯ覆ÇòíZKhhÌáÃ7¹‡N¬¢Üã42 ï­Ý NÝ\÷¢Áƒç\¿¾¹MÒ£»w_Ù¿ÿú¥KLMõþ,~lii}¦nÙ2gæLëgÏ,Øu°¸¸Â—½àçÏTT¦-X0Éßß=..õÍ›”+\ûô™¾³o_emí{ö,š7oiûÏ]±ÂÕÉilFFþ¹s÷¯_züxii%® öFˆ‹K%åá{¸B¡uÉu"‹‹+ììVáÇ7ÛºõNñ›CH§—=zÛÁaD{8‰«¢ÃÊòÐÈüN‹fKáþpp-ûëWmvv‘¾>ù3&„ÐÊ•ntz¹‡Ç_tz¹®®š««¥¶vŸââ l|˜B¡\¾¼qéÒÃ6ü#//=aÂÈM›f_¾üxР9І†:ØŒâiÓ,–,9¸jÕñOŸÎãòëêþÏ|®¨¨„¾á‚.©Ë—;¿zõ‘½¢’’Šìì"CÃ~¬Ü\zyyõΗ/>`d¤ºMWW­o_†……!{A …rþ¼¿ÏÁíÛ/¨uðàÒÜ\zqqÅàÁ}……©«VMß´éÜÌ™Öø>z]]çO³fí R…TUå'NwJII¶±_{#$&þC< ü>Ðßm›Z ½¿}ËquµfÌàˆˆ¬ET?­ªªqsÛ")i¯ 0Ù×÷oÜ.Î8©²l»Öˆ!##)##‰éóôê%íššÎÇdéB.DŽ»”“ä0(¹0}ÙÀÀ`l÷éÓ÷C†´Í;ý“'¯¶–”´_´h?/ùÛO¿¶ªªføð…ûö]û#Dy`–ðïþš8ªçà°¦Õwíºw®ã¼y°íÐÐm­6¸b…kYYÕ£Gqmâ?Ð6qWX˜êïïξR9QvÔÜ|È›7)¡û÷߬_ï‰ý6âãÓÆŒLj³¤¤’%H Ný”Áhb2QSSMMáèÑå¸]\YReÙv­‘ nn–OŸ&”–VVTTGGÀNˆ:µ ä \ôwBññ©ë×{ÄÆ¦””T ¶‰q2º'O†YYý>‡ÿÏ?¡¨¨Lkhh$µ\QQýõk6¶`“ŠÊ4ŸC}ûN³eõ­ƒUUÅÄl--—/Z´Ÿ»~-©¢ª.Qý÷ܹûUU5ë×{p*ÂN‹äYÀDoÙO­¬¬ ·Kl+aa*6’÷éSÆÈ‘±í={®N™òï²ü¹¹t…É99t•ióæíÑÒr·cÉ,ÏšJrq¡Ý½ûŠÓ÷Þåh3ý]oïñß¿ç=ž„íeGMMõóòJòóKRS³üü\^¾ü˜›K¯¯oÐÑQ%5(''URRÉ©:¢ú©“¬¬¤ººË˜1>·n=ÇíòÒ_#†ººâ°aú·o¿ {enn(/ÿ?‹ž³tjAÉèáp×ß­­­OIÉœut‰j"Ç«ä~ú”al¬‹š7oBjj–‚Âä)SÖÿø‘Ç]¿–ÔQU—èö½{o&OÍÊ@, ÜUЉÞâN ·Ë¥¢øø4CÃ~¬y©ººj••¿èôò þY¿ÞSJJ<>>§7ܧOoNšÇtz¹ššbKO–oiøA›õ IDATËu3DD¨k׺/]zq577ܽûŠ•• BÈÑqä‚û¸ôw)JxxàÚµ§¬­W—ëëkxyÙ±¾E¢úiß¾ÊË–ÎÈÈïÓ§wP?Bˆ}7Bª,Û®5rGIIvôèA 2¬®6Q§”\ž ú»¬à1|¸à‘#·†Õ#•щId0»w_ùçŸ5ÅÅùù%§NÝ=s†Û„ÛøøTWWKÄ&苊‹K53€26ÖMJ:[TTæâ²éäÉ»yyÅ\ôk÷칂³PQQSÕ%uÛÀÀséÒ©¬ D!^^ U)Æ4€I½•’g?µ;çãv9U—Ê®_$--¡  sóæ³ääïÁÁBññiãÇ›aGCCc&LY]]ÃIó'ÜÕi>îji)sdVSSÀ†£1||œ||œ°mâ(‡••IMÍCl[UUžÙÜ*¬½zI;æwì˜{"†’“ëõâÅ\~7·q\vÙ9rÄ·ƒkdG^^šxî¿|}Y»RRbïߟÆå!8€B\\êš538O1à !D¡PÆqþüƒ¿ÿö•’WU•ÿûïPv]qqѸ»Ûhh(Q©Bïß§9pР¾œ,WVþJKËfõw7ožÃªÑÇÇ)""öû÷Üùó'651KK«°§i4šQc#{rüóg¦_«££*%%N´ %%®¬,wöì}–ª®ŸŸ Ñ휺²²VXdÅ WvŸ9É;9Ý¿ÿº©©>»Jq||ÚªUÓ‰ÞÆÄ$±ŸZQQÙ߇²Ÿ)—/+>>uÁ‚ÿYqHGGuÍš“.¬Ã:3qq©'Žª¬ü•päÈ­gÏ‘~Y FSXØËèèƒ\ªëZ´å8së(.®05û°§wQZzR?þHOϵ·Þ‘N@‚»þ.¦/kb¢‹íbÊ¡Cõ0ÙÝË—ŸHI9 :¿¨¨LWWMBB´¾¾Ñßß!¤¨([SSÏþ—GHÈ3 W&“9tèüôô\– oyyõyFF:ââ"'N„IK1bá8LjŽé×*)9©©)`úµk˜L4t¨þr¹ÿcSÕ ~$)i¿dÉr·) kò±Îm.òÀ³fÙyxü%/?ÉÍm‹¨¨ð€š˜°©©>Î[Ü©yxØàΔS£á&Uaèêªé`CåyyÅtzù™3½{Oú믋wîlÇNxÖ¡Ë—cÏÚ8U×å="¾ÀÏïȯ_u'O®Äv;Frà ø_·ƒ{FŒXäçç‚›ŠÜU¨¯o4hNpð†aà Báá¯Î‡ôˆTTTͽys+ö ¼;zD|Â>컦¦út #áåÚI“F]¹ò„OânK›kÿþC‡êaAý;?¼ùçµMMM^^sç:vŸ ‹‚þ.t2ÐßÅ÷"ÐéåÚÚ3ÂÂvÐhFíKËÈË+–Dµ€ß¡uªºD±Û6t©Õøúþ½f͉Îö¢‡q€.C³ú»K—NÅ_±ïÚ$¼Ð U]R±Û6t©ÕÄǧ¶•à.ÐR îÐehV—%ø*##)--þZTÔ“ã=þ‘‘weå/¢Â+NÈ–ÉdÊÈ8bê³!•iïß§ùûŸbWÕ%!ÂIìöÝ»/cÇ.µÑÕu‰IdÕ2oÞž>}¦ÊÈ8^¿µpá~II{ee§œz³Gy”øMJJ;v©°°µ‰É¼„„oìë' Ä]ºÍêï~ú”1þ^Gì“‘‘?~üuuÅ  ÈØØ”mÛ.„‡ï¤ÓËq ¯D!Û¯_³Œ& „P^^qIIÅàÁÚ^,UÝ4IebqŠÝ¦¤dLž¼> À«º:ÒÓÓvþü½X-¥**òoÞ·´4öó;:nœ1¦KøöígîGA4—Tâ÷Ç<‡?—,q*(¸µ|¹³°°P¿~*mùõ<ëUÐ5hVWRR,!á +^ºtêáÃ7¿²EMM¨kK²½r剱±®€€B(>>mð`m*UèÝ»/,U]N2±8HÅn7m:çããdccŠrv¶Øº5ý'ë»eË„‚‚̼y0ù#aaª’’,÷£|ciêë«KHˆr9ZTTÆ‹Äoiieyyµ†Æ¿ÒñïÞ}ñõÆÝy ý€ç»t Ø{œDâãSutTéôrìS]]Ëd2gÏÞ9vì«W7½ŸöêÕG–Âkmm}n.}ݺӘ¨íÙ³÷ëê^¾ü¸ÿu„PyyÕׯÙß¿çnÝù«4==GYY®±‘A4òåËOR—œœÆ}Ê‘‘TQ‘GÅÅ}Á¹e‰æ~þœéé¹%ñËš3…õ×%%ÅDE…o܈þþ=w×®Ë8Qz ƒ¸ @€ýÝ… ÷+(LÆ>§NÝ 8[QQ8OYYnòäÑÜ *¼êé©…l—,q:t(dÜ8¿¦&&…‚ÔB±Tu JIeb‰ÅnÍÍ ÏžýsïÞkvÿ¹G]]‘]”7>>•õä5>>ÍÔTŸûQ¢h.©Ä/•*´zõô+Žöïï•”ô]\\&Uu" ‹ è"à€{нý]€ßÿ…{~ú»Ð©@—ë!¸ÝèïÐù`—Õ€n Ä]:öˆ =ˆ»tqž Ä]:ˆ¸@ÏÞß £ P…‚˜Ìv ºÁÁtuÝ©T+UUg/¯À††Fbž¬¬B--7.F²³‹0ù^aaë~ýfþùçÉêêZN™/\ˆTTœ",lýêÕG^<üøñ‡¼ü$^Ü@ýúUëçwDEe•j¥«ëþçŸ'™mÚn,g8±fÍ {ûÕ¤ÍÈ ZZn/>dí~ÿž+*jsçÎK …†ËÉKkàhÖùNl½¸¸ÔÞ½'q|„¸ @ûÓ·±‘ÉÞ‘›²`Á¾={åå…Þ¼¹µ¼¼ª®®˜ÁhÂÖxâVXxûÌ™ÕÏž}°·_Í`4óÔÖÖ/\¸ÿܹµ))AØȼӬL&sêÔ±±);KJîž;·öãǤn´ññi—.=º|y#•ÚÊaQggZhh k÷æÍS++ví ¿ÞéÜÖ35Õß±cîܹ{8e€¸ @{Òv}Üìì" ‹eœŽÆÄ$ª?eÊyyi3³·oo—”C…†ÆèéyHK;ZXøæäÐ'LX[W×€ r©KD„*##iiiüäÉŒŒüK—MÑh¾55uîîÛæÍÛSYùkÀ/II{g瀪ªšèè::31kqq©jjÎìö›uãÑ£¸çÏ“ÃÂvëJI‰38"b§àùó44\ÅÄlÖäæÒ1ã “—.=$%å ®î‚ úVUÕ¸¹m‘”´WP˜ìëû7BˆXÜ©!„¶m Z³f¦¿„ºq#ZW×]DÄfÔ¨%ÄžœÏ¡Aƒfã]\h‘‘ïX£7o>sq¡edä[[¯ÀÜVVvÚ½ûŠœÜľ}§³Zƒ´Ý KqÍËå»ã‡Ö›7oBqqù£Gq¤îAÜ }hçQeƒkÇÆ¦\¼øý¦œ””¾hÑÐÐm¥¥wÍÌøúß)"B-+‹(+‹àŬ„„¨³³ÅýûoIM!„èô°¨¨ƒŠŠ²IIg««”•EHJŠŸ={»Ùf݈Žþ@£)(Ȱ'¾zõqÕªcaa;ÊÊ"tuÕ<<¶c饥•ÊÊr))A³fÙ­^}!tøðÍââòÂÂÛ gœ rj¥òòêÞ²Ä!Ó½½w;æW^áí=þû÷<œ·#GÄ%ŽÑ_QQæþý7¡ì좾Mž<†=CaaYvvÑíÛ%&þý5ZÚ¼Ûz!?þáB$©{whk:6âb88ŒØ¹s¾¿ÿ)YÙ £Gû„„|ø¦¯¯Ñ»w¯ÿ2<š6ÍÜÆÆTTTØÛÛÑÑÑ ç˜ÓéÓ«‰gÁj ±±1•––`?ª¨(søð2ssÃ^½$ˆeq´¨y;·õ°tÍè͛ϤîÁ|fÚŽv˜«\\\¡ª: ³ÚÐЈéïê¼ys—ÓÏÏÅÏÏåóçÌ‹ººnNJ:››K}ûöóßq*?¿DII–»©sçîoÝtì˜ß¨Qƒvï¾òû ''•šš…K,((2DÛ–••.,,cÏ "Be0!§ÄÄoêê.j­\鯽 ñÔ J45•XòòŠutT[q..4[ÛUuu 7oÆx{o…Œ–6o綆¦¦2§‡ÖÐß -h·>nïÞ½jkÕÖ>JM½¨­ÝÛ&]ýûkîØ1OGG51ñ›‚‚ÌܹŽ×22®ef^+- §´p=¬ššº›7ŸMœ8ŠhŠ=[tô‡9sœœÆ*)ÉbU 4408™mÖ ssÃè踩ÔJJ²¬™e¥¥•µµõŠŠ2d¥‘¬¬THÈÖ¢¢;+WºMŸ¾U\\„KAâ©á¦þ*(ÈüüÙšüˆýee%ƒƒ½{÷7ÈÌ{k¶±y¹Ó¹­×¬{lý]ÂÜn€æá÷qƒED¨“'‘––xðàmN}̘!zzꎎkÇ7;vÈ—/? Ù³gQC£°°TN®— 'kuu FSrò÷uëNkk«¸¹Yêè¨âLÎgå×ÐP|ö,1/¯øË—Ÿ7nD»¸ÐúõSÉÍ¥GG““Ú²å<ξ´´w7ìì† ¨åì°{÷B55…ääïÁk׺;9m˜;×qÀ­€€³––Æ 2™™Äâ;w^61ѵ¶ª¦¦@¡ 7·q3flÅ,((Å2Ϙa…;5ww›ìì"–5WWK›•6#G¼ví©‚‚Ìøñÿ3Ô|äÈ­ÄÄoœ†šW¯>aee‚dæÔ¤íFl^N¦ø¡õ°vÈÌÌWV–#u￸ÛÙ¿ õðÇ]è‰ðÓµgnn¸m[ÐÖ­AÕÕµh…†nÓÔTÒÔT:zt¹Ï¡´´,//;ÉU«Ü45Ý$$Déô0NÖäå'Q©Bêꊮ®´€/aà p¦Øóûù¹DE%¨ª:kk÷<¸/BHEE~óæÙ&¬UR’sw·NHøÊž¿Y7(JxxàÚµ§¬­W—ëëkxyÙYXîÚµ`Ò¤uEEe4šÑ¥Kë9ùß·¯ò²e‡32òûôéäog7ŒKAâ©餤d””T`ó™ÍÌ=ºÜÛ{wVVá!ý.\X‡«îË—Ÿ¯_"õÄÅ…¶oß5î‘×Äv#6/w:·õ°ô¨¨„#ú“»×¶¯Çÿ‹·À7t8íqA?˜2e½¹¹áŠ®íH—¤©©iР9‡-µ±1Å=¢. ?u2€Gw¹üŠ‹+ììVáÇ7Ûºõè‘M›f;8¬ñò²gÍjæCø¶õΞ½/##ItBÐßíJ@è\:&âB—oøóÏ“>| lõ’U=“øø4{ûÕ11‡û÷×$9L¡AÜå{ ÜNGöq!îÝgækºË€Ð…‹Úˆ»ütp~".´wù·ŸÚX¯ª³ÁVùa-ô7; éŒu•Û††ÆíÛ/²$xgÏÞ‰-·‹$x‰Î´Ž«°û›@·ó€^À?t…«±±‘QPPªª*Ï)ôi……¥ÁÁôôÔ³² ƒƒ¿x‘L\X˜w ^AA„„¯þþ§ìí?FGÄwT0 Þ7¶èë«sqŒ%xËË«#"vêè¨&&¦3M\–Ùê`0Ù–lQÇ+ìòsãpú»®ƒ K×¹¹ëï>~ý!"b×ðáýed$ÖÞ¹sþìÙö$x[+"Ë(ìriœ–q·£€ñd€ßè:—ž>}om=”¸ÈHð¶ZD–PØåÒ8-ƙ۟®0‚ô,ºã5YZZ‰-&Œš2e}tô„P`àüŒŒ|L!´pá$“y­0®¢"Ÿ”ô¥´ÊÉÔéÓáçÎÝÿòågUU‚‚ô!ý~猸‹È"„¶l™#'7‘]D!äêjyâD"ˆÈúúþMZ£ÙSóñq"ujvv¶`)ìf±éïa »¡ŒŒüfÏ×z]¨qZ ÄÝvæ'|HŒ¸<êïöî-ûïÒü'O®ª©©óò ¬«k Þß‘m–ž¬°Ûj î¶5nþ¤ F\ L!„=8üöí2i6 Ã]».ýš­««¦¤$‹FÿÉ£îÙ³ˆ•“Tú ˜o`àüwï¾àLÑéå¬m–F,úOPö÷%xOž¼[]]+!!ÊJ$‘%=#LD¶±‘q÷î«éÓ·º»[ ²Ä숭Ä#ì »aa;8eã]añÐ2¨‹4'àùnÛoþ¤{=Ç儵õPKKã‰ýŸ?Oªªªùñ#¯¨¨!4c†UPPdTTBc#ããÇóæía©½66r Š¡ºº†òòê/’íìVc¼DSìù54_¼HÎË+ŽŠJ¸q#!Ä’’MJJç"ÁËÉ –ˆlrò÷ÒÒʘ˜D‡5S§š_¹ò$!ák]]K –´øÎ—>|' @a‰Èr)ÈýÔBGŽÜ"&b´Ha·±‘AÚ,ÄÖã_5NKþîo\€oé²}ÜV@¡PîÜÙ¾iÓ9í99EŠŠ²ŽŽf“&ÒÖV ÞV‹È²…].ÓR@¡µ@¸ø™®qAèÞ€.B‹p ð9]7âv8|¢ÞÊ'nð'ݲq ¿Ë3p;øœîq‰BèÞ€þnó@àºGÄÅàa.+ti`œ™n.AwЏÝé\x›pÞÓè™g q—„îw#º%p¡vzjøé±@Üýèà]ˆ¸Ý º=w!Ü]ˆ¸Ðõé©qÂ-е€ˆÛ-În¤çÅ]¸] ¸b»+t{*=&îBèr@ÄíÆ@ÐE1™=³º{Ü…p tE â@÷¥ûÆ]¸s]¸n{=²“°èvq:¸@"n‚n‡ÿânë.J·œ€U÷ZGG^Hq{t¾‹»­¸(ážÕ,°Ê|K¡Ð:ª"¸z ÇÁOq·EA:¸@—"n:»B!Îv …P(ÿ~˜Ì?@Ëildëë{ [KK;:8¬yùòcll …B30ðl÷î½F¡ÐXŸèè¼—ÍÏ/¡Ph’’öíáX'À~=ºÀðM—ûE ½Û6ÅÓsûÕ«OB£F b2™‘‘ï””ä.œÔ~5뺹»ví)BhÉ'UUùö«‹>n‚.Àôw¹\”лmk^¼HÆ‚îéÓ«_¾<òêÕѨ¨ƒòòÒìyrrè&&ó$%í©T+mí;v\B555mÞ|^]ÝEHhœššóŽ—ˆ)œ*µ²2Y»v&¶}䈯®®Ö½ÖÑ™¹xñII{55ç'OÞ“Öbf¶!T]]K¡ÐddI}ãd !“H£ùŠ‹ÛIHØ»”N/ŠJ03[$*j#/?ÉÏïHc#£]šèãð|Ðß% ºÐÁm7"#ß"„Ôš;×K±°0´°0ŒMa婬ü…Z´h2…B¹zõéúõgŒuÓÓs·l9od¤³xñ”Ì̂ϟ3»ƒKi©3éé¹ÇßAUW×®^}üýûÓD› Nö÷?%,Lݸq–¨¨0©o²²R¤ÖRR2lmWÕ×7º¹Y**Ê>~ÿòåG7·Í½{KïÛ·øúõèƒCTUV­rkƒ–%ú¸tvÿ¥³ã.pÛþÐéå! .y 4üýÝ INþŹϟ3¿}ËAÕÔÔIJŠ­Z妣£ºxñ\JKQQ‘?õæÍç)SÖ§§ç"„RR2p6óóKüýOQ©‚6üûì™èÛ¨QƒH­9QW×àéi{áÂ:¬ìŠGëê||œ¼¼ìuuÕbboß~ÎkÜmÅÔ?¸’{8t¹Ó#—Šäqfãɇœ\/„Pnn1—<.DººnŽM>Ü‹ÐMMÌéÓÇ SSS³–-;¬§ç±cÇ%bJK‘’SV–36ÖA1 „P³6I}ãd-;»!db¢Ç*ž•UˆZ·î´””ƒÝj„PaaO¾ò~w€Qe£çE€:5îb¸Iu,VV&¡ØØ”Þb)±±)kמbÏs÷î+„жmÞí377ÄÍÍ ?~<·qã,cc]&“¹{÷bJë\øÿëh“B¡ „Œ&.¾q²Ö§Oo„PRR:.eñâ)ÏŸÿ}®\ hÛ$ÀÅ @sñËzFæF¿!Žg2q⨻w_9:®=z“É|õê“§§-{%%9„PiieEE5ë©íÂ…ûkjê 4LMõ¾öï¯ILáTé“'ïOŸǶ}|ùúN㔓hSVVRD„Z[[ï娷oRß8ñÇãOœ;þAEEµººbtô‡õë=Oœ»xñá¯_µ²²R™™L&34t[3­ÖlÇF•ÐÙ8 „POZϨÃÖ!âoBB¶_¼øðõëOââ¢ãǘ?{÷7oRöï¿ùNHHK6L÷î«—/?ur{èÐÒ‡ßáR8Õ˜ð{‰!tôè-gg QQaÒœÄZ„…©{÷.Þº5èÒ¥Gýú©DE$úÆ CÃ~‘‘{6nüçÞ½7L&säÈ––Æ‘‘{¶l9ãFtmm½ŽŽêâÅSši/^^rƒ;,À]€3&êaq·§ý(”Žü~IßÉ °ývp× §{(D\€º-¢ç5Wk¥PhcÆøpÊÀËCÝm"¡üü*ÕŠø±µ]ÕÙ®ýœÞsƒç¸´ŠÎ~èFÈËK¿{w’˜Þ«—xÇ;Ó^@àNÏë½-…¼¿[[[ïá±½¶¶!téÒ#ìÉ\pð#uu ûÿaå$]<ˆ—†py šM¡ÐÂÂ^"„®^}J¡Ð¬­W`‹©ª:O˜°VTÔFCÃõáÃwX½¤Kyxl¯¨¨FmÛváÝ»/íØlBB‚¦¦úÄžžzg»ÖZØï¡ÐÇš‚.À$ýÝÜ\ú”)>}Ê8sfõš5'öì¹²5!áë¬YL&sÊ”1……¥¬Ì¤‹ñ²À.“É\³æÄÑ“&¾uë9BhÖ,;¬Š’’ M!!Á;w^Κµ#;;$55ËÁa qÉ¡gÏ>Œ±(,lGEEµ¹ù²Ó§W{xØtD+ò90›¬u°î¡ÐÇx‚.Àø¸›™Y0räbqq‘ׯΜ¹-""öøñÓ¦™/_~¤©©ÉÝÝæÒ¥õ¼upXƒå']ØhölûfÂåÁÖ$ {UQQ}ÿþ ÑiÓ,’“¿#„45•öî]Ä`4ÉÉM,((MMÍúçŸÒ%‡ž=;4mZÀˆ‹>Ü[]]ëé¹=/¯xõêéÖš|JÏ™7×V°þ©@Ä ­Á33™Ì¦¦&*UHX˜Ê`4 ˆ‹‹ „²³ BC‡êáòsY<¨Ey”•åìì†WTT¯Ys²²ò×Ô©æ¢ìää¤BUU5œ–b¹A¦×@ó°¿PÎRŸN—tv[ ¶TdOwµ´”ß½;)&&2|øÂ«WæÍ›àåxçÎKlÝù’’ \~ÒŃxY`—!4{¶=BèÔ©»!//ü<ç’’Šœ:BH]]Ó’CcÇ.--­|óæxHȳ#GnýóÏ÷ßk §ÂZ²”ýà À쀠 ´’ç»êêŠ/^üíåH¡PZ:dˆö¯_µöö#Μ‰8räVSóùó$VfÒŃxY`—góæÙ“&–“ëURR¡®®hiiĪ"7·xÉ¿; IDAT’ƒÏŸ'544Z[UQ‘Ç!".94l˜Á©S«de¥DD¨OŸ=zPû5Ð{+@‚.ÐBÈç3‹‹‹^¿¾[QÈÛÛqúôqS§Ž]ºtj]]ÃùóØEËýýÝMMõ÷ï¿>v첪ª,[`HAAæÒ¥G—/?æ%BHD„jf6!äîn;̂`LLâ—/?­¬L0U##ÈÈ=&&º7nD>|óÓ§4šBèúõÍX¿|óæÙt>„Ö«*/¯îÓgjMM]JJ¶ÒollÊÈ‘‹õõÕ¿|¹Ø6uÀzU/ôÀëàb×:»mBkF>Z½ïêÕ'55u¦¦ú\–×àzX´Ú >êïv=°ZGO»N^À­£I[ÑÃÖ‰ìôœÿUm¬4@»ÁGãÌ].jÐwŽ?ÒÕu§R­TU½¼‰y²² µ´Ü¸ÉÎ.¢Ph MXغ_¿™þy²ºº–4g³¦€/ ]kw<q·çÒØÈÀ–"!%66eÁ‚}{ö,ÊË ½yskyyU]]1ƒÑ”Ÿ_Òl]tzXaáí3gV?{öÁÞ~5ûz)-5YqA".ÐrÈãnc##00X_ßSXØZZÚÑÁaÍË—1u Ïöðëá>W¯>mºŒìì" ‹eœŽÆÄ$ª?eÊyyi3³·oo—”C…†ÆèéyHK;ZXøæäÐ'LX[W× #ã(#ãÈ¥.ªŒŒ¤¥¥ñ“'22ò/]zXXX:`€—ˆˆ¤¤½³s@UU »)âѶ?h5¬ÕÊ â¶ =l©Hò¸ëé¹}ݺÓiiYÆ ¨ùîôéðvõÃÎn˜Ý0ì "Il[èÖŽM¹xñ!{ÌKJJ_´è@hè¶ÒÒ»ff|}‡‡ï¡–•E”•EðbVBBÔÙÙâþý·ŠŠ²IIg««”•EHJŠŸ={Ýñh»(ð Xá".Ð*Hâî‹ÉXGóôéÕ/_yõêhTÔAyyiö<¤’ºMMM›7ŸWWw§¦æ¼cÇ%b '?<ØóàÁžÅ‹§ „ÔÂv—,9ðû¢¼@ëpp±sç|ÿS²²Fö y† ~>jÔ9¹‰.DbZìp? ´=¤«OÇt!îNw†?ϼGù!4p ÖܹÿŽZXZXÆÆ¦°òJꦧçnÙrÞÈHgñâ)™™Ÿ?g;v—Ò"ç¼¼ì_”·UÍÒ).®PU†b2QCC£¨¨ BÈÐPç͛㸜~~.~~.Ÿ?g^¼øÐÕusRÒÙÜ\zxøëÛ·Ÿ£ßxÁ5?¿DIIöܹû[·;æ7jÔ Ý»¯à¬q? ´ðÊÐ:àÕ»–@ÒߥÓËB˜`'0ÙÝׯ?Ø61è²èß_sÇŽy::ª‰‰ßdæÎuÌȸ–‘q-3óZii8¥…ÿskjênÞ|6qâ¨èèsæ889UR’ÅŒ°›"å;à?>­‚$îÊÉõBåæs)F*©;}ú8aajjjÖ²e‡õôª_W×P^^ýâE²Ýjmm77K Å/’óòŠ£¢n܈F±›"åX£jðx¯c!ìIš“}(§íVТâùù%¬ù¡ö††Þ{÷^#ÆÏž_R¯ tKH⮕• B(66åÁƒ·XJllÊÚµ§ØóJêš›~üxnãÆYÆÆºL&s÷î+Ä”–ú÷û¢¼@ë077|øðÝСóúô™ºgÏÕÐÐmššJÆ=ºÜÇ瘘­­í*yyiÉU«Ü45Ý”•¸X“—Ÿ¤ 0ÙË+pôèA;üü\šššTUçÍÛ3xp_„»)âÑNn!âv8?Ù³M°´4:T/%%cõêãu¶;_@ò|wÜ8“‰GݽûÊÑqíèу˜Læ«WŸ<=mÙóJê.\¸¿¦¦ÎÀ@ÃÔT?!ákÿþšÄ”–ú÷û¢¼-­±ç ¥¥üíÛeNGGôàÁbº‹ ÍÅ…Æž²kׂ]»p²£¦¦À${j('×ëÅ‹#¸DvSÄ£k$m§Â>Ù›wòìYâÝ»¯rrè'ú§¥eÕÕ5¨«+Îë¸nwSõõK—:þ¼¼tP¿¹¹!'#11‰gß¾ýB¡PLLtÿüs&ËÈÒ¥‡Ž¹ejªÿâÅ*—ê._Þ¨¬,÷òåGKËåW¯>uw·16Ö%Vgf¶!T]]K¡Ð¤¥%>} jéy]òõ™CB¶_¼øðõëOââ¢ãǘ?{÷7oRöï¿ùNHHK6L÷î«—/?ur{èÐÒ‡ßáRZê&Ê{ï^,©(ojjN”wË–ó7nD×ÖÖëè¨b³£Ž¡¸¸ÂÎn.qüx³­[ÿè~ˆ¸ü§Éž_¾üD„ ž˜7'22ò?ÎÔÐPJIÉðò üþý é,QMM%[ÛUõõnn–ŠŠ²Ç—•UaîßsäÈ-YY©7¶pº,F4~üˆ;w^†…½ÔÑQ%V·pádÿSÂÂÔg‰Š “ºäà0¢õ-ðäqWX˜ºiÓìM›fãÒYUUùwïN z{;âvq)¤O(XLõñqòñùŸáÊòòꨨÄ6“CQQ&9ùÎŽ¥¥±¥¥1éíMïÞ½ââN5Ÿ¯«ÀZ™ˆ8y "q‡Ãi²'6ÁóСääX¬úü9sÔ¨A\Léé©=~¼ÿׯZ…)ùiiÙ¤F=Š««kðô´ÅþÖ#„°:ÊË«çÌÙI¡P‚‚üµ´”y? %„Paa)iu³gÛûûŸ¢R7lø÷ù11ÄÝnC‡êåç—ôé3•˜neeòøñ~Ò" Ê t¬ K\Œ—˜hO8Mö¼p!ÒË+PPPÀÒÒ8'‡þùsfSOß…¸¸¨¼¼ôÏŸµeeU¤F°×4LLôp±¥L””d[t ØÄOeåÞ¼øÜêóºº>³¼¼ô»w'‰ŸcÇü8Y°`“ÍÞ·63ÀdFùr±C\z6Ø*\ eM­b}` v†ÓdOÒ ž¼PRREPUUyR#Ø<ͤ¤t\A55…5kf455-X°Ëüdoß~¾wï BÈÙÙ‚´:ìe9–ÁVŸW¦'-)„Pǽò,„iÇÔmq5|bÐ'nS8Mö$àÉœú¢EûŸ?Oª¯o°²2QSS 5‚ÍÓ<þAEEµººbtô‡•+ÝB¢7κtéчß¾éç罺™3·555½zõ©¡¡qÎkë¡·o¿ V'++)"B­­­÷ò ìÛ·O+Î èBÁíš§ÙÐK̃ØiZédOMMeâO‹¾x‘œ––mee‚­äC:KÔа_däžÿ¹wï “É9r kº–¤¤ØîÝ <<¶œuq¡©©)p©.**A\\´Í9s|}§qªNX˜ºwïâ­[ƒ.]zÔ¯ŸJTÔÁ–žÐ… 0á÷ß½¡PZ½ø_CCãîÝWΟ‘‘¯¨(kccºaƒ'6“¬¬Â±c—fd\ãd';»H]Ý!D¥ ©«+:;[xá–@áÑTA¡‘ÇEÒǽ­¬‚ÿ:Ä¿q©ôX¸OíApúÉ´ÌHKþÚve:t^ÀW462 JUUå9e˜6- °°48xƒžžzVVapðã/’‰q—w ^AA„„¯þþ§ìí?FGÄß›ø]‚»)´É݆¦»>­˜( ú»ÝΘŒŒ|k뜖Îxü8~êÔ?~\íÝ»îPhhÌÚµ§ JŒt._Þhg·êÓ§ ii „© Öß­¬¼)øVW×xþõ—·ƒÃmyzz.•*ho?üüy3³E,Sii—pG±âA³Þ;æyGbèï¶ÆFƇ߈é½z‰ëé©w¼? ôw[ôwrž>}om=”t1 Þ'Oö éï“à50ðäQ±IðzyÙ'%ÅçÎ݃Ið²›Â]¶lZ[œY[Ð1wxHÌß ššêw¶@×â.@Nii%öÒ$BhÊ”õÑÑBó32ò1 ^„ÐÂ…“LLæµÂ¸ŠŠ|RÒw„ÐéÓáçÎÝÿòågUU‚‚4.÷£=‘ö~“ÔÜ ý¸ÛãàQ·wo騨OØöÉ“«jjê¼¼ëê@‚—hó‡Ä0Î ´øÇÖ îö80ý]ÔÜó] Ã]».ýš­««†-Í#&&ŒÂ$x÷ìYÄÊ™™YÐ"0 ÞÀÀù¼ÅDvÑëJðâÒnÀt-à{zØdw€g¬­‡ZZOœèÿüyRUUÍyEEå!àíbÀêZÀg@ ‡B¡Ü¹³}Ó¦sÛsrŠeÍ&M¥­­‚Ið¦¥e)(ÈxyÙ±ts%$Déô0Nåå'aïﺺÒ¼0 Þ¨¨UUgmí>8 ^ Ñ´´K¸£@ÛÀKŸ:ž–®NÓe÷ˆº;ðrH+h“—"ºp©­¦­~2=#îBh3º›/@;qh3º›/@;ãÌÝxt×:zàï.àw€qfžþnw‡Ÿ/âžñëJÀó] uÀû»-â.д¡°@—Þß:ì…QìER »pìØm …Œí>}ú~È?BgÎD,X°K 8;þ^Þmúø¢Ph?þhso s¸ tq»2……¥µµõœŽÆÇ§éêªED¼fíb‚/_&ki)³MLôx¬îǼ»w_éë«gdäÿžãÀw@ÜÚˆ¸]Ÿqãü¸,Ÿº~½GllJIIB(>>mèP=ÿSAA‘Á22ޱññ©™™ùηcõŒ9ñíÝy\LëÿðÏ´N5Q)í!mܨ¦¾¸Ü%²k³%u­²_!ËÍr]‰×zEDB)Ü"é–´)ÓF)mTÒ6íÓüþ8÷Îon›R©f>ï×ü1sæ<Ïùœ3gÎgžç}/&†îããÜ× ½u&žßE¨]˜qÑ·º?ÊÅåj‹‰Gެž>ýd2››X,VBÂÛ'|ýýõZŒõlÌ˕B{÷Â… ;Ï1uÚÚ#Ž]cj:®¯#B€íÝ®Á¼‹º3.ë`Qw`Þí4ìgFÆßž†nÇpÿG=ó.êlæ"^†û?êQ˜wQ‡ðˆƒxîÿ¨`ÞEíÀ#âe¸ÿ÷ø«HÌ»¨-ܾß#ÔÜÿQo¼‹þ æ#^†û?ê}˜wÑ¿ðˆƒxîÿè{Á¼‹ðˆƒxv,£ïó.oÃŒ‹x~Ðw‡y—‡áo|ÄË0ã¢>‚y—'áñ2ÜÿQŸÂ¼Ëcðˆƒxv󠾆y—g`ÆE<¿¨À¼;ÀuæÇ;nïêO0ïdLºx¸A¼ ¿·ÿU$æ]î…¿ñïê—0ïXüÄà âqø@ýæÝ©½¤‹‡Äãð+€ú=Ì»Ü7qõIAÄ50ï@­.x¸A<w¢óÄãð+€Ì» »i‹‡„°§ @˜wâ(ƒ!ü  óî@ƒ?ðÃŒ‹8Þ˻ėv@ˆ«€GIÔ}˜qWོ ¬ð¾Ž€Çh}ø°§‡§põ_EòdÞE ØÌEÜ…¯¯è{®®¾$ýOê|ÙËH$…bÚ{áu¼hâ! `¤¦¶ôôé{ßm¹}²ÊˆçHÿ4z0é".‚yôôÔ-2"ž;8˜)*J÷m<]5uªÞر#³² 7mò Œêëpê!˜q—¼ ÆÆÔ]»–Ï==ÕÕ•bcSI$ššÚÒõëOR(¦JJ–OŸ&@ssó^ÊÊVFJJ–GŽ\Ÿ0a0u$MBbvAA)•ºšB14VU]räÈuh¯6ˆˆxM£9ŠŠÎ354ÜXZZñìYâ„ ëÈdiéy[¶x651¿¿sBÂEcc*¿$§®n½cÇŠi\\FPP´®îJ!¡irrf›7{Ö×7ó(*ZΙ³‹L6QQYøøñ+¢¶Ö´¨P^Þœs•µµíH$‘ïoÝ #‘hÓ¦míñÏñv3!n„y·]YY…üqŸÁ¨+((ݱã8{öþÁƒ^ÒÒƒ]\VΙ31--×Þ~> º¸¬Ü»wyUU ¬[7Ë«¦&æž=—þúëE{µ¥¦æLŸ¾=""yþüI«VÍ.+«ŠŠz3sæÎ¼¼’'ÖÿðÈS§îœ:u§“Ñ644€¸¸(ñòÝ»WW_£.>>ÃÌlïÛ· eÜÝïlÙâIÌSVV©¥5ÌÔt\^^ñòåGšš˜tzN{°+´°˜Ì¹Ê¶¶¦àçþþ‘°|ùŒØúˆ7aÇ2â˜wÛ¥  ]Tt/ à0de@jjÔÖÖS("Û·/òöÞcgg ‚‚ü{÷Úlß¾HKKÅÉÉ:&†~þ|P~~ ¤¥å¶WÛ¥Këë—-3¹ysŸ»ûF:Ýëï¿“êë7l0³µ5ݳgD~5ΟþJ]™,((°l™ 1QEE6?ÿ“F§ç0™ÍëÖÍ?yrƒŸßðò nll€aÃd]]×ݽë2hاO_22ò._~Ø^ì ==7s®²Ít~~¾ÀÀèÊJÆ_½#[XLé±Ïñ̸ˆg`Þm—¸¸ˆœœ”žž0™LX¼ØHHH0##oÓ& eD72§k×B.<›:nœ––– 47³Ú«HÌTª»x^^1ìÞ}Q\|æŒ; ¸¸ü«q¿LIÉÖ××xôèØ˜1ªÄD!EEi>>¾¢¢Ï ª*ÆÉ@mm}YY»8??Ÿ””8TW×v»ÂK—““š1c\e%cçÎóUU5ææ“ÅÄÈ_¡ÿÀŒ‹x ^Gôœ™fòd7o®x{?~ð &1ñíï¿ß\¹r60™ÍÄ AAÑàâ²ÒÉÉÚÞÞÝØm³6yù!œœÕbÊúõ –,1&¦ˆˆ5¢¢{rrRí½«  99àÇODD¢%”•U”€²²L›c6‰Ä¹Ê`ggúèQì… A@t;#ÔYxâ=˜wáéÓ„‹Ï7lpwt´hoN{{·ÚÚz--ÍÄÄ·£F “”¤ ÖÕ5ØÚ1B^VV ¾|©ª¬d´Nº-¬X1ëܹ@/¯àÊJ†²òÐðð¤={lÎ ôö~\SS'))ž›û‰ÅbÝ»çÒµ³µqæŒÿ™355õQQ)`gg*((……ŸNEF&766M›¦¯  M„Ô"€;—pVØb•°›7o’”Ô ²²Jeå¡S§êv'ZÄC0ã"^…ý̘øÖ×7Œx~æŒ?ÑøkÓÿþ§›ºoߟ¾¾ÏÌÌ oß> $$èêº^FFâúõ'>>¡NNÖšnn· 7UW×v¼\‘!!Ç'MÒ~ôèŹs’’âS§ê…„§RÕýüÂ=<îÒéïi´î¦1*UÃßÿººâ… A……Ÿ-Ý܈·ø#"^§§06¦^»¶tuÕ¾@‹UaaÁ F€µõ´Öш·tòOL±cñ0‹×v}i`ýOd›—ññ‘º“ábcSüq½¦¦rzºw7BûGEC^Þ¼¶¶>5õê¨QÃÚ˜ƒDÃ#,OèÌÅ?ØÌEÇ¥—“a?s¿öñcq½l ÆÆÔÐP·ïO›nÝzZ[[o` ÙvÒEˆ€!Àön?×ÔÄLJz×zú A¢Êß?žo„í]^ÐAÓ3.ú6\ÚÞż‹zæ]^ÐÞ!’Kè{àÒ‡'ó.úþxm7ã5m±™‹º©õ~Å™˜'Ïïb{÷;Ãûïò̸èpENí ¼ê!Ô=-—xú6Ľî;À-‰™'Û»¡Þ€Í\„:ó.B¨ˆ&f\Ô#ˆ}‰Ûèa?3B¨{°cõ ¯ö6|ØÞE¨ë¸ý¸Ðe<¾Að7ê Ì»}8\¿Ç±{›ÙO¸¨“x4ïâ÷!„Páɼ‹-•ï èt(,,ÁÅåZ\\F]]ƒœœ”¾¾Æ;¿ ð·9sÏÞÓ¢qþ÷8‰D2d¥å”S§6 öÒƒƒ_Μ¹sÒ$íçÏ={i¨Çp¶q¹«± <šwê7^¼H›>};??ÿÌ™ãDD„KJÊcbR›š˜íå]î3wîĺº†°°„sçeöîµéëˆPÿÀ½¬p<3B})44ŽÉlVP²eËB//§ÐP·OŸüÉd¡ÐÐx‰f`°ÒÓ?H4%%Kv©††¦ÝÅÅgޱ8"â5ÄÆ¦’H4EEË9sv‘É&** ?~Åž®®n½cÇŠi\\FPP´®îJ!¡irrf›7{Ö×7À™3þòòæââ3úi‰Dûé§ ­ËÞ¿E¥®¦PLUU—9r=šÚR{{711SMM›×¯³Ö®=!*:CIÉ233ï«[àÏ?yüØÕÆf:¼yóž˜øìYâ„ ëÈdiéy[¶xwÃŒˆxM£9ŠŠÎ354ÜXZZÑz]Z¯ïO”•­ÄÄL/÷ô§‡¾ îjì¶wê[::j“ó‘Fs65wèÐÊÑ£‡w\*'çcZZ®ŠŠljjŽ­íÑìì›Äô²²J-­aü÷ïG-_~$?ÿ1ýÝ»WW_ˆÏpp8%,,äà° ""ÙÝýNCCã’%Æ6¸“H$33Ã’’òËb—­ªª€uëæ“H¤[·Âö칤§§.))YY…YY™™7i’ƒQõ÷<=¿ºJJÊ““³@[{Ðé93gî2dð‰ëoß?uꎢ¢Ì¬Yã§OßÞÐдhÑÔ¡C%CCãŸ>·¶>Ôb]–/ŸÁsbâ[{{7‹µ`ÁOÅÅ_:÷™ð’Ñ ìçAvýgæ]„úÒœ9?ž:µÁÕÕ7?¿¤¶¶Þß?2<<)3ózÇ¥44”BCÝjjêddää|ÌÌÌ'¦&ë꺎Él–’šûéÓ—ŒŒš›**²ÑÑgäå¥6oöd2›×­›ïêº.;»päÈ¥^^ÁLf3ØÚθreq”sYì²|||‚îîwRRÞ98--wâDmPPNL¼èíýxûö?ebcÏž<éçâríýû¢¯n™ùÄ“Ÿ~ãèh—/?¬¯oܰÁÌÖÖT]])"âu@@daai}}£Íôk×vóoÚäÑz]–,1æŒyëÖ³ÍÍÍÖÖ&ׯïi½jÇ»tÏ7 ^Á&>ꈼIDAT~f„ú˜££e^žîåâ²’D"}ùR–Й‚¢¢diéÁP^^Í9ŸŸOJJª«k‰)""BŠŠÒ|||EEŸ@UU† “€ÚÚúÔÔø·åÝ»ìµk! ˆM7NKKKš›ÿù¥/..2t¨ä¨QÃ@R’"))N>|øP\^^ýî]A›eËÊ*?~,EEi"-±§”€²²Ì‡ÅœE¤ 'ç#|øð DD„ÕÔŸ?O!²]‚‚¢ÀÅe¥““µ½½[ZZn‹øøþÿw<©Ó}ƒgÏn=zøÁƒ^kמ00ÐTSS”—ë×/ ¯D×®…@rrVÇëBüà`#ºÁËÊ*; c2›ååÍKJÊoÝÚ·h‘¼yó~̘ŸÉd!gssgEEiöÉ 6bhº˜¹º:¸«Kìäøü¦&æñã·¼¼‚ß¿/ž8ñ‡½{—Oš¤ÝÕÅõT<ÝÄ{y—ëNÑ£­¼¼ÚÂbŸ––ʘ1ªii¹¥¥ªª &&úÅÅåPRR.)9§u©‚‚ÒuëÜ"#“©JJ2DÞ-,üìàp*22¹±±iÚ4}éy×ÖvÆ™3þgÎÔÔÔGE¥€©‘ÕË+ØÃãnZZnRÒ»öB•••€/_ª*+­“nw8;/ ‹Šz³pᘘ³+VÌ:w.ÐÛûqMM¤¤xnî'‹µ¿Ý¹s^^Á•• eå¡ááINNÖ­×EPð?Ç4SÓñ—.=ôôôonfEF&÷`Ì\‰ŸŸÏÜ|òùó÷ïGy×ß?LMÇ©«+-Zd4dÈ > ÌÆæð­[a0q¢6‹Å y%++Õy÷ûÀ~f„ú’•mÖ¬ ¥¥÷îE|üXfmmò÷ßäáÃ圗‹Š’GŒÿí·5-J‰Š’Ÿ?OÉÌÌ76¦z{ïaOàˆxžþÁؘÊ>ʉJÕð÷?¤®®xáBPaágGGK77 ‹É;v,#¿z•®««ÂÂB­Ë:9Yhº¹Ý64ÜÄîÁîüü|7n8,–˜øvóæÓººj!!Ç©Tu?¿p»tú{MWGgdHÈñI“´=zqî\ ¤¤¸±±~ëuiQ³¹¹áÆæõõ^^ÁŠŠÒ=3·²²¢À£G±Mðœ˜X]]ëëöôi<´èN\‡Í`Ô‘H4 ‰Ùí Å/((m=¾3ž?O!’îÅ‹;¢¢<££Ï<{vŠ8ÃÒÞ€v5µ¥ëן¤PL•”,Ÿ>M€æææ¼”•­Œ””,‰¥·9¶ŸS›ãê»ÄÂöB]E"õ·Ñ(ÝìSV¶26Öä y•—W|òä†Í›-¿^¬ÚÃ]ã™ûЀúþMŸ>¶wBõ1Îû1s26¦††º}ÿxzæ]„B}Œ§†¾cÞE!ÔÇxjè;æ]„âaÜ8.¬ŸÃ¼‹B<¬ßŒ«¾éW æ]„¾ ¶Bßó.Bß[ ˆ€¿ÀPõãë¢B!®ƒy¡ïêìÙ‰Æ~ðñM­ªªéÁú/]z¸ví‰f¨®®7ÎþÄ _âeJJ¶™Ù^ ‰ÙÂÂ&kîßêÁ`¾™£ãé;Ïurf£nófOYY3AAcMM›sç¡ýí°mÛÙyóÚ¸3qŽó;vþÅê)˜wêaÅÅ_êêÚ{7>>sãFó/_°_ýÿÛ.‰ŠJ>\®ƒ–-;4oÞ¤mÛ@XX¶™FÓÍ̼ž›ëkkkÚ¥?Îí=ññ¿ªÄ¹  $2Ò#/ÏoË«ââ/ÐþvظÑü?¶v)˜­[–—W?y×¥Rµó.B=ÌÈhKnî§öÞÏøñÇ$$(Äcð`±bÈd“²²Jðò ÖÕ]YUU“šš3cÆ)©¹ÊÊVaa ’’mb²MDdºŠÊB?¿p‹%!1›¸«(((X$$d:9]¸z5äèѳ>Œm]É•+UW×7­¨`,YâræÌfGGË¡C%åä¤6n4ßµké«W醆Éduu눈×ìúW¯>./o.!1ûöígöönŠ©œœYAAéWß]¼øW ‰ÙFcÆüL¬ `±aƒûˆ‹ED¦=zƒXDrr–¡áF!¡iTêêÄÄwúú-ónHÈ+‰öþ}çÄ´´ÜW/îÐÐP–““²·Ÿ·oŸm‹í  `áârMGgå¶mgŒ¶äæ~l/†çÏSÆŽ]! `¤¤dI¡˜ff怠 €•¸B=€…ê*+¼Íƒ,!Ain~Öæ»µµø)‘ÁƒÅˆÇû÷·˜Ì055E77‡˜˜³ªª yy~ÙÙ7‡—{úÔÅ wss˜4I;+ËGVVòƽuuOüý]¾¼3#ÛBa2ÃX¬ð»‚ ¡55!üŸ?²Xá­+©¯¢¢"K§{Áxz:êé©·ˆN÷’—òø±kSSØÁƒ?kj*õóññíÛg››ë»`ÁO Ò¾¾û³³oÊÊJÞ»çÒñ»,VxSSXcãÓÆÆ§»v-ýå—¥Äü;w.y÷ÎçäÉ ŠŠÒD´ Ò7oî++ ºzÕIB‚Òzëݾ}`î܉-&&&^MUU±'rn‡Â»$iåÊÙ¡¡ntº—€?ƒÜf ïÞùÈÈHøùd0‚¯]Û=x°ûs¼zÕÉȈÚö‡> ¢øèî£ëp<3B=))éÝØ±#‰;’¶–œœE¡ˆ©‚@ô…nÜhîáq÷?îß¹sPIIÆÆæ°½ý<##*Œ?êâÅû÷_Y±bÖÒ¥Ó`Á‚ŸàæÍ§zzêÄ_ÆÇÇgŽ£*((ðêUº’’ qŸð}ûþlQI@Àsmí£G'ýäI\ë[«îßeÃ3°´œòë¯W ..CWWíàÁŸ@FFbõê9 N!!AYYÉŽß­¯ots»}çÎßoßæWWמ8±ž˜ÿرµ ©©,!A€½{/¯X1sñb# ‘HTªFë­geEk}{]]µýûíöíûsëÖ3?þøÃáë Ç&&¾eo‡¸¸ ==õK—v«¬¥¥"*J~ú4¡u z­Y3×Òr Q3•ªÁþÅÅE‰Û§s!™ßß4šû™êÞÞÉd2ÙdÊǨ¨âùÁƒ^-f‹ÏÔÓS>\Žý ¦ÏžýcVV¡­í ==u Šöð¸7|ø¢áÃ-\x`ÌÕ‡c-,¦pV—¡¯¯ñoµÿœ ‹ûÿÓ¢­+yôèÅüù“Ø5dg©ªÊsÖÉb±BB^Í™ó#ñ²¨¨LYy(6{Y))ÙÄóòòꢢÏ::j¿»xñÁˆˆ×›>|¸­¦¦H¥jpÎO§ç«üðaÌ‚†­W­3°+- üûow~;»ßZlÎÅÅÇgÓ[ÇÀb±‚‚¢-,&³cà<Á\ZZ¡¤4´ó!!ÔÌ»õ›éuuOêêž,[fråÊ.âùþýv-fã<ܳÕÕ5ØØž2E'00*+Œ·o¯çäøæäøæçß¹xqû—/U22ƒ9K%%½ÓÑQã¨öŸtB´[Wâë»?6–ÎyÒTLŒ\TTÆYgyyuUUœœñòÁƒè™3Ç@\\:vS3)éñ<>>SSSYLŒÜÁ»%%å½ðó;8i’6??_vv!•ªÎžþI±š_¾TUT0TTþIl¯^¥w)ï??ßĉÚ+VÌ"¨ìíÀü¿Ï5[MÌÐ××,+«*/¯6L–câÿÇÐæ‡Ð·Á¼‹POjÑNj!>>CMM±´´‚x0u,ËÎî7Cñ·níOHÈŒŽ~#..ª¨(}úô½ºº†ÂÂÒÝ»/”ÊÉIýùç_õõQQoÜÜn@EEõÛ·ùÙÙ…¿þz5$ä±Ð¬¬99©¦&fëJÒÓ?õ°ƒ133c2›ýý#}}Ÿ99YG^§Ós$$( ÒÀ‘Ã:x÷ãÇ2øðáSZZ®Ía55EqqQöüðoKB!“…üü³³ ó!a‹MýfÚ´­Äè3¶ˆˆ×«VOJzWVVùüyÊ¡C×vìX̹8ÖíÝÿÄ &Fô÷,,,={6 >>ÃÀ@‹˜Él Œš={B×w„Ú€y¡SSS—Ÿ_¢©©Üæ»õõtz޽½›ŒÌ|âqáBо}VV2Ž]-''5þ¤“'ýH$’³ÏSqñ™úúkJJÊ54”½¼œnÜxB¡˜:8œ$ZrfîîwŒŒ¶47³H$øá‡á`a1ÅÁᔬ¬Ù§O_ZT¢®®D"‘8¯Þ¶mÑòå3–-;$-=oÑ¢ƒd²ÐäÉ:þù‹««¯˜ØŒÓ§ï…„WVZXXúùså˜1ªŸÁnG9¬ãw 4§LÑÑÖþyæÌ,èëÿgþŠ Æû÷Eººj‚‚;v,Þºǫ̃Q¶ÉÉÙ¢¢Â#G*´ØzÏž%&%½#NÙ²ÉÊJ}úTF£9ÊÊšÙ۟سÇfíÚyœÛ!!!“½¸²²Êüü‘mÆ@& >¼ÊÑñ4•ºúåËt E„ƒOè¨QÃ44ÚþXê* /G¨«H¤8eüøu[¶Xc—PNŸ¾C÷ñq€ÊJ†®îª»w%ÎC·Dƒ{˜{r?òMŸ>ŽgFˆWÌ›7ñæÍ§˜wÛÄd6766±X¬„„·'Nøúû€ææf[Û£«VÍn7érüéïÛ»uÝÀl%”–V¨ª. umbrello uml modeller http://uml.sf.net 1.5.7 UnicodeUTF8 alire-1.2.1/deps/gnatcoll-slim/docs/conf.py000066400000000000000000000207501425465243200205510ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # GNATColl documentation build configuration file, created by # sphinx-quickstart on Wed Dec 7 11:02:44 2011. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os, time # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' def get_copyright(): return u'2007-%s, AdaCore' % time.strftime("%Y") # General information about the project. project = u'GNATColl' copyright = get_copyright() def get_version(): """Extract the version from configure.in""" return file("../version_information").read().strip() # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = get_version() # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] rst_epilog = """ .. |Tip| image:: tip.png :width: 15pt :alt: TIP: .. |Note| image:: note.png :width: 15pt :alt: NOTE: .. |Important| image:: important.png :width: 15pt :alt: IMPORTANT: """ # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'sphinxdoc' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. html_logo = 'adacore_transparent.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = 'favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'GNATColldoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'GNATColl.tex', u'GNATColl Documentation', u'AdaCore', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'gnatcoll', u'GNATColl Documentation', [u'AdaCore'], 1) ] # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = u'GNATColl' epub_author = u'AdaCore' epub_publisher = u'AdaCore' epub_copyright = copyright # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. #epub_exclude_files = [] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True alire-1.2.1/deps/gnatcoll-slim/docs/config.rst000066400000000000000000000104521425465243200212470ustar00rootroot00000000000000*************************************** **Config**: Parsing configuration files *************************************** .. highlight:: ada `gnatcoll` provides a general framework for reading and manipulating configuration files. These files are in general static configuration for your application, and might be different from the preferences that a user might change interactively. However, it is possible to use them for both cases. There are lots of possible formats for such configuration files: you could chose to use an XML file (but these are in general hard to edit manually), a binary file, or any other format. One format that is found very often is the one used by a lot of Windows applications (the :file:`.ini` file format). `GNATCOLL.Config` is independent from the actual format you are using, and you can add your own parsers compatible with the `GNATCOLL.Config` API. Out of the box, support is provided for :file:`.ini` files, so let's detail this very simply format:: # A single-line comment [Section1] key1 = value key2=value2 [Section2] key1 = value3 Comments are (by default) started with `'#'` signs, but you can configure that and use any prefix you want. The `(key, value)` pairs are then organized into optional sections (if you do not start a section before the first key, that key will be considered as part of the `""` section). A section then extends until the start of the next section. The values associated with the various keys can be strings, integers or booleans. Spaces on the left and right of the values and keys are trimmed, and therefore irrelevant. Support is providing for interpreting the values as file or directory names. In such a case, if a relative name is specified in the configuration file it will be assumed to be relative to the location of the configuration file (by default, but you can also configure that). `GNATCOLL.Config` provides an abstract iterator over a config stream (in general, that stream will be a file, but you could conceptually read it from memory, a socket, or any other location). A specific implementation is provided for file-based streams, which is further specialized to parse :file:`.ini` files. Reading all the values from a configuration file is done with a loop similar to:: declare C : INI_Parser; begin Open (C, "settings.txt"); while not At_End (C) loop Put_Line ("Found key " & Key (C) & " with value " & Value (C)); Next (C); end loop; end; This can be made slightly lighter by using the Ada05 dotted notation. You would only use such a loop in your application if you intend to store the values in various typed constants in your application. But `GNATCOLL.Config` provides a slightly easier interface for this, in the form of a `Config_Pool`. Such a pool is filled by reading a configuration file, and then the values associated with each key can be read at any point during the lifetime of your application. You can also explicitely override the values when needed:: Config : Config_Pool; -- A global variable declare C : INI_Parser; begin Open (C, "settings.txt"); Fill (Config, C); end; Put_Line (Config.Get ("section.key")); -- Ada05 dotted notation Again, the values are by default read as strings, but you can interpret them as integers, booleans or files. A third layer is provided in `GNATCOLL.Config`. This solves the issue of possible typos in code: in the above example, we could have made a typo when writting `"section.key"`. That would only be detected at run time. Another issue is that we might decide to rename the key in the configuration file. We would then have to go through all the application code to find all the places where this key is references (and that can't be based on cross-references generated by the compiler, since that's inside a string). To solve this issue, it is possible to declare a set of constants that represent the keys, and then use these to access the values, solving the two problems above:: Section_Key1 : constant Config_Key := Create ("Key1", "Section"); Section_Key2 : constant Config_Key := Create ("Key2", "Section"); Put_Line (Section_Key1.Get); You then access the value of the keys using the Ada05 dotted notation, providing a very natural syntax. When and if the key is renamed, you then have a single place to change. alire-1.2.1/deps/gnatcoll-slim/docs/email.rst000066400000000000000000000155221425465243200210740ustar00rootroot00000000000000************************************ **Email**: Processing email messages ************************************ .. highlight:: ada .. index:: email GNATColl provides a set of packages for managing and processing email messages. Through this packages, you can extract the various messages contained in an existing mailbox, extract the various components of a message, editing previously parsed messages, or create new messages from scratch. This module fully supports MIME-encoded messages, with attachments. This module currently does not provide a way to send the message through the SMTP protocol. Rather, it is used to create an in-memory representation of the message, which you can then convert to a string, and pass this to a socket. See for instance the `AWS library `_) which contains the necessary subprograms to connect with an SMTP server. Message formats =============== .. index:: GNATCOLL.Email.Utils The format of mail messages is defined through numerous RFC documents. GNATColl tries to conform to these as best as possible. Basically, a message is made of two parts: *The headers* These are various fields that indicate who sent the message, when, to whom, and so on *The payload (aka body)* This is the actual contents of the message. It can either be a simple text, or made of one or more attachments in various formats. These attachments can be HTML text, images, or any binary file. Since email transfer is done through various servers, the set of bytes that can be sent is generally limited to 7 bit characters. Therefore, the attachments are generally encoded through one of the encoding defined in the various MIME RFCs, and they need to be decoded before the original file can be manipulated again. GNATColl gives you access to these various components, as will be seen in the section :ref:`Parsing_messages`. .. index:: MIME .. index:: encoding The package :file:`GNATCOLL.Email.Utils` contains various subprograms to decode MIME-encoded streams, which you can use independently from the rest of the packages in the email module. The headers part of the message contains various pieces of information about the message. Most of the headers have a well-defined semantics and format. However, a user is free to add new headers, which will generally start with `X-` prefix. For those fields where the format is well-defined, they contain various pieces of information: *Email addresses* The `From`, `TO` or `CC` fields, among others, contain list of recipients. These recipients are the usual email addresses. However, the format is quite complex, because the full name of the recipient can also be specified, along with comments. The package :file:`GNATCOLL.Email.Utils` provides various subprograms for parsing email addresses and list of recipients. *Dates* The `Date` header indicates when the message was sent. The format of the date is also precisely defined in the RFC, and the package :file:`GNATCOLL.Email.Utils` provides subprograms for parsing this date (or, on the contrary, to create a string from an existing time). *Text* The `Subject` header provides a brief overview of the message. It is a simple text header. However, one complication comes from the fact that the user might want to use extended characters not in the ASCII subset. In such cases, the Subject (or part of it) will be MIME-encoded. The package :file:`GNATCOLL.Email.Utils` provides subprograms to decode MIME-encoded strings, with the various charsets. .. _Parsing_messages: Parsing messages ================ There are two ways a message is represented in memory: initially, it is a free-form `String`. The usual Ada operations can be used on the string, of course, but there is no way to extract the various components of the message. For this, the message must first be parsed into an instance of the `Message` type. This type is controlled, which means that the memory will be freed automatically when the message is no longer needed. .. index:: GNATCOLL.Email.Parser The package :file:`GNATCOLL.Email.Parser` provides various subprograms that parse a message (passed as a string), and create a `Message` out of it. Parsing a message might be costly in some cases, for instance if a big attachment needs to be decoded first. In some cases, your application will not need that information (for instance you might only be looking for a few of the headers of the message, and not need any information from the body). This efficiency concern is why there are multiple parsers. Some of them will ignore parts of the message, and thus be more efficient if you can use them. .. index:: GNATCOLL.Email Once a `Message` has been created, the subprograms in `GNATCOLL.Email` can be used to access its various parts. The documentation for these subprograms is found in the file `gnatcoll-email.ads` directly, and is not duplicated here. Parsing mailboxes ================= Most often, a message is not found on its own (unless you are for instance writing a filter for incoming messages). Instead, the messages are stored in what is called a mailbox. The latter can contain thousands of such messages. There are traditionally multiple formats that have been used for mailboxes. At this stage, GNATColl only supports one of them, the `mbox` format. In this format, the messages are concatenated in a single file, and separated by a newline. .. index:: GNATCOLL.Email.Mailboxes The package `GNATCOLL.Email.Mailboxes` provides all the types and subprograms to manipulate mailboxes. Tagged types are used, so that new formats of mailboxes can relatively easily be added later on, or in your own application. Here is a small code example that opens an mbox on the disk, and parses each message it contains:: declare Box : Mbox; Curs : Cursor; Msg : Message; begin Open (Box, Filename => "my_mbox"); Curs := Mbox_Cursor (First (Box)); while Has_Element (Curs) loop Get_Message (Curs, Box, Msg); if Msg /= Null_Message then ... end if; Next (Curs, Box); end loop; end; As you can see, the mailbox needs to be opened first. Then we get an iterator (called a cursor, to match the Ada2005 containers naming scheme), and we then parse each message. The `if` test is optional, but recommended: the message that is returned might be null if the mailbox was corrupted and the message could not be parsed. There are still chances that the next message will be readable, so only the current message should be ignored. Creating messages ================= The subprograms in `GNATCOLL.Email` can also be used to create a message from scratch. Alternatively, if you have already parsed a message, you can alter it, or easily generate a reply to it (using the `Reply_To` subprogram. The latter will preset some headers, so that message threading is preserved in the user's mailers. alire-1.2.1/deps/gnatcoll-slim/docs/favicon.ico000066400000000000000000000015761425465243200214000ustar00rootroot00000000000000h(   Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡¼“m“Q“QñéâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëÞÓ“Q“QØ·¡Ø·¡ëÞÓ“Q“Qг˜ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼“m“Q“QØ·¡Ø·¡ÿÿÿ¡g2“Q§rAÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿš\$“Q¡g2Ø·¡Ø·¡ÿÿÿг˜“Q“QñéâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÖ½§“Q“Qг˜Ø·¡Ø·¡ÿÿÿñéâ“Q“Qг˜ÿÿÿµˆ^“Q“Q“Q“Q“Q“QøôðØ·¡Ø·¡ÿÿÿÿÿÿµˆ^“Q¡g2ÿÿÿÝȶ®}P®}P®}P“Q“Qµˆ^ÿÿÿØ·¡Ø·¡ÿÿÿÿÿÿÝȶ“Q“QëÞÓÿÿÿÿÿÿÿÿÿÖ½§“Q“QÝȶÿÿÿØ·¡Ø·¡ÿÿÿÿÿÿÿÿÿš\$“QÂ|ÿÿÿÿÿÿÿÿÿµˆ^“Qš\$ÿÿÿÿÿÿØ·¡Ø·¡ÿÿÿÿÿÿÿÿÿÂ|“Q¡g2ÿÿÿÿÿÿñéâ“Q“QÂ|ÿÿÿÿÿÿØ·¡Ø·¡ÿÿÿÿÿÿÿÿÿëÞÓ“Q“QäÓÄÿÿÿг˜“Q“QñéâÿÿÿÿÿÿØ·¡Ø·¡ÿÿÿÿÿÿÿÿÿÿÿÿ§rA“Q¼“mÿÿÿ§rA“Q§rAÿÿÿÿÿÿÿÿÿØ·¡Ø·¡ÿÿÿÿÿÿÿÿÿÿÿÿÖ½§“Qš\$ëÞÓ“Q“QÖ½§ÿÿÿÿÿÿÿÿÿØ·¡Ø·¡ÿÿÿÿÿÿÿÿÿÿÿÿøôð“Q“Q§rA“Qš\$øôðÿÿÿÿÿÿÿÿÿØ·¡Ø·¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼“m“Q“Q“Q¼“mÿÿÿÿÿÿÿÿÿÿÿÿØ·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡Ø·¡le:Ph<ey <ri>fe:lolht/gBk/DAREibalire-1.2.1/deps/gnatcoll-slim/docs/filling.rst000066400000000000000000000011641425465243200214260ustar00rootroot00000000000000************************************** **Paragraph filling**: formatting text ************************************** .. index:: paragraph filling .. index:: filling .. index:: Knuth The package `GNATCOLL.Paragraph_Filling` provides several algorithms for filling paragraphs---formatting them to take up the minimal number of lines and to look better. `Knuth_Fill` is based on an algorithm invented by Donald Knuth, and used in TeX. `Pretty_Fill` uses a different algorithm, which was judged by some to produce more aesthetically pleasing output. More detailed documentation may be found in the comments in the package spec. alire-1.2.1/deps/gnatcoll-slim/docs/geometry.rst000066400000000000000000000022221425465243200216310ustar00rootroot00000000000000******************************************** **Geometry**: primitive geometric operations ******************************************** .. highlight:: ada GNATColl provides the package `GNATCOLL.Geometry`. This package includes a number of primitive operations on geometric figures like points, segments, lines, circles, rectangles and polygons. In particular, you can compute their intersections, the distances,... This package is generic, so that you can specify the type of coordinates you wish to handle:: declare package Float_Geometry is new GNATCOLL.Geometry (Float); use Float_Geometry; P1 : constant Point := (1.0, 1.0); P2 : constant Point := (2.0, 3.0); begin Put_Line ("Distance P1-P2 is" & Distance (P1, P2)'Img); -- Will print 2.23607 end; Or some operations involving a polygon:: declare P3 : constant Point := (3.7, 2.0); P : constant Polygon := ((2.0, 1.3), (4.1, 3.0), (5.3, 2.6), (2.9, 0.7), (2.0, 1.3)); begin Put_Line ("Area of polygon:" & Area (P)); -- 3.015 Put_Line ("P3 inside polygon ? " & Inside (P3, P)'Img); -- True end; alire-1.2.1/deps/gnatcoll-slim/docs/important.png000066400000000000000000000026471425465243200220020ustar00rootroot00000000000000‰PNG  IHDR"":G ÂgAMAÖØÔOX2bKGDÿÿÿ ½§“ pHYsHHFÉk> IDATXÃí—KlTUÇÿçÜ÷½ó¸wf:ÓÒ™vf -m§@ÀðªÄ -ˆ |,uAŒñ±p#k7cb0ÀNbLL ¤D1ÊK * iZ! ¢ØÖJÛ±™>èc˜÷½wîuQ m[…ü×ç|ßï|¯|x¨‡š_Ì=°!°X„x€@Ï= ÍUã Ö_px+Ðcˆ.&¼ä~&ÖúòªÆÍ;š ¡­œ <Hyݣχš¶2áU[´ÀÒÕ/…Œç?]þg+c-1Á€\ŠàŠ S–}ló+ï,ÈÞB‹Õï‹®{«þ‰×«EY‚ÓmÁíUùDïÏŽ_¿i; pÿ#B((Ã?XÞ²’“=Eš›"ZßˆÆæ- ¥­÷;"€2ÀnòD6ìŒl|©Æ©ùP]ÅÀçááP$¸44øÛE%9>r3­M˜™3ó¿o8'€SB«åC¼³2 ºƒ!Áá –·ÔT®ØÆVW‰X³R‚"3 ”À(pþä‘Â/ÃɉÉxfjt|lè÷ñ\*™°aÀÆ€m[£EÓŒ˜ºÈNå;˜²fçŠ(‚3à\¢èT‰(;¡¸\pk*TMÀÚÕ ê–É` B†n`|,‰áø4Šz–™ž™,êÙ©ÂØPoúì‘C£‰kWÞpèV§ì, ÇÁH­Ô³¾‘µ2§·ÊBu³ðh ¼*‹2/‡Šrág@ÈÍ÷°Ê ·Š\¾³hÁ²lÆ2rrjêºi[ÖQÇK©‘ Óí¤0â©{cµ«*i$L 3¨‰r¨‰Š¨®Qá— ·Cü-J 8–0QÐ LNNãÌgûÓ§Úöí‹÷¿ UR±†IZ¹‘Ròi>g,´,Êhª‡ÄA–9(Qä@él™ýË™É|6“EÇу7Î~²oÏÄpÿ{„2iØwÖîì]3s0›OŽŸK÷ù9^ˆk›Y!‰d‘»#%ÿ¼NžÏãôáýéo~°÷züê.™Ù 湩L!“ìœîó ¢ØªmdE„(°à¹¹A ¹,¾ûtêØG{w ^Ù =Ÿ£RæHFϦÎǬ¶ªfD€ãÐ9@(ô\8‡¶ÝoŽ÷u¿‰YjâŽ;%€Àd&Ï÷^ü)Ë]yèz¦iÁ¶ç›Sœ NÐKqP*ˆÌ*å5yË‹¾þ²9¹¼y ÌM Û¶aš€¤–Áé Ô(i7`K9@&¬3LExÎF^7Àæ(@$‘ËØ3E ºaS<àeg-€‰EƒF†]̺ çª"œ Ž+"“5@E6ÂX(±­† 8aè& º ÝbÁÉn€ µ<48=_ˆÚŽüÐ!"øy–³JçñGÏ%ôtœëjÿúKJ©knÙÛ´ÍjX›°(6\§heu½‰¡ü„,$w­ T^RKäkY&Rãø¾óä¿;=v­ûâiœ@}.wžy1¼býS ›¶{µêFFP—°¬ ×Ý ¢´ÔBˆŽZEƒ½Ñ} w®ã«öt¢ûcSÏí³Á¶Ï&®vè]×w±ýµèÚ'·ÊÞ fYv=fšbQß  `äÏ©»ááµWT”pG£ ÷œ¬;Ê Ò) Þeo €mÂø÷«¥ à®{òPÿoý Œ‡»n£,ñ’"zTXtSoftwarexÚsLÉOJUðÌMLO JML©/œÔ® ©MIEND®B`‚alire-1.2.1/deps/gnatcoll-slim/docs/index.rst000066400000000000000000000012231425465243200211050ustar00rootroot00000000000000GNATColl Core Components ======================== .. toctree:: :numbered: :maxdepth: 3 intro building scripting traces strings memory mmap boyer_moore filling templates email ravenscar storage_pools vfs tribooleans geometry projects refcount config pools json sql terminals promises Indices and tables ================== * :ref:`genindex` This document may be copied, in whole or in part, in any form or by any means, as is or with alterations, provided that (1) alterations are clearly marked as alterations and (2) this copyright notice is included unmodified in any copy. alire-1.2.1/deps/gnatcoll-slim/docs/intro.rst000066400000000000000000000017531425465243200211410ustar00rootroot00000000000000.. _Introduction: ********************************************* Introduction to the GNAT Component Collection ********************************************* The reusable library known as the GNAT Component Collection (GNATColl) is based on one main principle: general-purpose packages that are part of the GNAT technology should also be available to GNAT user application code. The compiler front end, the GNAT Programming Studio (GPS) Interactive Development Environment, and the GNAT Tracker web-based interface all served as sources for the components. The GNATColl components complement the predefined Ada and GNAT libraries and deal with a range of common programming issues including string and text processing, memory management, and file handling. Several of the components are especially useful in enterprise applications. Bug reports ----------- Please send questions and bug reports to report@adacore.com following the same procedures used to submit reports with the GNAT toolset itself. alire-1.2.1/deps/gnatcoll-slim/docs/json.rst000066400000000000000000000032211425465243200207470ustar00rootroot00000000000000**************************** **JSON**: handling JSON data **************************** .. index:: json .. highlight:: ada JSON is a format often used on the web to communicate between a server and a browser, or between servers. It plays a similar role to XML, but is much lighter in terms of size. On the other hand, it doesn't provide advanced features like validation which XML provides. The package **GNATCOLL.JSON** provides an Ada for creating JSON data, or parse such data that your application receives. Most JSON data will generally start with an object, on which attributes can be set. The value for the attributes are also JSON data. Here is an example of use:: pragma Ada_05; with GNATCOLL.JSON; use GNATCOLL.JSON; with Ada.Text_IO; use Ada.Text_IO; procedure JSON_Test is MyObj : JSON_Value := Create_Object; begin MyObj.Set_Field ("field1", Create (1)); MyObj.Set_Field ("name", "theName"); -- Now print the value Put_Line (MyObj.Write); end JSON_Test; This example used the Ada05 dot notation to call the primitive operations, but would also work using the more traditional prefix notation. It is also possible to create JSON arrays. These are not tagged types, so the prefix notation has to be used. Here is a further example that sets another field in the object we had before:: declare MyArr : JSON_Array := Empty_Array; begin Append (MyArr, Create (1)); Append (MyArr, Create ("aString")); MyObj.Set_Field ("vals", MyArr); end; GNATColl automatically takes care of memory management, and all allocated memory is automatically freed when the object is no longer needed. alire-1.2.1/deps/gnatcoll-slim/docs/memory.rst000066400000000000000000000123231425465243200213110ustar00rootroot00000000000000*********************************** **Memory**: Monitoring memory usage *********************************** .. highlight:: ada The GNAT compiler allocates and deallocates all memory either through type-specific debug pools that you have defined yourself, or defaults to the standard malloc and free system calls. However, it calls those through an Ada proxy, in the package `System.Memory` that you can also replace in your own application if need be. Like this:: procedure Ada `gnatcoll` provides such a possible replacement. Its implementation is also based on `malloc` and `free`, but if you so chose you can activate extra monitoring capabilities to help you find out which parts of your program is allocating the most memory, or where memory is allocated at any moment in the life of your application. This package is called `GNATCOLL.Memory`. To use it requires a bit of preparation in your application: * You need to create your own version of :file:`s-memory.adb` with the template below, and put it somewhere in your source path. This file should contain the following bit of code:: with GNATCOLL.Memory; package body System.Memory is package M renames GNATCOLL.Memory; function Alloc (Size : size_t) return System.Address is begin return M.Alloc (M.size_t (Size)); end Alloc; procedure Free (Ptr : System.Address) renames M.Free; function Realloc (Ptr : System.Address; Size : size_t) return System.Address is begin return M.Realloc (Ptr, M.size_t (Size)); end Realloc; end; * You then need to compile your application with the extra switch `-a` passed to `gnatmake` or `gprbuild`, so that this file is appropriately compiled and linked with your application * If you only do this, the monitor is disabled by default. This basically has zero overhead for your application (apart from the initial small allocation of some internal data). When you call the procedure `GNATCOLL.Memory.Configure` to activate the monitor, each memory allocation or deallocation will result in extra overhead that will slow down your application a bit. But at that point you can then get access to the information stored in the monitor We actually recommend that the activation of the monitor be based on an environment variable or command line switch of your application, so that you can decide at any time to rerun your application with the monitor activated, rather than have to go through an extra recompilation. All allocations and deallocations are monitor automatically when this module is activated. However, you can also manually call `GNATCOLL.Memory.Mark_Traceback` to add a dummy entry in the internal tables that matches the current stack trace. This is helpful for instance if you want to monitor the calls to a specific subprogram, and know both the number of calls, and which callers executed it how many times. This can help find hotspots in your application to optimize the code. The information that is available through the monitor is the list of all chunks of memory that were allocated in Ada (this does not include allocations done in other languages like C). These chunks are grouped based on the stack trace at the time of their invocation, and this package knows how many times each stack trace executed each allocation. As a result, you can call the function `GNATCOLL.Memory.Dump` to dump on the standard output various types of data, sorted. To limit the output to a somewhat usable format, `Dump` asks you to specify how many blocks it should output. *Debugging dangling pointer* Using a dangling pointer can lead (and usually it does) to no crash or no side effects. Frequently, freed buffers still contains valid data and are still part of pages owned by your process. Probably, this occurs more often on linux compare to windows. Writing 0 or 0xDD pattern when a memory is freed will be (because of the exception that will be thrown) detected at the first usage of a freed buffer. The crash occurrence will be higher and less random. This makes solid reproducer more easy to build. For dangling pointer usage debugging, use Memory_Free_Pattern parameter when calling `GNATCOLL.Memory.Configure` procedure. *Memory usage* Blocks are sorted based on the amount of memory they have allocated and is still allocated. This helps you find which part of your application is currently using the most memory. *Allocations count* Blocks are sorted based on the number of allocation that are still allocated. This helps you find which part of your application has done the most number of allocations (since malloc is a rather slow system call, it is in general a good idea to try and reduce the number of allocations in an application). *Total number of allocations* This is similar to the above, but includes all allocations ever done in this block, even if memory has been deallocated since then. *Marked blocks* These are the blocks that were created through your calls to `GNATCOLL.Memory.Mark_Traceback`. They are sorted by the number of allocation for that stacktrace, and also shows you the total number of such allocations in marked blocks. This is useful to monitor and analyze calls to specific places in your code alire-1.2.1/deps/gnatcoll-slim/docs/mmap.rst000066400000000000000000000140271425465243200207360ustar00rootroot00000000000000.. _Reading_and_Writing_Files: *********************************** **Mmap**: Reading and Writing Files *********************************** .. index:: mmap .. highlight:: ada Most applications need to efficiently read files from the disk. Some also need in addition to modify them and write them back. The Ada run-time profiles several high-level functions to do so, most notably in the :file:`Ada.Text_IO` package. However, these subprograms require a lot of additional housekeeping in the run-time, and therefore tend to be slow. GNAT provides a number of low-level functions in its :file:`GNAT.OS_Lib` package. These are direct import of the usual C system calls `read()`, `write()` and `open()`. These are much faster, and suitable for most applications. However, if you happen to manipulate big files (several megabytes and much more), these functions are still slow. The reason is that to use `read` you basically need a few other system calls: allocate some memory to temporarily store the contents of the file, then read the whole contents of the file (even if you are only going to read a small part of it, although presumably you would use `lseek` in such a case). On most Unix systems, there exists an additional system call `mmap()` which basically replaces `open`, and makes the contents of the file immediately accessible, in the order of a few micro-seconds. You do not need to allocate memory specifically for that purpose. When you access part of the file, the actual contents is temporarily mapped in memory by the system. To modify the file, you just modify the contents of the memory, and do not worry about writing the file back to the disk. When your application does not need to read the whole contents of the file, the speed up can be several orders of magnitude faster than `read()`. Even when you need to read the whole contents, using `mmap()` is still two or three times faster, which is especially interesting on big files. GNATColl's `GNATCOLL.Mmap` package provides a high-level abstraction on top of the `mmap` system call. As for most other packages in GNATColl, it also nicely handles the case where your system does not actually support `mmap`, and will in that case fallback on using `read` and `write` transparently. In such a case, your application will perform a little slower, but you do not have to modify your code to adapt it to the new system. Due to the low-level C API that is needed underneath, the various subprograms in this package do not directly manipulate Ada strings with valid bounds. Instead, a new type `Str_Access` was defined. It does not contain the bounds of the string, and therefore you cannot use the usual `'First` and `'Last` attributes on that string. But there are other subprograms that provide those values. Here is how to read a whole file at once. This is what your code will use in most cases, unless you expect to read files bigger than `Integer'Last` bytes long. In such cases you need to read chunks of the file separately. The `mmap` system call is such that its performance does not depend on the size of the file your are mapping. Of course, this could be a problem if `GNATCOLL.Mmap` falls back on calling `read`, since in that case it needs to allocate as much memory as your file. Therefore in some cases you will also want to only read chunks of the file at once:: declare File : Mapped_File; Reg : Mapped_Region; Str : Long.Str_Access; begin File := Open_Read ("/tmp/file_on_disk"); Reg := Read (File); *-- map the whole file* Close (File); Str := Long.Data (File); for S in 1 .. Long.Last (File) loop Put (Str (S)); end loop; Free (Reg); end; The above example works for files larger than 2Gb, on 64 bits system (up to a petabyte in fact), on systems that support the `mmap` system call. To read only a chunk of the file, your code would look like the following. At the low-level, the system call will always read chunks multiple of a size called the page_size. Although `GNATCOLL.Mmap` takes care of rounding the numbers appropriately, it is recommended that you pass parameters that are multiples of that size. That optimizes the number of system calls you will need to do, and therefore speeds up your application somewhat:: declare File : Mapped_File; Reg : Mapped_Region; Str : Str_Access; Offs : Long_Integer := 0; Page : constant Integer := Get_Page_Size; begin File := Open_Read ("/tmp/file_on_disk"); while Offs < Length (File) loop Read (File, Reg, Offs, Length => Long_Integer (Page) * 4); Str := Data (File); *-- Print characters for this chunk:* for S in Integer (Offs - Offset (File)) + 1 .. Last (File) loop Put (Str (S)); end loop; Offs := Offs + Long_Integer (Last (File)); end loop; Free (Reg); Close (File); end; There are a number of subtle details in the code above. Since the system call only manipulates chunk of the file on boundaries multiple of the code size, there is no guarantee that the part of the file we actually read really starts exactly at `Offs`. If could in fact start before, for rounding issues. Therefore when we loop over the contents of the buffer, we make sure to actually start at the `Offs`-th character in the file. In the particular case of this code, we make sure we only manipulate multiples of the page_size, so we could in fact replace the loop with the simpler:: for S in 1 .. Last (File) loop If you intend to modify the contents of the file, not that `GNATCOLL.Mmap` currently gives you no way to change the size of the file. The only difference compared to the code used for reading the file is the call to open the file, which should be:: File := Open_Write ("/tmp/file_on_disk"); Modifications to Str are automatically reflected in the file. However, there is no guarantee this saving is done immediately. It could be done only when you call `Close`. This is in particular always the case when your system does not support `mmap` and `GNATCOLL.Mmap` had to fallback on calls to `read`. alire-1.2.1/deps/gnatcoll-slim/docs/note.png000066400000000000000000000043071425465243200207250ustar00rootroot00000000000000‰PNG  IHDR"":G ÂbKGDÿÿÿ ½§“ pHYsHHFÉk>gIDATXÃí—kl[gÇçûØq|KâØ¹‘‹suœÛæ¦]Òµ ÓÚµ5ë†&b€´O“úBB|BÀ$$@ã ©hRÕ‚h«Q.em¤)¬£i:'nI¶Ù^Ü&qîqm×ñíø>¤ mÚn)Ò>ðH¯^éÕûüßÿÿÿ>çyáÿñ éÖ>< ”Y hŸÝ×úûû¿þÜsÏ“$i>Dý~ÿ‰Db4®®®~$õÿ5{cccïÑ£G£ÑXuäÈ‘ªõõu_0üÒõë×3¡PèÆÚÚÚÕp8|ejjê=`˜òŸžž@Eeee«ÕjEUU¬V+V«U¨¨¨äl6ÛyóæÍÎH$òÒüüüJ8} ¹\n,™LNq@á!r~,¿ßOKK‹¯££Ã P(H&“ȲLQQ‚ `4ikkÃëõŠŠ¢8ãñ¸3‘Hô-..f'&&~¿q~~~<‹] …B×’ÉdX¸;°Ö„®®®_?~üåÚÚZ2™ ‹‹‹¨ªºq«ÕŠÅbA¯×#¢("[«ªŠªªÌÏÏk“““LNN¦^}õÕãKKKÇÕ#öæææŽ²²24MC§ÓQ[[K¡P “ÉËåH$¬­­QWW‡Ñh@Ó´-P’$Q__/466âõzÍ'NœÐ/--=š4¢(¶ïÚµ«Ê`0 ±XŒL&ƒ^¯Çd2a·Û)//GÓ4$i£‚°ÅÈæ÷&;@ “ËåÞÞº# ’$¡×ë½­­­N£Ñˆªª”––’J¥Èf³$“IVVVÐ4 ‹Å‚ÝnÇd2¡Óéî° L&&&ÖgffÆúúúvÎH¡PÐ÷÷÷wº\.£(Šc6›QUEQP…|>ÏíÛ·™››Ãf³Q]]}ˆ;̋ŘÌçó‹£££$³½½½Ãår°´´ÄÈÈv»ŸÏGYY²,£iÚ€íÒlÎ’$‰DXZZnoš}ËC`2™*«««Û].š¦qúôY. ó׳çøÁwŽqöÌâñ8z½~ë¦lÎÛ‡(ŠLOO«@à]ŸÏ—۞¤R)¼^¯·¡¡Á!I…Bêê*‚S!ú[J˜[Ôøû…1®ú¯sàézzz°ÙlètºûØL&ÃÜÜÜh4ŽF£ìˆ úÁÁÁ=GÈd2TT8)â5U=Tv|ºT ã㣼ö›“xÚ.ñôÓOáp8°ÙlX­VdYF–eDQ$355b£üß”Æl6˜Çn·ÛªªX,:»zhöîCäLâ%ÚZJس§ö®ÃÌD³œþãVWWÉçóD"Âá0Š¢luttôýgžyfñA9ÈÈÑÔÝÝ]¥×ëQU•ÙÙYú¿ÉðŸc8g~IEQYYIr½@dAA,Å"UDÐ)+µQZZBQ‘ñNáÚ¨ åååìò=Æz*Áo¼( ìÞÝM»·Ë”ͱ{aaÖx;7[ìé\.ó‘)Ù»wïw_|ñÅ£Afz!ÏZReaMAEbÉW¦Òh¤³J ²ˆx×/Ý`0àñ´ÑÚÒÈùóá›oj==íìß7`DSßÍ›7l+ËÑ+l¼îrøða¢ÑhëÐÐз8P¤FYÄd”0›Dry°[$”‚ÆZ²ÀªÂbLAŒ²€Nº·¬ÛívææfoÿèÇ?üí{SS!³Y®{òɽEfK©72‰[ÿÜ”é³:tˆñññÊt:­¸Ýn,f3Ó^UÕ(³¡ªW4ÒY•èŠÂJ\¡Ê¡G+([[(âôéÓs™túWo½5»üìÀÀÀ—}¾=ûË¥/ÍÌL¿L¶žµ¥¥…7n”655}Áív÷»\®ÝõõõM>ŸÏèñxd»Ý.˜L&ôz=‹……‚Á ñxœ‹/*'OžüùÂÂÂ÷ï2h¹ÉdÚ¯Ó銉ęMy>ªy6æÒÒÒš’’’=%%%Otvv¶õööV7448«ªª 555Øív6›¦x<ÎÄÄÁ`+W®d.\¸p2¯¸¸x)•Jmß_à®§ÅNºø»Ãx‡§···³¹¹¹»¢¢¢£¶¶Öb6›‰F£- FÀï–——_cÛ³áañ¨@¶3æeÙYSSó¸N§«SUµH$Â+++WUU ¹O°ÿâ'<Øg#þ Þ.n¢fRÌIEND®B`‚alire-1.2.1/deps/gnatcoll-slim/docs/pools.rst000066400000000000000000000030271425465243200211360ustar00rootroot00000000000000****************************************** **Pools**: Controlling access to resources ****************************************** The package **GNATCOLL.Pools** provides resource pools. A pool contains a maximum number of resources, which are created on demand. However, once a resource is no longer needed by the client, it is not freed, but instead it is released to the pool, which will then return it again the next time a client requests a resource. The typical resource is when the creation of the resources is expensive, for instance a connection to a database or a remote server. The lazy creation then provides a faster startup time (as well as more flexibility, since there is no need to allocate dozens of resources if only one will be needed in the end), and more efficient retrieval through the reuse of resources. The pool in this package is task safe, and is intended as a global variable (or field of a global variable) somewhere in your application. The resources are implemented as reference-counted types (through `GNATCOLL.Refcount`). As a result, as soon as the client no longer has a handle on them, they are automatically released to the pool and there is no risk that the client forgets to do so. `GNATCOLL.Pools` is a generic package where the formal parameters describe the type of resources, how to create them on demand, what should happen when a resource is released, and finally how to free a resource when the pool itself is freed. See :file:`gnatcoll-pools.ads` for a full and up-to-date description of these parameters. alire-1.2.1/deps/gnatcoll-slim/docs/projects.rst000066400000000000000000000065471425465243200216450ustar00rootroot00000000000000.. _Projects: ************************************ **Projects**: manipulating gpr files ************************************ .. highlight:: ada The package `GNATCOLL.Projects` provides an extensive interface to parse, manipulate and edit project files (:file:`.gpr` files). Although the interface is best used using the Ada05 notation, it is fully compatible with Ada95. Here is a quick example on how to use the interface, although the spec file itself contains much more detailed information on all the subprograms related to the manipulation of project files:: pragma Ada_05; with GNATCOLL.Projects; use GNATCOLL.Projects; with GNATCOLL.VFS; use GNATCOLL.VFS; procedure Test_Project is Tree : Project_Tree; Files : File_Array_Access; begin Tree.Load (GNATCOLL.VFS.Create (+"path_to_project.gpr")); -- List the source files for project and all imported projects Files := Tree.Root_Project.Source_Files (Recursive => True); for F in Files'Range loop Put_Line ("File is: " & Files (F).Display_Full_Name); end loop; Tree.Unload; end Test_Project; Defining a project with user-defined packages and reading them. ================================================================= .. highlight:: ada If you want to use `GNATCOLL.Projects` with a GPR file that contains specific packages and attributes, you must procede in several steps. The following example will show you how to do it:: pragma Ada_05; with GNATCOLL.Projects; use GNATCOLL.Projects; with GNATCOLL.VFS; use GNATCOLL.VFS; procedure Test_Project is Tree : Project_Tree; Virtual_File : VFS; -- We assume it points to a valid file. begin -- 1 Register_New_Attribute ("String", "Package_Name"); Register_New_Attribute ("List", "Package_Name", Is_List => True); Register_New_Attribute ("Index", "Package_Name", Is_Index => True); -- 2 Tree.Load (Root_Project_Path => VFS, Packages_To_Check => All_Packs); declare -- 3 String_Attribute := constant Attribute_Pkg_String := Build ("string", "package_name") Index_Attribute := constant Attribute_Pkg_List := Build ("index", "package_name") List_Attribute := constant Attribute_Pkg_List := Build ("list", "package_name") begin -- 4 for Val in Tree.Root_Project.Attribute_Value (List_Attribute).all loop Put_Line ("Value:" & Val.all); end loop; declare Indexed_Value : constant String := Tree.Root_Project. Attribute_Value (Index_Attribute, Index => "Index").all begin Put_Line ("Indexed_Value:" & Indexed_Value); end; end; end Test_Project; Step 1: We register all the attributes that we want for a given package. If the package does not already exists it is created. Step 2: We load the project into the projects hierarchy. We tell Tree.Load to check all packages otherwise it will not load any packages. Step 3: We read the Attributes from the project. An attribute can be an Attribute_Pkg_String (representing a plain string) or an Attribute_Pkg_List (representing a list or an index). Step 4: We can do something with those values. Here we print the plain string and the content of the list, aswell as an indexed value from the index. alire-1.2.1/deps/gnatcoll-slim/docs/promises.rst000066400000000000000000000022521425465243200216420ustar00rootroot00000000000000.. highlight:: ada ************************************* **Promises**: deferring work ************************************* This package provides a way to synchronize work between some asynchronous workers (or threads). Promises are a way to encapsulate a yet unknown value, immediately return to the caller, and work in the background to actually execute the work. For instance, you could have a function that reads some data from a socket. This takes time, and we do not want to block the application while retrieving the data (and if there is an error retrieving it, we certainly want to properly handle it). The main thread (for instance a graphical user interface) needs to keep processing events and refresh itself. As soon as the data becomes available from the socket, we should let this main thread know so that it can take further action, like post-processing the data and then displaying it. A general scheme to do that is to have a callback function that is called whenever the work is finished. Promises build on that simple idea so that you can easily chain multiple callbacks to build more complex actions. See the extensive documentation in :file:`gnatcoll-promises.ads` alire-1.2.1/deps/gnatcoll-slim/docs/ravenscar.rst000066400000000000000000000034551425465243200217730ustar00rootroot00000000000000**************************************** **Ravenscar**: patterns for multitasking **************************************** .. index:: ravenscar GNATColl provides a set of patterns for concurrent programming using Ravenscar-compliant semantics only. The core goal of the GNATCOLL.Ravenscar (sub) packages is to ease the development of high-integrity multitasking applications by factorizing common behavior into instantiable, Ravenscar-compliant, generic packages. Instances of such generic packages guarantee predictable timing behavior and thus permit the application of most common timing analysis techniques. Tasks ===== The `GNATCOLL.Ravenscar.Simple_Cyclic_Task` generic package lets instantiate a cyclic tasks executing the same operation at regular time intervals; on the other side, the `GNATCOLL.Ravenscar.Simple_Sporadic_Task` task lets instantiate sporadic tasks enforcing a minimum inter-release time. Servers ======= Servers present a more sophisticated run-time semantics than tasks: for example, they can fulfill different kind of requests (see multiple queues servers). `Gnat.Ravenscar.Sporadic_Server_With_Callback` and `Gnat.Ravenscar.Timed_Out_Sporadic_Server` are particularly interesting. The former shows how synchronous inter-task communication can be faked in Ravenscar (the only form of communication permitted by the profile is through shared resources): the server receives a request to fulfill, computes the result and returns it by invoking a call-back. The latter enforces both a minimum and a maximum inter-release time: the server automatically releases itself and invokes an appropriate handler if a request is not posted within a given period of time. Timers ====== `Gnat.Ravenscar.Timers.One_Shot_Timer` is the Ravenscar implementation of time-triggered event through Ada 2005 Timing Events. alire-1.2.1/deps/gnatcoll-slim/docs/refcount.rst000066400000000000000000000121701425465243200216260ustar00rootroot00000000000000******************************** **Refcount**: Reference counting ******************************** .. highlight:: ada Memory management is often a difficulty in defining an API. Should we let the user be responsible for freeing the types when they are no longer needed, or can we do it automatically on his behalf ? The latter approach is somewhat more costly in terms of efficiency (since we need extra house keeping to know when the type is no longer needed), but provides an easier to use API. Typically, such an approach is implemented using reference counting: all references to an object increment a counter. When a reference disappears, the counter is decremented, and when it finally reaches 0, the object is destroyed. .. index:: reference counting This approach is made convenient in Ada using controlled types. However, there are a number of issues to take care of to get things exactly right. In particular, the Ada Reference Manual specifies that `Finalize` should be idempotent: it could be called several times for a given object, in particular when exceptions occur. An additional difficulty is task-safety: incrementing and decrementing the counter should be task safe, since the controlled object might be referenced from several task (the fact that other methods on the object are task safe or not is given by the user application, and cannot be ensures through the reference counting mecanism). To make things easier, GNATColl provides the package `GNATCOLL.Refcount`. This package contains a generic child package. To use it, you need to create a new tagged type that extends `GNATCOLL.Refcount.Refcounted`, so that it has a counter. Here is an example:: with GNATCOLL.Refcount; use GNATCOLL.Refcount; package My_Pkg is type My_Type is new Refcounted with record Field1 : ...; -- Anything end record; package My_Type_Ptr is new Smart_Pointers (My_Type); end My_Pkg; The code above makes a `Ref` available. This is similar in semantics to an access type, although it really is a controlled type. Every time you assign the `Ref`, the counter is incremented. When the `Ref` goes out of scope, the counter is decremented, and the object is potentially freed. Here an example of use of the package:: declare R : Ref; Tmp : My_Type := ...; begin Set (R, Tmp); -- Increment counter Get (R).Field1 := ...; -- Access referenced object end; -- R out of scope, so decrement counter, and free Tmp Although reference counting solves most of the issues with memory management, it can get tricky: when there is a cycle between two reference counted objects (one includes a reference to the other, and the other a reference to the first), their counter can never become 0, and thus they are never freed. There are, however, common design patterns where this can severly interfer: imagine you want to have a `Map`, associating a name with a reference counted object. Typically, the map would be a cache of some sort. While the object exists, it should be referenced in the map. So we would like the Map to store a reference to the object. But that means the object will then never be freed while the map exists either, and memory usage will only increase. .. index:: reference, weak The solution to this issue is to use `weak references`. These hold a pointer to an object, but do not increase its counter. As a result, the object can eventually be freed. At that point, the internal data in the weak reference is reset to `null`, although the weak reference object itself is still valid. Here is an example:: with GNATCOLL.Refcount.Weakref; use GNATCOLL.Refcount.Weakref; type My_Type is new Weak_Refcounted with...; package Pointers is new Weakref_Pointers (My_Type); The above code can be used instead of the code in the first example, and provides the same capability (smart pointers, reference counted types,...). However, the type `My_Type` is slightly bigger, but can be used to create weak references:: WR : Weak_Ref; declare R : Ref; Tmp : My_Type := ...; begin Set (R, Tmp); -- Increment counter WR := Get_Weak_Ref (R); -- Get a weak reference Get (R).Field1 := ...; -- Access referenced object Get (Get (WR)).Field1 := ...; -- Access through weak ref end; -- R out of scope, so decrement counter, and free Tmp if Get (WR) /= Null_Ref then -- access to WR still valid -- Always true, since Tmp was freed end if; The example above is very simplified. Imagine, however, that you store `WR` in a map. Even when `R` is deallocated, the contents of the map remains accessible without a `Storage_Error` (although using `Get` will return `Null_Ref`, as above). For task-safety issues, `Get` on a weak-reference returns a smart pointer. Therefore, this ensures that the object is never freed while that smart pointer object lives. As a result, we recommend the following construct in your code:: declare R : constant Ref := Get (WR); begin if R /= Null_Ref then -- Get (R) never becomes null while in this block end if; end; alire-1.2.1/deps/gnatcoll-slim/docs/scripting.rst000066400000000000000000001272731425465243200220160ustar00rootroot00000000000000.. _Embedding_script_languages: *************************************** **Scripts**: Embedding script languages *************************************** In a lot of contexts, you want to give the possibility to users to extend your application. This can be done in several ways: define an Ada API from which they can build dynamically loadable modules, provide the whole source code to your application and let users recompile it, interface with a simpler scripting languages,... Dynamically loadable modules can be loaded on demand, as their name indicate. However, they generally require a relatively complex environment to build, and are somewhat less portable. But when your users are familiar with Ada, they provide a programming environment in which they are comfortable. As usual, changing the module requires recompilation, re-installation,... Providing the source code to your application is generally even more complex for users. This requires an even more complex setup, your application is generally too big for users to dive into, and modifications done by one users are hard to provide to other users, or will be lost when you distribute a new version of your application. The third solution is to embed one or more scripting languages in your application, and export some functions to it. This often requires your users to learn a new language, but these languages are generally relatively simple, and since they are interpreted they are easier to learn in an interactive console. The resulting scripts can easily be redistributed to other users or even distributed with future versions of your application. The module in GNATColl helps you implement the third solution. It was used extensively in the GPS programming environment for its python interface. |Tip| Each of the scripting language is optional This module can be compiled with any of these languages as an optional dependency (except for the shell language, which is always built-in, but is extremely minimal, and doesn't have to be loaded at run time anyway). If the necessary libraries are found on the system, GNATColl will be build with support for the corresponding language, but your application can chose at run time whether or not to activate the support for a specific language. .. index:: test driver .. index:: testing your application |Tip| Use a scripting language to provide an automatic testing framework for your application. The GPS environment uses python command for its *automatic test suite*, including graphical tests such as pressing on a button, selecting a menu,... .. _Supported_languages: Supported languages =================== The module provides built-in support for several scripting languages, and other languages can "easily" be added. Your application does not change when new languages are added, since the interface to export subprograms and classes to the scripting languages is language-neutral, and will automatically export to all known scripting languages. The Core component provides support for the following language: *Shell* This is a very simple-minded scripting language, which doesn't provide flow-control instructions (:ref:`The_Shell_language`). Optional components add support for other languages, e.g. Python. Please refer to the corresponding component's documentation. .. _The_Shell_language: The Shell language ------------------ The shell language was initially developed in the context of the GPS programming environment, as a way to embed scripting commands in XML configuration files. In this language, you can execute any of the commands exported by the application, passing any number of arguments they need. Arguments to function calls can, but need not, be quoted. Quoting is only mandatory when they contain spaces, newline characters, or double-quotes ('"'). To quote an argument, surround it by double-quotes, and precede each double-quote it contains by a backslash character. Another way of quoting is similar to what python provides, which is to triple-quote the argument, i.e. surround it by '"""' on each side. In such a case, any special character (in particular other double-quotes or backslashes) lose their special meaning and are just taken as part of the argument. This is in particular useful when you do not know in advance the contents of the argument you are quoting:: Shell> function_name arg1 "arg 2" """arg 3""" Commands are executed as if on a stack machine: the result of a command is pushed on the stack, and later commands can reference it using `%` following by a number. By default, the number of previous results that are kept is set to 9, and this can only be changed by modifying the source code for GNATColl. The return values are also modified by commands executed internally by your application, and that might have no visible output from the user's point of view. As a result, you should never assume you know what `%1`,... contain unless you just executed a command in the same script:: Shell> function_name arg1 Shell> function2_name %1 In particular, the `%1` syntax is used when emulating object-oriented programming in the shell. A method of a class is just a particular function that contains a '.' in its name, and whose first implicit argument is the instance on which it applies. This instance is generally the result of calling a constructor in an earlier call. Assuming, for instance, that we have exported a class "Base" to the shell from our Ada core, we could use the following code:: Shell> Base arg1 arg2 Shell> Base.method %1 arg1 arg2 to create an instance and call one of its methods. Of course, the shell is not the best language for object-oriented programming, and better languages should be used instead. When an instance has associated properties (which you can export from Ada using `Set_Property`), you access the properties by prefixing its name with "@":: Shell> Base arg1 arg2 # Build new instance Shell> @id %1 # Access its "id" field Shell> @id %1 5 # Set its "id" field Some commands are automatically added to the shell when this scripting language is added to the application. These are .. index:: Function load `Function load (file)` Loads the content of `file` from the disk, and execute each of its lines as a Shell command. This can for instance be used to load scripts when your application is loaded .. index:: Function echo `Function echo (arg...)` This function takes any number of argument, and prints them in the console associated with the language. By default, when in an interactive console, the output of commands is automatically printed to the console. But when you execute a script through `load` above, you need to explicitly call `echo` to make some output visible. .. index:: Function clear_cache `Function clear_cache` This frees the memory used to store the output of previous commands. Calling `%1` afterward will not make sense until further commands are executed. .. _Classes_exported_to_all_languages: Classes exported to all languages --------------------------------- In addition to the functions exported by each specific scripting language, as described above, GNATColl exports the following to all the scripting languages. These are exported when your Ada code calls the Ada procedure `GNATCOLL.Scripts.Register_Standard_Classes`, which should done after you have loaded all the scripting languages. .. index:: Class Console `Class Console` `Console` is a name that you can chose yourself when you call the above Ada procedure. It will be assumed to be `Console` in the rest of this document. This class provides an interface to consoles. A console is an input/output area in your application (whether it is a text area in a graphical application, or simply standard text I/O in text mode). In particular, the python standard output streams `sys.stdin`, `sys.stdout` and `sys.stderr` are redirected to an instance of that class. If you want to see python's error messages or usual output in your application, you must register that class, and define a default console for your scripting language through calls to `GNATCOLL.Scripts.Set_Default_Console`. You can later add new methods to this class, which would be specific to your application. Or you can derive this class into a new class to achieve a similar goal. .. index:: Console.write `Console.write(text)` This method writes `text` to the console associated with the class instance. See the examples delivered with GNATColl for examples on how to create a graphical window and make it into a `Console`. .. index:: Console.clear `Console.clear()` Clears the contents of the console. .. index:: Console.flush `Console.flush()` Does nothing currently, but is needed for compatibility with python. Output through `Console` instances is not buffered anyway. .. index:: Console.isatty `Console.isatty(): Boolean` Whether the console is a pseudo-terminal. This is always wrong in the case of GNATColl. .. index:: Console.read `Console.read([size]): string` Reads at most `size` bytes from the console, and returns the resulting string. .. index:: Console.readline `Console.readline([size]): string` Reads at most `size` lines from the console, and returns them as a single string. .. _Scripts_API: Scripts API =========== This section will give an overview of the API used in the scripts module. The reference documentation for this API is in the source files themselves. In particular, each :file:`.ads` file fully documents all its public API. As described above, GNATColl contains several levels of API. In particular, it provides a low-level interface to python, in the packages `GNATCOLL.Python`. This interface is used by the rest of GNATColl, but is likely too low-level to really be convenient in your applications, since you need to take care of memory management and type conversions by yourself. Instead, GNATColl provides a language-neutral Ada API. Using this API, it is transparent for your application whether you are talking to the Shell, to python, or to another language integrated in GNATColl. The code remains exactly the same, and new scripting languages can be added in later releases of GNATColl without requiring a change in your application. This flexibility is central to the design of GNATColl. In exchange for that flexibility, however, there are language-specific features that cannot be performed through the GNATColl API. At present, this includes for instance exporting functions that return hash tables. But GNATColl doesn't try to export the greatest set of features common to all languages. On the contrary, it tries to fully support all the languages, and provide reasonable fallback for languages that do not support that feature. For instance, named parameters (which are a part of the python language) are fully supported, although the shell language doesn't support them. But that's an implementation detail transparent to your own application. Likewise, your application might decide to always load the python scripting language. If GNATColl wasn't compiled with python support, the corresponding Ada function still exists (and thus your code still compiles), although of course it does nothing. But since the rest of the code is independent of python, this is totally transparent for your application. |Tip| GNATColl comes with some examples, which you can use as a reference when building your own application. See the :file:`/share/examples/gnatcoll` directory. Interfacing your application with the scripting module is a multistep process: * You *must* **initialize** GNATColl and decide which features to load * You *can* create an **interactive console** for the various languages, so that users can perform experiments interactively. This is optional, and you could decide to keep the scripting language has a hidden implementation detail (or just for automatic testing purposes for instance) * You *can* **export** some classes and methods. This is optional, but it doesn't really make sense to just embed a scripting language and export nothing to it. In such a case, you might as well spawn a separate executable. * You *can* load **start up scripts** or plug-ins that users have written to extend your application. .. _Initializing_the_scripting_module: Initializing the scripting module --------------------------------- GNATColl must be initialized properly in order to provide added value to your application. This cannot be done automatically simply by depending on the library, since this initialization requires multiple-step that must be done at specific moments in the initialization of your whole application. This initialization does not depend on whether you have build support for python in GNATColl. The same packages and subprograms are available in all cases, and therefore you do not need conditional compilation in your application to support the various cases. .. _Create_the_scripts_repository: Create the scripts repository ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The type `GNATCOLL.Scripts.Scripts_Repository` will contain various variables common to all the scripting languages, as well as a list of the languages that were activated. This is the starting point for all other types, since from there you have access to everything. You will have only one variable of this type in your application, but it should generally be available from all the code that interfaces with the scripting language. Like the rest of GNATColl, this is a tagged type, which you can extend in your own code. For instance, the GPS programming environment is organized as a kernel and several optional modules. The kernel provides the core functionality of GPS, and should be available from most functions that interface with the scripting languages. Since these functions have very specific profiles, we cannot pass additional arguments to them. One way to work around this limitation is to store the additional arguments (in this case a pointer to the kernel) in a class derived from `Scripts_Repository_Data`. .. highlight:: ada As a result, the code would look like:: with GNATCOLL.Scripts; Repo : Scripts_Repository := new Scripts_Repository_Record; or, in the more complex case of GPS described above:: type Kernel_Scripts_Repository is new Scripts_Repository_Data with record Kernel : ...; end record; Repo : Scripts_Repository := new Kernel_Scripts_Repository' (Scripts_Repository_Data with Kernel => ...); .. _Loading_the_scripting_language: Loading the scripting language ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The next step is to decide which scripting languages should be made available to users. This must be done before any function is exported, since only functions exported after a language has been loaded will be made available in that language. |Note| If for instance python support was build into GNATColl, and if you decide not to make it available to users, your application will still be linked with :file:`libpython`. It is therefore recommended although not mandatory to only build those languages that you will use. This is done through a simple call to one or more subprograms. The following example registers both the shell and python languages:: with GNATCOLL.Scripts.Python; with GNATCOLL.Scripts.Shell; Register_Shell_Scripting (Repo); Register_Python_Scripting (Repo, "MyModule"); .. index:: Procedure Register_Shell_Scripting `Procedure Register_Shell_Scripting (Repo)` This adds support for the shell language. Any class or function that is now exported through GNATColl will be made available in the shell .. index:: Procedure Register_Python_Scripting `Procedure Register_Python_Scripting (Repo, Module_Name)` This adds support for the python language. Any class or function exported from now on will be made available in python, in the module specified by `Module_Name` .. _Exporting_standard_classes: Exporting standard classes ^^^^^^^^^^^^^^^^^^^^^^^^^^ To be fully functional, GNATColl requires some predefined classes to be exported to all languages (:ref:`Classes_exported_to_all_languages`). For instance, the `Console` class is needed for proper interactive with the consoles associated with each language. These classes are created with the following code:: Register_Standard_Classes (Repo, "Console"); This must be done only after all the scripting languages were loaded in the previous step, since otherwise the new classes would not be visible in the other languages. .. index:: Procedure Register_Standard_Classes `Procedure Register_Standard_Classes(Repo,Console_Class)` The second parameter `Console_Class` is the name of the class that is bound to a console, and thus provides input/output support. You can chose this name so that it matches the classes you intend to export later on from your application. .. _Creating_interactive_consoles: Creating interactive consoles ----------------------------- The goal of the scripting module in GNATColl is to work both in text-only applications and graphical applications. However, in both cases applications will need a way to capture the output of scripting languages and display them to the user (at least for errors, to help debugging scripts), and possibly emulate input when a script is waiting for such input. GNATColl solved this problem by using an abstract class `GNATCOLL.Scripts.Virtual_Console_Record` that defines an API for these consoles. This API is used throughout `GNATCOLL.Scripts` whenever input or output has to be performed. |Tip| The :file:`examples/` directory in the GNATColl package shows how to implement a console in text mode and in graphical mode. If you want to provide feedback or interact with users, you will need to provide an actual implementation for these `Virtual_Console`, specific to your application. This could be a graphical text window, or based on `Ada.Text_IO`. The full API is fully documented in :file:`gnatcoll-scripts.ads`, but here is a list of the main subprograms that need to be overriden. .. index:: Virtual_Console.Insert_Text `Virtual_Console.Insert_Text (Txt)` .. index:: Virtual_Console.Insert_Log `Virtual_Console.Insert_Log (Txt)` .. index:: Virtual_Console.Insert_Error `Virtual_Console.Insert_Error (Txt)` These are the various methods for doing output. Error messages could for instance be printed in a different color. Log messages should in general be directed elsewhere, and not be made visible to users unless in special debugging modes. .. index:: Virtual_Console.Insert_Prompt `Virtual_Console.Insert_Prompt (Txt)` This method must display a prompt so that the user knows input is expected. Graphical consoles will in general need to remember where the prompt ended so that they also know where the user input starts .. index:: Virtual_Console.Set_As_Default_Console `Virtual_Console.Set_As_Default_Console (Script)` This method is called when the console becomes the default console for a scripting language. They should in general keep a pointer on that language, so that when the user presses :kbd:`enter` they know which language must execute the command .. index:: Virtual_Console.Read `Virtual_Console.Read (Size, Whole_Line) : String` Read either several characters or whole lines from the console. This is called when the user scripts read from their stdin. .. index:: Virtual_Console.Set_Data_Primitive `Virtual_Console.Set_Data_Primitive (Instance)` .. index:: Virtual_Console.Get_Instance `Virtual_Console.Get_Instance : Console` These two methods are responsible for storing an instance of `Console` into a `GNATCOLL.Scripts.Class_Instance`. Such an instance is what the user manipulates from his scripting language. But when he executes a method, the Ada callback must know how to get the associated `Virtual_Console` back to perform actual operations on it. These methods are implemented using one of the `GNATCOLL.Scripts.Set_Data` and `GNATCOLL.Scripts.Get_Data` operations when in text mode. .. highlight:: ada Once you have created one or more of these console, you can set them as the default console for each of the scripting languages. This way, any input/output done by scripts in this language will interact with that console, instead of being discarded. This is done through code similar to:: Console := GtkConsole.Create (...); Set_Default_Console (Lookup_Scripting_Language (Repo, "python"), Virtual_Console (Console)); Creating a new instance of `Console`, although allowed, will by default create an unusable console. Indeed, depending on your application, you might want to create a new window, reuse an existing one, or do many other things when the user does:: c = Console() As a result, GNATColl does not try to guess the correct behavior, and thus does not export a constructor for the console. So in the above python code, the default python constructor is used. But this constructor does not associate `c` with any actual `Virtual_Console`, and thus any call to a method of `c` will result in an error. To make it possible for users to create their own consoles, you need to export a `Constructor_Method` (see below) for the `Console` class. In addition to your own processing, this constructor needs also to call:: declare Inst : constant Class_Instance := Nth_Arg (Data, 1); begin C := new My_Console_Record; -- or your own type GNATCOLL.Scripts.Set_Data (Inst, C); end .. _Exporting_classes_and_methods: Exporting classes and methods ----------------------------- Once all scripting languages have been loaded, you can start exporting new classes and functions to all the scripting languages. It is important to realize that through a single Ada call, they are exported to all loaded scripting languages, without further work required on your part. .. _Classes_diagram: Classes diagram ^^^^^^^^^^^^^^^ The following diagram shows the dependencies between the major data types defined in :file:`GNATCOLL.Scripts`. Most of these are abstract classes that are implemented by the various scripting languages. Here is a brief description of the role of each type: .. index:: class diagram, script module .. image:: classes.png .. index:: Class Scripts_Repository `Class Scripts_Repository` As we have seen before, this is a type of which there is a single instance in your whole application, and whose main role is to give access to each of the scripting languages (`Lookup_Scripting_Language` function), and to make it possible to register each exported function only once (it then takes care of exporting it to each scripting language). .. index:: Class Scripting_Language `Class Scripting_Language` Instances of this type represent a specific language. It provides various operations to export subprograms, execute commands, create the other types described below,... There should exists a single instance of this class per supported language. This class interacts with the script interpreter (for instance python), and all code executed in python goes through this type, which then executes your Ada callbacks to perform the actual operation. It is also associated with a default console, as described above, so that all input and output of the scripts can be made visible to the user. .. index:: Class Callback_Data `Class Callback_Data` This type is an opaque tagged type that provides a language-independent interface to the scripting language. It gives for instance access to the various parameters passed to your subprogram (`Nth_Arg` functions), allows you to set the return value (`Set_Return_Value` procedure), or raise exceptions (`Set_Error_Msg` procedure),... .. index:: Record Class_Type `Record Class_Type` This type is not tagged, and cannot be extended. It basically represents a class in any of the scripting languages, and is used to create new instances of that class from Ada. .. index:: Class Class_Instance `Class Class_Instance` A class instance represents a specific instance of a class. In general, such an instance is strongly bound to an instance of an Ada type. For instance, if you have a `Foo` type in your application that you wish to export, you would create a `Class_Type` called "Foo", and then the user can create as many instances as he wants of that class, each of which is associated with different values of `Foo` in Ada. Another more specific example is the predefined `Console` class. As we have seen before, this is a `Virtual_Console` in Ada. You could for instance have two graphical windows in your application, each of which is a `Virtual_Console`. In the scripting language, this is exported as a class named `Console`. The user can create two instances of those, each of which is associated with one of your graphical windows. This way, executing `Console.write` on these instances would print the string on their respective graphical window. .. highlight:: python Some scripting languages, in particular python, allow you to store any data within the class instances. In the example above, the user could for instance store the time stamp of the last output in each of the instances. It is therefore important that, as much as possible, you always return the same `Class_Instance` for a given Ada object. See the following python example:: myconsole = Console ("title") # Create new console myconsole.mydata = "20060619" # Any data, really myconsole = Console ("title2") # Create another window myconsole = Console ("title") # Must be same as first, print myconsole.mydata # so that this prints "20060619" .. index:: Class Instance_Property `Class Instance_Property` As we have seen above, a `Class_Instance` is associated in general with an Ada object. This `Instance_Property` tagged type should be extended for each Ada type you want to be able to store in a `Class_Instance`. You can then use the `Set_Data` and `Get_Data` methods of the `Class_Instance` to get and retrieve that associated Ada object. .. index:: Class Subprogram_Record `Class Subprogram_Record` This class represents a callback in the scripting language, that is some code that can be executed when some conditions are met. The exact semantic here depends on each of the programming languages. For instance, if you are programming in python, this is the name of a python method to execute. If you are programming in shell, this is any shell code. .. highlight:: python The idea here is to blend in as smoothly as possible with the usual constructs of each language. For instance, in python one would prefer to write the second line rather than the third:: def on_exit(): pass set_on_exit_callback(on_exit) # Yes, python style set_on_exit_callback("on_exit") # No The last line (using a string as a parameter) would be extremely unusual in python, and would for instance force you to qualify the subprogram name with the name of its namespace (there would be no implicit namespace resolution). To support this special type of parameters, the `Subprogram_Record` type was created in Ada. Although the exact way they are all these types are created is largely irrelevant to your specific application in general, it might be useful for you to override part of the types to provide more advanced features. For instance, GPS redefines its own Shell language, that has basically the same behavior as the Shell language described above but whose `Subprogram_Record` in fact execute internal GPS actions rather than any shell code. .. _Exporting_functions: Exporting functions ^^^^^^^^^^^^^^^^^^^ .. highlight:: ada All functions that you export to the scripting languages will result in a call to an Ada subprogram from your own application. This subprogram must have the following profile:: procedure Handler (Data : in out Callback_Data'Class; Command : String); The first parameter `Data` gives you access to the parameters of the subprogram as passed from the scripting language, and the second parameter `Command` is the name of the command to execute. The idea behind this second parameter is that a single Ada procedure might handle several different script function (for instance because they require common actions to be performed). .. index:: Register_Command `Register_Command (Repo,Command,Min_Args,Max_Args,Handler)` Each of the shell functions is then exported through a call to `Register_Command`. In its simplest form, this procedure takes the following arguments. `Repo` is the scripts repository, so that the command is exported to all the scripting languages. `Command` is the name of the command. `Min_Args` and `Max_Args` are the minimum and maximum number of arguments. Most language allow option parameters, and this is how you specify them. `Handler` is the Ada procedure to call to execute the command. Here is a simple example. It implements a function called `Add`, which takes two integers in parameter, and returns their sum:: Arg1_C : aliased constant String := "arg1"; Arg2_C : aliased constant String := "arg2"; procedure Sum (Data : in out Callback_Data'Class; Command : String) is Arg1, Arg2 : Integer; begin Name_Parameters ((1 => Arg1_C'Access, 2 => Arg2_C'Access)); Arg1 := Nth_Arg (Data, 1); Arg2 := Nth_Arg (Data, 2); Set_Return_Value (Data, Arg1 + Arg2); end Sum; Register_Command (Repo, "sum", 2, 2, Sum'Access); This is not the most useful function to export! Still, it illustrates a number of important concepts. Automatic parameters types ~~~~~~~~~~~~~~~~~~~~~~~~~~ When the command is registered, the number of arguments is specified. This means that GNATColl will check on its own whether the right number of arguments is provided. But the type of these arguments is not specified. Instead, your callback should proceed as if they were correct, and try to retrieve them through one of the numerous `Nth_Arg` functions. In the example above, we assume they are integer. But if one of them was passed as a string, an exception would be raised and sent back to the scripting language to display a proper error message to the user. You have nothing special to do here. Support for named parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some languages (especially python) support named parameters, ie parameters can be specified in any order on the command line, as long as they are properly identified (very similar to Ada's own capabilities). In the example above, the call to `Name_Parameters` is really optional, but adds this support for your own functions as well. You just have to specify the name of the parameters, and GNATColl will then ensure that when you call `Nth_Arg` the parameter number 1 is really "arg1". For scripting languages that do not support named parameters, this has no effect. Your code can then perform as complex a code as needed, and finally return a value (or not) to the scripting language, through a call to `Set_Return_Value`. .. highlight:: python After the above code has been executed, your users can go to the python console and type for instance:: from MyModule import * # MyModule is the name we declared above print sum (1,2) => 3 print sum () => Error: Wrong number of parameters print sum ("1", 2) => Error: Parameter 1 should be an integer print sum (arg2=2, arg1=1) => 3 .. _Exporting_classes: Exporting classes ^^^^^^^^^^^^^^^^^ Whenever you want to make an Ada type accessible through the scripting languages, you should export it as a class. For object-oriented languages, this would map to the appropriate concept. For other languages, this provides a namespace, so that each method of the class now takes an additional first parameter which is the instance of the class, and the name of the method is prefixed by the class name. .. highlight:: ada Creating a new class is done through a call to `New_Class`, as shown in the example below:: MyClass : Class_Type; MyClass := GNATCOLL.Scripts.New_Class (Repo, "MyClass"); At this stage, nothing is visible in the scripting language, but all the required setup has been done internally so that you can now add methods to this class. You can then register the class methods in the same way that you registered functions. An additional parameter `Class` exists for `Register_Command`. A method is really just a standard function that has an implicit first parameter which is a `Class_Instance`. This extra parameter should not be taken into account in `Min_Args` and `Max_Args`. You can also declare the method as a static method, ie one that doesn't take this extra implicit parameter, and basically just uses the class as a namespace. Some special method names are available. In particular, `Constructor_Method` should be used for the constructor of a class. It is a method that receives, as its first argument, a class instance that has just been created. It should associate that instance with the Ada object it represents. .. highlight:: python Here is a simple example that exports a class. Each instance of this class is associated with a string, passed in parameter to the constructor. The class has a single method `print`, which prints its string parameter prefixed by the instance's string. To start with, here is a python example on what we want to achieve:: c1 = MyClass ("prefix1") c1.print ("foo") => "prefix1 foo" c2 = MyClass () # Using a default prefix c2.print ("foo") => "default foo" .. highlight:: ada Here is the corresponding Ada code:: with GNATCOLL.Scripts.Impl; procedure Handler (Data : **in out** Callback_Data'Class; Command : String) is Inst : Class_Instance := Nth_Arg (Data, 1, MyClass); begin if Command = Constructor_Method then Set_Data (Inst, MyClass, Nth_Arg (Data, 2, "default")); elsif Command = "print" then Insert_Text (Get_Script (Data), null, String'(Get_Data (Inst)) & " " & Nth_Arg (Data, 2)); end if; end Handler; Register_Command (Repo, Constructor_Method, 0, 1, Handler'Access, MyClass); Register_Command (Repo, "print", 1, 1, Handler'Access, MyClass); This example also demonstrates a few concepts: the constructor is declared as a method that takes one optional argument. The default value is in fact passed in the call to `Nth_Arg` and is set to "default". In the handler, we know there is always a first argument which is the instance on which the method applies. The implementation for the constructor stores the prefix in the instance itself, so that several instances can have different prefixes (we can't use global variables, of course, since we don't know in advance how many instances will exist). The implementation for `print` inserts code in the default console for the script (we could of course use `Put_Line` or any other way to output data), and computes the string to output by concatenating the instance's prefix and the parameter to `print`. Note that `Set_Data` and `Get_Data` take the class in parameter, in addition to the class instance. This is needed for proper handling of multiple inheritance: say we have a class `C` that extends two classes `A` and `B`. The Ada code that deals with `A` associates an integer with the class instance, whereas the code that deals with `B` associates a string. Now, if you have an instance of `C` but call a method inherited from `A`, and if `Get_Data` didn't specify the class, there would be a risk that a string would be returned instead of the expected integer. In fact, the proper solution here is that both `A` and `B` store their preferred data at the same time in the instances, but only fetch the one they actually need. Therefore instances of `C` are associated with two datas. Here is a more advanced example that shows how to export an Ada object. Let's assume we have the following Ada type that we want to make available to scripts:: type MyType is record Field : Integer; end record; As you can see, this is not a tagged type, but could certainly be. There is of course no procedure `Set_Data` in :file:`GNATCOLL.Scripts` that enables us to store `MyType` in a `Class_Instance`. This example shows how to write such a procedure. The rest of the code would be similar to the first example, with a constructor that calls `Set_Data`, and methods that call `Get_Data`:: type MyPropsR is new Instance_Property_Record with record Val : MyType; end record; type MyProps is access all MyPropsR'Class; procedure Set_Data (Inst : Class_Instance; Val : MyType) is begin Set_Data (Inst, Get_Name (MyClass), MyPropsR'(Val => Val)); end Set_Data; function Get_Data (Inst : Class_Instance) return MyType is Data : MyProps := MyProps (Instance_Property' (Get_Data (Inst, Get_Name (MyClass)))); begin return Data.Val; end Get_Data; Several aspects worth noting in this example. Each data is associated with a name, not a class as in the previous example. That's in fact the same thing, and mostly for historical reasons. We have to create our own instance of `Instance_Property_Record` to store the data, but the implementation presents no special difficulty. In fact, we don't absolutely need to create `Set_Data` and `Get_Data` and could do everything inline in the method implementation, but it is cleaner this way and easier to reuse. GNATColl is fully responsible for managing the lifetime of the data associated with the class instances and you can override the procedure `Destroy` if you need special memory management. .. _Reusing_class_instances: Reusing class instances ^^^^^^^^^^^^^^^^^^^^^^^ We mentioned above that it is more convenient for users of your exported classes if you always return the same class instance for the same Ada object (for instance a graphical window should always be associated with the same class instance), so that users can associate their own internal data with them. GNATColl provides a few types to facilitate this. In passing, it is worth noting that in fact the Ada objects will be associated with a single instance *per scripting language*, but each language has its own instance. Data is not magically transferred from python to shell! You should store the list of associated instances with your object. The type `GNATCOLL.Scripts.Instance_List_Access` is meant for that purpose, and provides two `Set` and `Get` primitives to retrieve existing instances. The final aspect to consider here is how to return existing instances. This cannot be done from the constructor method, since when it is called it has already received the created instance (this is forced by python, and was done the same for other languages for compatibility reasons). There are two ways to work around that limitation: * Static `get` methods .. highlight:: python With each of your classes, you can export a static method generally called `get` that takes in parameter a way to identify an existing instance, and either return it or create a new one. It is also recommended to disable the constructor, ie force it to raise an error. Let's examine the python code as it would be used:: ed = Editor ("file.adb") # constructor => Error, cannot construct instances ed = Editor.get ("file.adb") => Create a new instance ed2 = Editor.get ("file.adb") => Return existing instance ed == ed2 => True .. highlight:: ada The corresponding Ada code would be something like:: type MyType is record Val : Integer; Inst : Instance_List_Access; end record; type MyTypeAccess is access all MyType; procedure Handler (Data : in out Callback_Data'Class; Cmd : String) is Inst : Class_Instance; Tmp : MyTypeAccess; begin if Cmd = Constructor_Method then Set_Error_Msg (Data, "cannot construct instances"); elsif Cmd = "get" then Tmp := check_if_exists (Nth_Arg (Data, 1)); if Tmp = null then Tmp := create_new_mytype (Nth_Arg (Data, 1)); Tmp.Inst := new Instance_List; end if; Inst := Get (Tmp.Inst.all, Get_Script (Data)); if Inst = No_Class_Instance then Inst := New_Instance (Get_Script (Data), MyClass); Set (Tmp.Inst.all, Get_Script (Data), Inst); Set_Data (Inst, Tmp); end if; Set_Return_Value (Data, Inst); end if; end Handler; * Factory classes The standard way to do this in python, which applies to other languages as well, is to use the Factory design pattern. For this, we need to create one class (`MyClassImpl`) and one factory function (`MyClass`). .. highlight:: python The python code now looks like:: ed = MyClass ("file.adb") # Create new instance => ed is of type MyClassImpl ed = MyClass ("file.adb") # return same instance ed.do_something() It is important to realize that in the call above, we are not calling the constructor of a class, but a function. At the Ada level, the function has basically the same implementation as the one we gave for `get` above. But the python code looks nicer because we do not have these additional `.get()` calls. The name of the class `MyClassImpl` doesn't appear anywhere in the python code, so this is mostly transparent. However, if you have more than one scripting language, in particular for the shell, the code looks less nice in this case:: MyClass "file.adb" => MyClassImpl.do_something %1 and the new name of the class is visible in the method call. .. _Executing_startup_scripts: Executing startup scripts ------------------------- The final step in starting up your application is to load extensions or plug-ins written in one of the scripting languages. There is not much to be said here, except that you should use the `GNATCOLL.Scripts.Execute_File` procedure to do so. .. _Debugging_scripts: Multithreading applications and scripts --------------------------------------- Python itself is not thread-safe. So a single thread can call the python C API at a time. To enforce this, the python interpreter provides a global interpreter lock, which you must acquire before calling the C API, and release when you are done. To simulate multitasking, the python interpreter will in fact release and reacquire the lock every 100 micro-instructions (opcodes in the python virtual machine), to give a chance to run to other tasks. So this is preemptive multitasking. The threads that are created in Ada that do not need access to python do not need any special handling. However, those that need access to python must make a special function call before they first call the python C API, so that python can create a thread-specific data for them. `GNATCOLL.Scripts.Python` contains a number of subprograms to interact with the global interpreter lock of the python engine. The initialization of your application needs to do two extra calls:: Register_Python_Scripting (...); Initialize_Threads_Support; -- Also acquires the lock Begin_Allow_Threads; -- Releases the lock Whenever a task needs to execute python commands (or basically use any subprogram from `GNATCOLL.Scripts`, it needs to do the following:: Ensure_Thread_State; -- Block all python threads ... access to python C API as usual Begin_Allow_Threads; -- Let other python threads run In some cases, the simplest is to get the lock at the beginning of the task, and release it when done. This assumes the task executes fast enough. In other cases, you will need finer grain control over the lock. Debugging scripts ----------------- GNATColl provides a convenient hook to debug your script. By default, a script (python for instance) will call your Ada callback, which might raise errors. Most of the time, the error should indeed be reported to the user, and you can thus raise a standard exception, or call `Set_Error_Msg`. But if you wish to know which script was executing the command, it is generally not doable. You can however activate a trace (:ref:`Logging_information`) called `"PYTHON.TB"` (for "traceback"), which will output the name of the command that is being executed, as well as the full traceback within the python scripts. This will help you locate which script is raising an exception. alire-1.2.1/deps/gnatcoll-slim/docs/sql.rst000066400000000000000000002413771425465243200206150ustar00rootroot00000000000000*************************** **SQL**: Database interface *************************** .. highlight:: ada A lot of applications need to provide **persistence** for their data (or a part of it). This means the data needs to be somehow saved on the disk, to be read and manipulated later, possibly after the application has been terminated and restarted. Although Ada provides various solutions for this (including the use of the streams as declared in the Ada Reference Manual), the common technics is through the use of relational database management systems (**RDBMS**. The term database is in fact overloaded in this context, and has come to mean different things: * The software system that implements file and query management. This is generally provided by a third-party. The common abbreviation for these is **DBMS**. Queries are generally written in a language called **SQL**. One of the issues is that each DBMS tends to make minor changes to this language. Another issue is that the way to send these SQL commands to the DBMS is vendor-specific. GNATColl tries to abstract this communication through its own API. Optional components can instantiate this framework to specific DBMS, for example **PostgreSQL** and **sqlite**. Common API makes it relatively easy to change between two systems. For instance, development could be done using a local sqlite DBMS, and then deployed (after testing, of course!) on a PostgreSQL system. The code in GNATColl is such that adding support for a new DBMS should be relatively easy. * A place where an application stores its data. The term **database** in this document refers to this meaning. In a relational database, this place is organized into tables, each of which contains a number of fields. A row in a table represents one object. The set of tables and their fields is called the **schema** of the database. Traditionally, writing the SQL queries is done inline: special markers are inserted into your code to delimit sections that contain SQL code (as opposed to Ada code), and these are then preprocessed to generate actual code. This isn't the approach chosen in GNATColl: there are several drawbacks, in particular your code is no longer Ada and various tools will choke on it. The other usual approach is to write the queries as strings, which are passed, via a DBMS-specific API, to the DBMS server. This approach is very fragile: * The string might not contain **well-formed** SQL. This will unfortunately only be detected at run time when the DBMS complains. * This is not **type safe**. You might be comparing a text field with an integer, for instance. In some cases, the DBMS will accept that (sqlite for instance), but in some other cases it won't (PostgreSQL). The result might then either raise an error, or return an empty list. * There is a risk of **SQL injection**. Assuming the string is constructed dynamically (using Ada's `&` operator), it might be easy for a user to pass a string that breaks the query, and even destroys things in the database. * As discussed previously, the SQL code might not be **portable** across DBMS. For instance, creating an automatically increment integer primary key in a table is DBMS specific. * The string is fragile if the database **schema changes**. Finding whether a schema change impacts any of the queries requires looking at all the strings in your application. * **performance** might be an issue. Whenever you execute a query, the DBMS will analyze it, decide how to execute it (for instance, whether it should traverse all the rows of a table, or whether it can do a faster lookup), and then retrieve the results. The analysis pass is typically slow (relatively the overall execution time), and queries can in fact be **prepared** on the server: they are then analyzed only once, and it is possible to run them several times without paying the price of the analysis every time. Such a query can also be **parameterized**, in that some values can be deferred until the query is actually executed. All the above is made easy and portable in GNATColl, instead of requiring DBMS-specific techniques. * This might require **large amount of code** to setup the query, bind the parameters, execute it, and traverse the list of results. GNATColl attempts to solve all these issues. It also provides further performance improvements, for instance by keeping connections to the DBMS open and reusing them when possible. A paper was published at the Ada-Europe conference in 2008 which describes the various steps we went through in the design of this library. .. _Database_abstraction_layers: Database Abstraction Layers =========================== GNATColl organizes the API into several layers, each written on top of the previous one and providing more abstraction. All layers are compatible with each other and can be mixed inside a given application. * **low-level binding**. This API is DBMS-specific, and is basically a mapping of the C API provided by the DBMS vendors into Ada. If you are porting C code, or working with an existing application, as a way to start using GNATColl before moving to higher levels of abstraction. The code is found in :file:`gnatcoll-sql-sqlite-gnade.ads` and :file:`gnatcoll-sql-postgres-gnade.ads`. The *gnade* part in the file names indicate that this code was initially inspired by the **GNADE** library that used to be available on the internet. Part of the code might in fact come from that library. Using this API requires writing the SQL queries as strings, with all the disadvantages that were highlighted at the beginning of this chapter. * **GNATCOLL.SQL** and **GNATCOLL.SQL.Exec** The first of these packages makes it possible to write type-safe queries strongly linked to the database schema (thus with a guarantee that the query is up-to-date with regards to the schema). To accomplish this, it also relies on code that is generated automatically from a description of your database schema, using the tool `gnatcoll_db2ada`. To simplify memory management, the queries are automatically referenced counted and freed when they are no longer needed. The second of these packages provides communication with the DBMS. It provides a vendor-neutral API. You can send your queries either as strings, or preferably as written with `GNATCOLL.SQL`. It also provides a simple way to prepare parameterized statements on the server for maximum efficiency, as well as the reuse of existing DBMS connections. It provides a simple API to retrieve and manipulate the results from a query. * **GNATCOLL.SQL.ORM** and **GNATCOLL.SQL.Sessions** This is an Object-Relational Mapping (ORM). The first of these packages makes it possible to manipulate a database without writing SQL. Instead, you manipulate Ada objects (tagged types), whose primitive operations might transparently execute SQL queries. This API provides caching for maximum efficiency. It relies on code automatically generated by `gnatcoll_db2ada` from the schema of your database. The generated objects can then be extended in your own code if needed. The second package encapsulates DBMS connections into higher-level objects which provide their own caching and work best with the ORM objects. A session is automatically released to a pool when no longer needed and will be reused later on. The following sections will ignore the lower layer, and concentrate on the other layers. They share a number of types and, again, are fully compatible with each other. You could connect to the database, and then write some queries using **GNATCOLL.SQL** and some using **GNATCOLL.SQL.ORM**. .. _Database_example: Database example ================ This section describes an example that will be extended throughout this chapter. We will build an application that represents a library. Such a library contains various media (books and DVDs for instance), and customers. A customer can borrow multiple media at the same time, but a media is either at a customer's, or still in the library. The GNATColl distribution includes an example directory which contains all the code and data for this example. .. _Database_schema: Database schema =============== As was mentioned earlier (:ref:`Database_abstraction_layers`), GNATColl relies on automatic code generation to provide a type safe interface to your database. This code is generated by an external tool called `gnatcoll_db2ada` provided as an optional component. In some cases, this tool requires an installation of python (`www.python.org `_) on your machine, since part of the code is written in that language. This tool is able to output various kind of information, and is fully described in the corresponding component. However, the input is always the same: this is the schema of your database, that is the list of tables and fields that make up your database. There exist two ways to provide that information: * From a running database If you pass the DBMS vendor (postgresql, sqlite,...) and the connection parameters to `gnatcoll_db2ada`, it is able to query the schema on its own. However, this should not be the preferred method: this is similar to reverse engineering assembly code into the original high-level code, and some semantic information will be missing. For instance, in SQL we have to create tables just to represent the many-to-many relationships. These extra tables are part of the implementation of the schema, but are just noise when it comes to the semantics of the schema. For this reason, it is better to use the second solution below: * From a textual description Using the `-dbmodel` switch to `gnatcoll_db2ada`, you can pass a file that describes the schema. We do not use SQL as the syntax in this, because as explained above this is too low-level. This text file also provides additional capabilities that do not exist when reverse-engineering an existing database, for instance the ability to use name to represent reverse relationships for foreign keys (see below and the ORM). The most convenient editor for this file is Emacs, using the `org-mode` which provides convenient key shortcuts for editing the contents of ASCII tables. But any text editor will do, and you do not need to align the columns in this file. All lines starting with a hash sign ('#') will be ignored. This file is a collection of ASCII tables, each of which relates to one table or one SQL view in your database. The paragraphs start with a line containing:: table ::= '|' ('ABSTRACT')? ('TABLE'|'VIEW') ['(' supertable ')'] '|' '|' "name" is the name of the table. The third pipe and third column are optional, and should be used to specify the name for the element represented by a single row. For instance, if the table is called "books", the third column could contain "book". This is used when generating objects for use with `GNATCOLL.SQL.ORM`. If the first line starts with the keyword `ABSTRACT`, then no instance of that table actually exists in the database. This is used in the context of table inheritance, so define shared fields only once among multiple tables. The keyword `TABLE` can be followed by the name of a table from which it inherits the fields. Currently, that supertable must be abstract, and the fields declared in that table are simply duplicated in the new table. Following the declaration of the table, the file then describe their fields, each on a separate line. Each of these lines must start with a pipe character ("|"), and contain a number of pipe-separated fields. The order of the fields is always given by the following grammar:: fields ::= '|' '|' '|' ('PK'|''|'NULL'|'NOT NULL'|'INDEX'|'UNIQUE'|'NOCASE') '|' [default] '|' [doc] '|' The type of the field is the SQL type ("INTEGER", "TEXT", "TIMESTAMP", "DATE", "DOUBLE PRECISION", "MONEY", "BOOLEAN", "TIME", "CHARACTER(1)"). Any maximal length can be specified for strings, not just 1 as in this example. The tool will automatically convert these to Ada when generating Ada code. A special type ("AUTOINCREMENT") is an integer that is automatically incremented according to available ids in the table. The exact type used will depend on the specific DBMS. The property 'NOCASE' indicates that comparison should be case insensitive for this field. If the field is a foreign key (that is a value that must correspond to a row in another table), you can use the special syntax for its type:: fk_type ::= 'FK' [ '(' ')' ] As you can see, the type of the field is not specified explicitly, but will always be that of the foreign table's primary key. With this syntax, the foreign table must have a single field for its primary key. GNATColl does not force a specific order for the declaration of tables: if is valid to have a foreign key to a table that hasn't been declared yet. There is however a restriction if you use the model to create a sqlite database (through the `-createdb` switch of `gnatcoll_db2ada`): in this case, a reference to a table that hasn't been defined yet may not be not through a field marked as NOT NULL. This is a limitation of the sqlite backend itself. The solution in this case is to reorder the declaration of tables, or drop the NOT NULL constraint. Another restriction is that a foreign key that is also a primary key must reference a table that has already been defined. You need to reorder the declaration of your tables to ensure this is the case. "reverse_name" is the optional name that will be generated in the Ada code for the reverse relationship, in the context of `GNATCOLL.SQL.ORM`. If the "reverse_name" is empty (the parenthesis are shown), no reverse relationship is generated. If the parenthesis and the reverse_name are both omitted, a default name is generated based on the name of the field. The third column in the fields definition indicates the constraints of the type. Multiple keywords can be used if they are separated by commas. Thus, "NOT NULL, INDEX" indicates a column that must be set by the user, and for which an index is created to speed up look ups. * A primary key ("PK") * The value must be defined ("NOT NULL") * The value can be left undefined ("NULL") * A unique constraint and index ("UNIQUE") * An index should be created for that column ("INDEX") to speed up the lookups. * The automatic index created for a Foreign Key should not be created ("NOINDEX"). Every time a field references another table, GNATColl will by default create an index for it, so that the ORM can more efficiently do a reverse query (from the target table's row find all the rows in the current table that reference that target row). This will in general provide more efficiency, but in some cases you never intend to do the reverse query and thus can spare the extra index. The fourth column gives the default value for the field, and is given in SQL syntax. Strings must be quoted with single quotes. The fifth column contains documentation for the field (if any). This documentation will be included in the generated code, so that IDEs can provide useful tooltips when navigating your application's code. After all the fields have been defined, you can specify extract constraints on the table. In particular, if you have a foreign key to a table that uses a tuple as its primary key, you can define that foreign key on a new line, as:: FK ::= '|' "FK:" '|' '|' * '|' * '|' For instance:: | TABLE | tableA | | FK: | tableB | fieldA1, fieldA2 | fieldB1, fieldB2 | It is also possible to create multi-column indexes, as in the following example. In this case, the third column contains the name of the index to create. If left blank, a default name will be computed by GNATColl:: | TABLE | tableA | | INDEX: | field1,field2,field3 | name | The same way the unique multi-column constraint and index can be created. The name is optional. | TABLE | tableA | | UNIQUE: | field1,field2,field3 | name | Going back to the example we described earlier (:ref:`Database_example`), let's describe the tables that are involved. The first table contains the customers. Here is its definition:: | TABLE | customers | customer || The customer for the library | | id | AUTOINCREMENT | PK || Auto-generated id | | first | TEXT | NOT NULL || Customers' first name | | last | TEXT | NOT NULL, INDEX || Customers' last name | We highly recommend to set a primary key on all tables. This is a field whose value is unique in the table, and thus that can act as an identifier for a specific row in the table (in this case for a specific customer). We recommand using integers for these ids for efficiency reasons. It is possible that the primary key will be made of several fields, in which case they should all have the "PK" constraint in the third column. A table with no primary key is still usable. The difference is in the code generated for the ORM (:ref:`The_Object_Relational_Mapping_layer`), since the `Delete` operation for this table will raise a `Program_Error` instead of doing the actual deletion (that's because there is no guaranteed unique identifier for the element, so the ORM does not know which one to delete -- we do not depend on having unique internal ids on the table, like some DBMS have). Likewise, the elements extracted from such a primary key-less table will not be cached locally in the session, and cannot be updated (only new elements can be created in the table). As we mentioned, the library contains two types of media, books and DVDs. Each of those has a title, an author. However, a book also has a number of pages and a DVD has a region where it can be viewed. There are various ways to represent this in a database. For illustration purposes, we will use table inheritance here: we will declare one abstract table (media) which contains the common fields, and two tables to represent the types of media. As we mentioned, a media can be borrowed by at most one customer, but a customer can have multiple media at any point in time. This is called a **one-to-many** relationship. In SQL, this is in general described through the use of a foreign key that goes from the table on the "many" side. In this example, we therefore have a foreign key from media to customers. We also provide a name for the reverse relationship, which will become clearer when we describe the ORM interface. Here are the declarations:: | ABSTRACT TABLE | media | media || The contents of the library | | id | AUTOINCREMENT | PK || Auto-generated id | | title | TEXT | || The title of the media | | author | TEXT | || The author | | published | DATE | || Publication date | | borrowed_by | FK customers(items) | NULL || Who borrowed the media | | TABLE (media) | books | book | | The books in the library | | pages | INTEGER | | 100 | | | TABLE (media) | dvds | dvd | | The dvds in the library | | region | INTEGER | | 1 | | For this example, all this description is put in a file called :file:`dbschema.txt`. .. _Connecting_to_the_database: Connecting to the database ========================== This library abstracts the specifics of the various database engines it supports. Ideally, code written for one database could be ported almost transparently to another engine. This is not completely doable in practice, since each system has its own SQL specifics, and unless you are writing things very carefully, the interpretation of your queries might be different from one system to the next. However, the Ada code should remain untouched if you change the engine. Various engines are supported out of the box (PostgreSQL and Sqlite), although new ones can be added by overriding the appropriate SQL type (`Database_Connection`). When you compile GNATColl, the build scripts will try and detect what systems are installed on your machine, and only build support for those. It is possible, if no database was installed on your machine at that time, that the database interface API is available (and your application compiles), but no connection can be done to database at run time. To connect to a DBMS, you need to specify the various connection parameters. This is done via a `GNATCOLL.SQL.Exec.Database_Description` object. The creation of this object depends on the specific DBMS you are connecting to (and this is the only part of your code that needs to know about the specific system). The packages `GNATCOLL.SQL.Postgres` and `GNATCOLL.SQL.Sqlite` contain a `Setup` function, whose parameters depend on the DBMS. They provide full documentation for their parameters. Let's take a simple example from sqlite:: with GNATCOLL.SQL.Sqlite; -- or Postgres declare DB_Descr : GNATCOLL.SQL.Exec.Database_Description; begin DB_Descr := GNATCOLL.SQL.Sqlite.Setup ("dbname.db"); end At this point, no connection to the DBMS has been done, and no information was exchanged. To communicate with the database, however, we need to create another object, a **GNATCOLL.SQL.Exec.Database_Connection**. Your application can create any number of these. Typically, one would create one such connection per task in the application, although other strategies are possible (like a pool of reusable connections, where a task might be using two connections and another task none at any point in time). If you do not plan on using the ORM interface from **GNATCOLL.SQL.ORM**, GNATColl provides a simple way to create a task-specific connection. While in this task, the same connection will always be returned (thus you do not have to pass it around in parameter, although the latter might be more efficient):: declare DB : GNATCOLL.SQL.Exec.Database_Connection; begin DB := GNATCOLL.SQL.Exec.Get_Task_Connection (Description => DB_Descr); end; If your application is not multi-tasking, or you wish to implement your own strategy for a connection pool, you can also use the following code (using Ada 2005 dotted notation when calling the primitive operation). This code will always create a new connection, not reuse an existing one, as opposed to the code above:: declare DB : GNATCOLL.SQL.Exec.Database_Connection; begin DB := DB_Descr.Build_Connection; end; A note on concurrency: if you implement your own pool, you might sometimes end up with dead locks when using sqlite. If a task uses two or more connections to sqlite, and you setup GNATCOLL to create SQL transactions even for `SELECT` statements (see `GNATCOLL.SQL.Sqlite.Always_Use_Transactions`), the following scenario will result in a deadlock:: DB1 := ... new connection to sqlite ... execute a SELECT through DB1. The latter then holds a shared ... lock, preventing other connections from writing (but not from ... reading). DB2 := ... another connection in the same thread ... execute an INSERT through DB2. This tries to get a lock, which ... will fail while DB1 holds the shared lock. Since these are in ... the same thread, this will deadlock. By default, GNATCOLL will not create SQL transactions for select statements to avoid this case, which occurs frequently in code. If you wish to reuse an existing connection later on, you must reset it. This terminates any on-going SQL transaction, and resets various internal fields that describe the state of the connection:: Reset_Connection (DB); In all three cases, the resulting database connection needs to be freed when you no longer needed (which might be when your program terminates if you are using pools) to avoid memory leaks. Nothing critical will appear if you do not close, though, because the transactions to the DBMS server are saved every time you call `Commit` in any case. So the code would end with:: Free (DB); -- for all connections you have opened Free (DB_Descr); At this point, there still hasn't been any connection to the DBMS. This will be done the first time a query is executed. If for some reason the connection to the DBMS server is lost, GNATColl will automatically attempt to reconnect a number of times before it gives up. This might break if there was an ongoing SQL transaction, but simplifies your code since you do not have to handle reconnection when there was a network failure, for instance. As we saw before, the database interface can be used in multi-tasking applications. In such a case, it is recommended that each thread has its own connection to the database, since that is more efficient and you do not have to handle locking. However, this assumes that the database server itself is thread safe, which most often is the case, but not for `sqlite` for instance. In such a case, you can only connect one per application to the database, and you will have to manage a queue of queries somehow. If you want to use **GNATCOLL.SQL.Sessions** along with the Object-Relational Mapping API, you will need to initialize the connection pool with the **Database_Description**, but the session will then take care automatically of creating the **Database_Connection**. See later sections for more details. Loading initial data in the database ==================================== We have now created an empty database. To make the queries we will write later more interesting, we are going to load initial data. There are various ways to do it: * Manually or with an external tool One can connect to the database with an external tool (a web interface when the DBMS provides one for instance), or via a command line tool (`psql` for PostgreSQL or `sqlite3` for Sqlite), and start inserting data manually. This shows one of the nice aspects of using a standard DBMS for your application: you can alter the database (for instance to do minor fixes in the data) with a lot of external tools that were developed specifically for that purpose and that provide a nice interface. However, this is also tedious and error prone, and can't be repeat easily every time we recreate the database (for instance before running automatic tests). * Using `GNATCOLL.SQL.EXEC` As we will describe later, GNATColl contains all the required machinery for altering the contents of the database and creating new objects. Using `GNATCOLL.SQL.ORM` this can also be done at a high-level and completely hide SQL. * Loading a data file A lot of frameworks call such a file that contains initial data a "fixture". We will use this techniques as an example. At the Ada level, this is a simple call to `GNATCOLL.SQL.Inspect.Load_Data`. The package contains a lot more than just this subprogram (:ref:`The_gnatcoll_db2ada_tool`):: declare File : GNATCOLL.VFS.Virtual_File := Create ("fixture.txt"); DB : Database_Connection; -- created earlier begin GNATCOLL.SQL.Inspect.Load_Data (DB, File); DB.Commit; end; The format of this file is described just below. As we mentioned, GNATColl can load data from a file. The format of this file is similar to the one that describes the database schema. It is a set of ASCII tables, each of which describes the data that should go in a table (it is valid to duplicate tables). Each block starts with two lines: The first one has two mandatory columns, the first of which contains the text "TABLE", and the second contains the name of the table you want to fill. The second line should contain as many columns as there are fields you want to set. Not all the fields of the table need to have a corresponding column if you want to set their contents to NULL (provided, of course, that your schema allows it). For instance, we could add data for our library example as such:: | TABLE | customers | | | id | first | last | |-------+-----------+--------| | 1 | John | Smith | | 2 | Alain | Dupont | | TABLE | books | | | | | title | author | pages | published | borrowed_by | |------------+---------+-------+------------+-------------| | Art of War | Sun Tzu | 90 | 01-01-2000 | 1 | | Ada RM | WRG | 250 | 01-07-2005 | | A few comments on the above: the `id` for `books` is not specified, although the column is the primary key and therefore cannot be NULL. In fact, since the type of the `id` was set to AUTOINCREMENT, GNATColl will automatically assign valid values. We did not use this approach for the id of `customers`, because we need to know this id to set the `borrowed_by` field in the `books` table. There is another approach to setting the `borrowed_by` field, which is to give the value of another field of the `customers` table. This of course only work if you know this value is unique, but that will often be the case in your initial fixtures. Here is an example:: | TABLE | dvds | | | | title | author | region | borrowed_by(&last) | |--------------+-----------+--------+--------------------| | The Birds | Hitchcock | 1 | &Smith | | The Dictator | Chaplin | 3 | &Dupont | Here, the title of the column indicates that any value in this column might be a reference to the `customers.last` value. Values which start with an ampersand ("&") will therefore be looked up in `customers.last`, and the `id` of the corresponding customer will be inserted in the `dvds` table. It would still be valid to use directly customer ids instead of references, this is just an extra flexibility that the references give you to make your fixtures more readable. However, if we are using such references we need to provide the database schema to `Load_Data` so that it can write the proper queries. This is done by using other services of the `GNATCOLL.SQL.Inspect` package. The code for our example would be:: Load_Data (DB, Create ("fixture.txt"), New_Schema_IO (Create ("dbschema.txt")).Read_Schema); .. _Writing_queries: Writing queries =============== The second part of the database support in GNATColl is a set of Ada subprograms which help write SQL queries. Traditional ways to write such queries have been through embedded SQL (which requires a preprocessing phase and complicates the editing of source files in Ada-aware editors), or through simple strings that are passed as is to the server. In the latter case, the compiler can not do any verification on the string, and errors such a missing parenthesis or misspelled table or field names will not be detected until the code executes the query. GNATColl tries to make sure that code that compiles contains syntactically correct SQL queries and only reference existing tables and fields. This of course does not ensure that the query is semantically correct, but helps detect trivial errors as early as possible. Such queries are thus written via calls to Ada subprograms, as in the following example:: with GNATCOLL.SQL; use GNATCOLL.SQL; with Database; use Database; declare Q : SQL_Query; begin Q := SQL_Select (Fields => Max (Ticket_Priorities.Priority) & Ticket_Priorities.Category, From => Ticket_Priorities, Where => Ticket_Priorities.Name /= "low", Group_By => Ticket_Priorities.Category); end; The above example will return, for each type of priority (internal or customer) the highest possible value. The interest of this query is left to the user... This is very similar to an actual SQL query. Field and table names come from the package that was automatically generated by the `gnatcoll_db2ada` tool, and therefore we know that our query is only referencing existing fields. The syntactic correctness is ensured by standard Ada rules. The `SQL_Select` accepts several parameters corresponding to the usual SQL attributes like `GROUP BY`, `HAVING`, `ORDER BY` and `LIMIT`. The `From` parameter could be a list of tables if we need to join them in some ways. Such a list is created with the overridden `"&"` operator, just as for fields which you can see in the above example. GNATColl also provides a `Left_Join` function to join two tables when the second might have no matching field (see the SQL documentation). Similar functions exist for `SQL_Insert`, `SQL_Update` and `SQL_Delete`. Each of those is extensively documented in the :file:`gnatcoll-sql.ads` file. It is worth noting that we do not have to write the query all at once. In fact, we could build it depending on some other criteria. For instance, imagine we have a procedure that does the query above, and omits the priority specified as a parameter, or shows all priorities if the empty string is passed. Such a procedure could be written as:: procedure List_Priorities (Omit : String := "") is Q : SQL_Query; C : SQL_Criteria := No_Criteria; begin if Omit /= "" then C := Ticket_Priorities.Name /= Omit; end if; Q := SQL_Select (Fields => ..., -- as before Where => C); end; With such a code, it becomes easier to create queries on the fly than it would be with directly writing strings. The above call has not sent anything to the database yet, only created a data structure in memory (more precisely a tree). In fact, we could be somewhat lazy when writing the query and rely on auto-completion, as in the following example:: Q := SQL_Select (Fields => Max (Ticket_Priorities.Priority) & Ticket_Priorities.Category, Where => Ticket_Priorities.Name /= "low"); Auto_Complete (Q); This query is exactly the same as before. However, we did not have to specify the list of tables (which GNATColl can compute on its own by looking at all the fields referenced in the query), nor the list of fields in the `GROUP BY` clause, which once again can be computed automatically by looking at those fields that are not used in a SQL aggregate function. This auto-completion helps the maintenance of those queries. There is another case where GNATColl makes it somewhat easier to write the queries, and that is to handle joins between tables. If your schema was build with foreign keys, GNATColl can take advantage of those. Going back to our library example, let's assume we want to find out all the books that were borrowed by the user "Smith". We need to involve two tables (`Books` and `Customers`), and provide a join between them so that the DBMS knows how to associate the rows from one with the rows from the other. Here is a first example for such a query:: Q := SQL_Select (Fields => Books.Title & Books.Pages, From => Books & Customers, Where => Books.Borrowed_By = Customers.Id and Customers.Last = "Smith"); In fact, we could also use auto-completion, and let GNATColl find out the involved tables on its own. We thus write the simpler:: Q := SQL_Select (Fields => Books.Title & Books.Pages, Where => Books.Borrowed_By = Customers.Id and Customers.Last = "Smith"); There is one more things we can do to simplify the query and make it more solid if the schema of the database changes. For instance, when a table has a primary key made up of several fields, we need to make sure we always have an "=" statement in the WHERE clause for all these fields between the two tables. In our example above, we could at some point modify the schema so that the primary key for `customers` is multiple (this is unlikely in this example of course). To avoid this potential problems and make the query somewhat easier to read, we can take advantage of the `FK` subprograms generated by `gnatcoll_db2ada`. Using the Ada05 dotted notation for the call, we can thus write:: Q := SQL_Select (Fields => Books.Title & Books.Pages, Where => Books.FK (Customers) and Customers.Last = "Smith"); Regarding memory management, there is no need for explicitly freeing memory in the above code. GNATColl will automatically do this when the query is no longer needed. Executing queries ================= Once we have our query in memory, we need to pass it on to the database server itself, and retrieve the results. Executing is done through the `GNATCOLL.SQL.Exec` package, as in the following example:: declare R : Forward_Cursor; begin R.Fetch (Connection => DB, Query => Q); end; This reuses the connection we have established previously (`DB`) (although now we are indeed connecting to the DBMS for the first time) and sends it the query. The result of that query is then stored in `R`, to be used later. Some SQL commands execute code on the DBMS, but do not return a result. In this case, you can use `Execute` instead of `Fetch`. This is the case when you execute an `INSERT` or `UPDATE` statement for instance. Using `Execute` avoids the need to declare the local variable `R`. If for some reason the connection to the database is no longer valid (a transient network problem for instance), GNATColl will attempt to reconnect and re-execute your query transparently, so that your application does not need to handle this case. We'll describe later (:ref:`Getting_results`) how to analyze the result of the query. Some versions of `Fetch` have an extra parameter `Use_Cache`, set to `False` by default. If this parameter is true, and the exact same query has already been executed before, its result will be reused without even contacting the database server. The cache is automatically invalidated every hour in any case. This cache is mostly useful for tables that act like enumeration types. In this case, the contents of the table changes very rarely, and the cache can provide important speedups, whether the server is local or distant. However, we recommend that you do actual measurements to know whether this is indeed beneficial for you. You can always invalidate the current cache with a call to `Invalidate_Cache` to force the query to be done on the database server. If your query produces an error (whether it is invalid, or any other reason), a flag is toggled in the `Connection` parameter, which you can query through the `Success` subprogram. As a result, a possible continuation of the above code is:: if Success (DB) then ... else ... -- an error occurred end if GNATColl also tries to be helpful in the way it handles SQL transactions. Such transactions are a way to execute your query in a sandbox, i.e. without affecting the database itself until you decide to `COMMIT` the query. Should you decide to abort it (or `ROLLBACK` as they say for SQL), then it is just as if nothing happened. As a result, it is in general recommended to do all your changes to the database from within a transaction. If one of the queries fail because of invalid parameters, you just rollback and report the error to the user. The database is still left in a consistent state. As an additional benefit, executing within a transaction is sometimes faster, as is the case for PostgreSQL for instance. To help with this, GNATColl will automatically start a transaction the first time you edit the database. It is then your responsibility to either commit or rollback the transaction when you are done modifying. A lot of database engines (among which PostgreSQL) will not accept any further change to the database if one command in the transaction has failed. To take advantage of this, GNATColl will therefore not even send the command to the server if it is in a failure state. Here is code sample that modifies the database:: Execute (DB, SQL_Insert (...)); -- Executed in the same transaction Commit_Or_Rollback (DB); -- Commit if both insertion succeeded, rollback otherwise -- You can still check Success(DB) afterward if needed .. _Prepared_queries: Prepared queries ================ The previous section showed how to execute queries and statements. But these were in fact relatively inefficient. With most DBMS servers, it is possible to compile the query once on the server, and then reuse that prepared query to significantly speed up later searches when you reuse that prepared statement. .. highlight:: sql It is of course pretty rare to run exactly the same query or statement multiple times with the same values. For instance, the following query would not give much benefit if it was prepared, since you are unlikely to reuse it exactly as is later on:: SELECT * FROM data WHERE id=1 SQL (and GNATColl) provide a way to parameterize queries. Instead of hard-coding the value `1` in the example above, you would in fact use a special character (unfortunately specific to the DBMS you are interfacing to) to indicate that the value will be provided when the query is actually executed. For instance, `sqlite` would use:: SELECT * FROM data WHERE id=? .. highlight:: ada You can write such a query in a DBMS-agnostic way by using GNATColl. Assuming you have automatically generated :file:`database.ads` by using `gnatcoll_db2ada`, here is the corresponding Ada code:: with Database; use Database; Q : constant SQL_Query := SQL_Select (Fields => Data.Id & Data.Name From => Data, Where => Data.Id = Integer_Param (1)); GNATColl provides a number of functions (one per type of field) to indicate that the value is currently unbound. `Integer_Param`, `Text_Param`, `Boolean_Param`,... All take a single argument, which is the index of the corresponding parameter. A query might need several parameters, and each should have a different index. On the other hand, the same parameter could be used in several places in the query. Although the query above could be executed as is by providing the values for the parameters, it is more efficient, as we mentioned at the beginning, to compile it on the server. In theory, this preparation is done within the context of a database connection (thus cannot be done for a global variable, where we do not have connections yet, and where the query might be executed by any connection later on). GNATColl will let you indicate that the query should be prepared. This basically sets up some internal data, but does not immediately compile it on the server. The first time the query is executed in a given connection, though, it will first be compiled. The result of this compilation will be reused for that connection from then on. If you are using a second connection, it will do its own compilation of the query. So in our example we would add the following global variable:: P : constant Prepared_Statement := Prepare (Q, On_Server => True); Two comments about this code: * You do not have to use global variables. You can prepare the statement locally in a subprogram. A `Prepared_Statement` is a reference counted type, that will automatically free the memory on the server when it goes out of scope. * Here, we prepared the statement on the server. If we had specified `On_Server => False`, we would still have sped things up, since Q would be converted to a string that can be sent to the DBMS, and from then on reused that string (note that this conversion is specific to each DBMS, since they don't always represent things the same way, in particular parameters, as we have seen above). Thus every time you use P you save the time of converting from the GNATColl tree representation of the query to a string for the DBMS. Now that we have a prepared statement, we can simply execute it. If the statement does not require parameters, the usual `Fetch` and `Execute` subprograms have versions that work exactly the same with prepared statements. They also accept a `Params` parameter that contains the parameter to pass to the server. A number of `"+"` operators are provided to create those parameters:: declare F : Forward_Cursor; begin F.Fetch (DB, P, Params => (1 => +2)); F.Fetch (DB, P, Params => (1 => +3)); end; Note that for string parameters, the `"+"` operator takes an access to a string. This is for efficiency, to avoid allocating memory and copying the string, and is safe because the parameters are only needed while `Fetch` executes (even for a `Forward_Cursor`. Back to our library example. We showed earlier how to write a query that retrieves the books borrowed by customer "Smith". We will now make this query more general: given a customer name, return all the books he has borrowed. Since we expect to use this often, we will prepare it on the server (in real life, this query is of little interest since the customer name is not unique, we would instead use a query that takes the id of the customer). In general we would create a global variable with:: Borrowed : constant Prepared_Statement := Prepare (SQL_Select (Fields => Books.Title & Books.Pages, Where => Books.FK (Customers) and Customers.Last = Text_Param (1)); Auto_Complete => True, On_Server => True); Then when we need to execute this query, we would do:: declare Name : aliased String := "Smith"; begin R.Fetch (DB, Borrowed, Params => (1 => +Smith'Access)); end; There is one last property on `Prepared_Statement`s: when you prepare them, you can pass a `Use_Cache => True` parameter. When this is used, the result of the query will be cached by GNATColl, and reuse when the query is executed again later. This is the fastest way to get the query, but should be used with care, since it will not detect changes in the database. The local cache is automatically invalidated every hour, so the query will be performed again at most one hour later. Local caching is disabled when you execute a query with parameters. In this case, prepare the query on the server which will still be reasonably fast. Finally, here are some examples of timings. The exact timing are irrelevant, but it is interesting to look at the different between the various scenarios. Each of them performs 100_000 simple queries similar to the one used in this section:: Not preparing the query, using `Direct_Cursor`: 4.05s Not preparing the query, using `Forward_Cursor`, and only retrieving the first row: 3.69s Preparing the query on the client (`On_Server => False`), with a `Direct_Cursor`. This saves the whole `GNATCOLL.SQL` manipulations and allocations: 2.50s Preparing the query on the server, using `Direct_Cursor`: 0.55s Caching the query locally (`Use_Cache => True`): 0.13s .. _Getting_results: Getting results =============== Once you have executed a `SELECT` query, you generally need to examine the rows that were returned by the database server. This is done in a loop, as in:: while Has_Row (R) loop Put_Line ("Max priority=" & Integer_Value (R, 0)'Img & " for category=" & Value (R, 1)); Next (R); end loop; You can only read one row at a time, and as soon as you have moved to the next row, there is no way to access a previously fetched row. This is the greatest common denominator between the various database systems. In particular, it proves efficient, since only one row needs to be kept in memory at any point in time. For each row, we then call one of the `Value` or `*Value` functions which return the value in a specific row and a specific column. We mentioned earlier there was no way to go back to a row you fetched previously except by executing the query again. This is in fact only true if you use a `Forward_Cursor` to fetch the results. But GNATColl provides another notion, a `Direct_Cursor`. In this case, it fetches all the rows in memory when the query executes (thus it needs to allocate more memory to save every thing, which can be costly if the query is big). This behavior is supported natively by `PostgreSQL`, but doesn't exist with `sqlite`, so GNATColl will simulate it as efficiently as possible. But it will almost always be faster to use a `Forward_Cursor`. In exchange for this extra memory overhead, you can now traverse the list of results in both directions, as well as access a specific row directly. It is also possible to know the number of rows that matched (something hard to do with a `Forward_Cursor` since you would need to traverse the list once to count, and then execute the query again if you need the rows themselves). Direct_Cursor, produced from prepeared statements, could be indexed by the specified field value and routine Find could set the cursor position to the row with specified field value.:: -- Prepared statement should be declared on package level. Stmt : Prepared_Statement := Prepare ("select Id, Name, Address from Contact order by Name" Use_Cache => True, Index_By => Field_Index'First); procedure Show_Contact (Id : Integer) is CI : Direct_Cursor; begin CI.Fetch (DB, Stmt); CI.Find (Id); -- Find record by Id if CI.Has_Row then Put_Line ("Name " & CI.Value (1) & " Address " & CI.Value (2)); else Put_Line ("Contact id not found."); end if; end Show_Contact; In general, the low-level DBMS C API use totally different approaches for the two types of cursors (when they even provide them). By contrast, GNATColl makes it very easy to change from one to the other just by changing the type of a the result variable. So you would in general start with a `Forward_Cursor`, and if you discover you in fact need more advanced behavior you can pay the extra memory cost and use a `Direct_Cursor`. For both types of cursors, GNATColl automatically manages memory (both on the client and on the DBMS), thus providing major simplification of the code compared to using the low-level APIs. Creating your own SQL types =========================== GNATColl comes with a number of predefined types that you can use in your queries. :file:`gnatcoll_db2ada` will generate a file using any of these predefined types, based on what is defined in your actual database. But sometimes, it is convenient to define your own SQL types to better represent the logic of your application. For instance, you might want to define a type that would be for a `Character` field, rather than use the general `SQL_Field_Text`, just so that you can write statements like:: declare C : Character := 'A'; Q : SQL_Query; begin Q := SQL_Select (.., Where => Table.Field = C); end This is fortunately easily achieved by instantiating one generic package, as such:: with GNATCOLL.SQL_Impl; use GNATCOLL.SQL_Impl; function To_SQL (C : Character) return String is begin return "'" & C & "'"; end To_SQL; package Character_Fields is new Field_Types (Character, To_SQL); type SQL_Field_Character is new Character_Fields.Field with null record; This automatically makes available both the field type (which you can use in your database description, as :file:`gnatcoll_db2ada` would do, but also all comparison operators like `<`, `>`, `=`, and so on, both to compare with another character field, or with `Character` Ada variable. Likewise, this makes available the assignment operator `=` so that you can create `INSERT` statements in the database. Finally, the package `Character_Fields` contain other generic packages which you can instantiate to bind SQL operators and functions that are either predefined in SQL and have no equivalent in GNATColl yet, or that are functions that you have created yourself on your DBMS server. See the specs of `GNATCOLL.SQL_Impl` for more details. This package is only really useful when writing your own types, since otherwise you just have to use `GNATCOLL.SQL` to write the actual queries. See also `GNATCOLL.SQL_Fields` for an example on how to have a full integration with other parts of `GNATCOLL.SQL`. Query logs ========== In :ref:`Logging_information` we discovered the logging module of GNATColl. The database interface uses this module to log the queries that are sent to the server. If you activate traces in your application, the user can then activate one of the following trace handles to get more information on the exchange that exists between the database and the application. As we saw before, the output of these traces can be sent to the standard output, a file, the system logs,... The following handles are provided: * SQL.ERROR This stream is activated by default. Any error returned by the database (connection issues, failed transactions,...) will be logged on this stream * SQL This stream logs all queries that are not SELECT queries, ie mostly all queries that actually modify the database * SQL.SELECT This stream logs all select queries. It is separated from SQL because very often you will be mostly interested in the queries that impact the database, and logging all selects can generate a lot of output. In our library example, we would add the following code to see all SQL statements executed on the server:: with GNATCOLL.Traces; use GNATCOLL.Traces; procedure Main is begin GNATCOLL.Traces.Parse_Config_File (".gnatdebug"); ... -- code as before GNATCOLL.Traces.Finalize; -- reclaim memory and then create a .gnatdebug in the directory from which we launch our executable. This file would contain a single line containing "+" to activate all log streams, or the following to activate only the subset of fields related to SQL:: SQL=yes SQL.SELECT=yes SQL.LITE=yes .. _Writing_your_own_cursors: Writing your own cursors ======================== The cursor interface we just saw is low-level, in that you get access to each of the fields one by one. Often, when you design your own application, it is better to abstract the database interface layer as much as possible. As a result, it is often better to create record or other Ada types to represent the contents of a row. Fortunately, this can be done very easily based on the API provided by `GNATCOLL.SQL`. Note that `GNATCOLL.SQL.ORM` provides a similar approach based on automatically generated code, so might be even better. But it is still useful to understand the basics of providing your own objects. Here is a code example that shows how this can be done:: type Customer is record Id : Integer; First, Last : Unbounded_String; end record; type My_Cursor is new Forward_Cursor with null record; function Element (Self : My_Cursor) return My_Row; function Do_Query (DB, ...) return My_Cursor; The idea is that you create a function that does the query for you (based on some parameters that are not shown here), and then returns a cursor over the resulting set of rows. For each row, you can use the `Element` function to get an Ada record for easier manipulation. Let's first see how these types would be used in practice:: declare C : My_Cursor := Do_Query (DB, ...); begin while Has_Row (C) loop Put_Line ("Id = " & Element (C).Id); Next (C); end loop; end; So the loop itself is the same as before, except we no longer access each of the individual fields directly. This means that if the query changes to return more fields (or the same fields in a different order for instance), the code in your application does not need to change. The specific implementation of the subprograms could be similar to the following subprograms (we do not detail the writing of the SQL query itself, which of course is specific to your application):: function Do_Query return My_Cursor is Q : constant SQL_Query := ....; R : My_Cursor; begin R.Fetch (DB, Q); return R; end Do_Query; function Element (Self : My_Cursor) return My_Row is begin return Customer' (Id => Integer_Value (Self, 0), First => To_Unbounded_String (Value (Self, 1)), Last => To_Unbounded_String (Value (Self, 2))); end Element; There is one more complex case though. It might happen that an element needs access to several rows to fill the Ada record. For instance, if we are writing a CRM application and query the contacts and the companies they work for, it is possible that a contact works for several companies. The result of the SQL query would then look like this:: contact_id | company_id 1 | 100 1 | 101 2 | 100 The sample code shown above will not work in this case, since Element is not allowed to modify the cursor. In such a case, we need to take a slightly different approach:: type My_Cursor is new Forward_Cursor with null record; function Do_Query return My_Cursor; -- as before procedure Element_And_Next (Self : in out My_Cursor; Value : out My_Row); where `Element_And_Next` will fill Value and call Next as many times as needed. On exit, the cursor is left on the next row to be processed. The usage then becomes:: while Has_Row (R) loop Element_And_Next (R, Value); end loop; To prevent the user from using Next incorrectly, you should probably override `Next` with a procedure that does nothing (or raises a Program_Error maybe). Make sure that in `Element_And_Next` you are calling the inherited function, not the one you have overridden, though. There is still one more catch. The user might depend on the two subprograms `Rows_Count` and `Processed_Rows` to find out how many rows there were in the query. In practice, he will likely be interested in the number of distinct contacts in the tables (2 in our example) rather than the number of rows in the result (3 in the example). You thus need to also override those two subprograms to return correct values. .. _The_object_relational_mapping_layer: The Object-Relational Mapping layer (ORM) ========================================= GNATColl provides a high-level interface to manipulate persistent objects stored in a database, using a common paradigm called an object-relational mapping. Such mappings exist for most programming languages. In the design of GNATColl, we were especially inspired by the python interface in `django` and `sqlalchemy`, although the last two rely on dynamic run time introspection and GNATColl relies on code generation instead. This API is still compatible with `GNATCOLL.SQL`. In fact, we'll show below cases where the two are mixed. It can also be mixed with `GNATCOLL.SQL.Exec`, although this might be more risky. Communication with the DBMS is mostly transparent in the ORM, and it uses various caches to optimize things and make sure that if you modify an element the next querie(s) will also return it. If you use `GNATCOLL.SQL.Exec` directly you are bypassing this cache so you risk getting inconsistent results in some cases. In ORM, a table is not manipulated directly. Instead, you manipulate objects that are read or written to a table. When we defined our database schema (:ref:`Database_schema`), we gave two names on the first line of a table definition. There was the name of the table in the database, and the name of the object that each row represent. So for our library example we have defined `Customer`, `Book` and `Dvd` objects. These objects are declared in a package generated automatically by `gnatcoll_db2ada`. There is first one minor change we need to do to our library example. The ORM currently does not handle properly cases where an abstract class has foreign keys to other tables. So we remove the `borrowed_by` field from the `Media` table, and change the `books` table to be:: | TABLE (media) | books | book | | The books in the library | | pages | INTEGER | | 100 | | | borrowed_by | FK customers(borrowed_books) | NULL | | Who borrowed the media | Let's thus start by generating this code. We can replace the command we ran earlier (with the `-api` switch) with one that will also generate the ORM API:: gnatcoll_db2ada -dbmode dbschema.txt -api Database -orm ORM The ORM provides a pool of database connections through the package `GNATCOLL.SQL.Sessions`. A session therefore acts as a wrapper around a connection, and provides a lot more advanced features that will be described later. The first thing to do in the code is to configure the session pool. The `Setup` procedure takes a lot of parameters to make sessions highly configurable. Some of these parameters will be described and used in this documentation, others are for special usage and are only documented in :file:`gnatcoll-sql-sessions.ads`. Here will we use only specify the mandatory parameters and leave the default value for the other parameters:: GNATCOLL.SQL.Sessions.Setup (Descr => GNATCOLL.SQL.Sqlite.Setup ("library.db"), Max_Sessions => 2); The first parameter is the same `Database_Description` we saw earlier (:ref:`Connecting_to_the_database`), but it will be freed automatically by the sessions package, so you should not free it yourself. Once configure, we can now request a session. Through a session, we can perform queries on the database, make objects persistent, write the changes back to the database,.... We configured the session pool to have at most 2 sessions. The first time we call `Get_New_Session`, a new session will be created in the pool and marked as busy. While you have a reference to it in your code (generally as a local variable), the session belongs to this part of the code. When the session is no longer in scope, it is automatically released to the pool to be reused for the next call to `Get_New_Session`. If you call `Get_New_Session` a second time while some part of your code holds a session (for instance in a different task), a new session will be created. But if you do that a third time while the other two are busy, the call to `Get_New_Session` is blocking until one of the two sessions is released to the pool. This technics ensures optimal use of the resources: we avoid creating a new session every time (with the performance cost of connecting to the database), but also avoid creating an unlimited number of sessions which could saturate the server. Since the sessions are created lazily the first time they are needed, you can also configure the package with a large number of sessions with a limited cost. Let's then take a new session in our code:: Session : constant Session_Type := Get_New_Session; and let's immediately write our first simple query. A customer comes at the library, handles his card and we see his id (1). We need to look up in the database to find out who he is. Fortunately, there is no SQL to write for this:: C : ORM.Detached_Customer'Class := Get_Customer (Session, Id => 1); The call to `Get_Customer` performs a SQL query transparently, using prepared statements for maximum efficiency. This results in a `Customer` object. `ORM` is the package that was generated automatically by `gnatcoll_db2ada`. For each table in the database, it generates a number of types: * `Customer` This type represents a row of the `Customers` table. It comes with a number of primitive operations, in particular one for each of the fields in the table. Such an object is returned by a cursor, similarly to what was described in the previous section (:ref:`Writing_your_own_cursors`). This object is no longer valid as soon as the cursor moves to the next row (in the currently implementation, the object will describe the next row, but it is best not to rely on this). As a benefit, this object is light weight and does not make a copy of the value of the fields, only reference the memory that is already allocated for the cursor. This object redefines the equality operator ("=") to compare the primary key fields to get expected results. * `Detached_Customer` A detached object is very similar to the `Customer` object, but it will remain valid even if the cursor moves or is destroyed. In fact, the object has made a copy of the value for all of its fields. This object is heavier than a `Customer`, but sometimes easier to manager. If you want to store an object in a data structure, you must always store a detached object. A detached object also embeds a cache for its foreign keys. In the context of our demo for instance, a `Book` object was borrowed by a customer. When returning from a query, the book knows the id of that customer. But if call `B.Borrowed_By` this returns a `Detached_Customer` object which is cached (the first time, a query is made to the DBMS to find the customer given his id, but the second time this value is already cached). One cache create a `Detached_Customer` from a `Customer` by calling the `Detach` primitive operation. * `Customer_List` This type extends a `Forward_Cursor` (:ref:`Getting_results`). In addition to the usual `Has_Row` and `Next` operations, it also provides an `Element` operation that returns a `Customer` for easy manipulation of the results. * `Direct_Customer_List` This type extends a `Direct_Cursor`. It also adds a `Element` operation that returns a `Customer` element. * `Customers_Managers` This type is the base type to perform queries on the DBMS. A manager provides a number of primitive operations which end up creating a SQL query operation in the background, without making that explicit. Let's first write a query that returns all books in the database:: declare M : Books_Managers := All_Books; BL : Book_List := M.Get (Session); B : Book; begin while BL.Has_Row loop B := BL.Element; Put_Line ("Book: " & B.Title); Put_Line (" Borrowed by: " & B.Borrowed_By.Last); BL.Next; end loop; end; The manager `M` corresponds to a query that returns all the books in the database. The second line then executes the query on the database, and returns a list of books. We then traverse the list. Note how we access the book's title by calling a function, rather than by the index of a field as we did with `GNATCOLL.SQL.Exec` with Value(B, 0). The code is much less fragile this way. The line that calls `Borrowed_By` will execute an additional SQL query for each book. This might be inefficient if there is a large number of books. We will show later how this can be optimized. The manager however has a lot more primitive operations that can be used to alter the result. Each of these primitive operations returns a modified copy of the manager, so that you can easily chain calls to those primitive operations. Those operations are all declared in the package `GNATCOLL.SQL.ORM.Impl` if you want to look at the documentation. Here are those operations: * `Get` and `Get_Direct` As seen in the example above, these are the two functions that execute the query on the database, and returns a list of objects (respectively a `Customer_List` and a `Direct_Customer_List`). * `Distinct` Returns a copy of the manager that does not return twice a row with the same data (in SQL, this is the "DISTINCT" operator) * `Limit` (Count : Natural; From : Natural := 0) Returns a copy of the manager that returns a subset of the results, for instance the first `Count` ones. * `Order_By` (By : SQL_Field_List) Returns a copy of the manager that sorts the results according to a criteria. The criteria is a list of field as was defined in `GNATCOLL.SQL`. We can for instance returns the list of books sorted by title, and only the first 5 books, by replacing `M` with the following:: M : Books_Managers := All_Books.Limit (5).Order_By (Books.Title); * `Filter` Returns a subset of the result matching a criteria. There are currently two versions of Filter: one is specialized for the table, and has one parameter for each field in the table. We can for instance return all the books by Alexandre Dumas by using:: M : Books_Managers := All_Books.Filter (Author => "Dumas"); This version only provides the equality operator for the fields of the table itself. If for instance we wanted all books with less than 50 pages, we would use the second version of filter. This version takes a `GNATCOLL.SQL.SQL_Criteria` similar to what was explained in previous sections, and we would write:: M : Books_Managers := All_Books.Filter (Condition => Books.Pages < 50); More complex conditions are possible, involving other tables. Currently, the ORM does not have a very user-friendly interface for those, but you can always do this by falling back partially to SQL. For instance, if we want to retrieve all the books borrowed by user "Smith", we need to involve the `Customers` table, and thus make a join with the `Books` table. In the future, we intend to make this join automatic, but for now you will need to write:: M : Books_Managers := All_Books.Filter (Books.FK (Customers) and Customers.Last = "Smith"); -- SQL query: SELECT books.pages, books.borrowed_by, books.id, -- books.title, books.author, books.published -- FROM books, customers -- WHERE books.borrowed_by=customers.id AND customers.last='Smith' This is still simpler code than we were writing with `GNATCOLL.SQL` because we do not have to specify the fields or tables, and the results are objects rather than fields with specific indexes. * `Select_Related` (Depth : Integer; Follow_Left_Join : Boolean) This function returns a new manager that will retrieve all related objects. In the example we gave above, we mentioned that every time `B.Borrowed_By` was called, this resulted in a call to the DBMS. We can optimize this by making sure the manager will retrieve that information. As a result, there will be a single query rather than lots. Be careful however, since the query will return more data, so it might sometimes be more efficient to perform multiple smaller queries. `Depth` indicates on how many levels the objects should be retrieved. For instance, assume we change the schema such that a Book references a Customer which references an Address. If we pass 1 for `Depth`, the data for the book and the customer will be retrieved. If however you then call `B.Borrowed_By.Address` this will result in a query. So if you pass 2 for `Depth` the data for book, customers and addresses will be retrieved. The second parameter related to efficiency. When a foreign key was mentioned as `NOT NULL` in the schema, we know it is always pointing to an existing object in another table. `Select_Related` will always retrieve such objects. If, however, the foreign key can be null, i.e. there isn't necessarily a corresponding object in the other table, the SQL query needs to use a `LEFT JOIN`, which is less efficient. By default, GNATColl will not retrieve such fields unless `Follow_Left_Join` was set to True. In our example, a book is not necessarily borrowed by a customer, so we need to follow the left joins:: M : Books_Managers := All_Books.Filter (Books.FK (Customers) and Customers.Last = "Smith") .Select_Related (1, Follow_Left_Join => True); -- SQL query: SELECT books.pages, books.borrowed_by, books.id, -- books.title, books.author, books.published, -- customers.id, customers.first, customers.last -- FROM (books LEFT JOIN customers ON books.borrowed_by=customers.id) -- WHERE books.borrowed_by=customers.id AND customers.last='Smith' reverse relationships --------------------- In fact, the query we wrote above could be written differently. Remember we have already queries the `Customer` object for id 1 through a call to `Get_Customer`. Since our schema specified a `reverse_name` for the foreign key `borrowed_by` in the table `books`, we can in fact simply use:: BL := C.Borrowed_Books.Get (Session); -- SQL: SELECT books.pages, books.borrowed_by, books.id, books.title, -- books.author, books.published FROM books -- WHERE books.borrowed_by=1 `Borrowed_Books` is a function that was generated because there was a `reverse_name`. It returns a `Books_Managers`, so we could in fact further filter the list of borrowed books with the same primitive operations we just saw. As you can see, the resulting SQL is optimital. Let's optimize further the initial query. We have hard-coded the customer name, but in fact we could be using the same subprograms we were using for prepared statements (:ref:`Prepared_queries`), and even prepare the query on the server for maximum efficiency. Since our application is likely to use this query a lot, let's create a global variable:: M : constant Books_Managers := All_Books.Filter (Books.FK (Customers) and Customers.Id = Integer_Param (1)) .Select_Related (1, Follow_Left_Join => True); MP : constant ORM_Prepared_Statement := M.Prepare (On_Server => True); ... later in the code Smith_Id : constant Natural := 1; BL : Book_List := MP.Get (Session, Params => (1 => Smith_Id)); The last call to `Get` is very efficient, with timing improvements similar to the ones we discussed on the session about prepared statements (:ref:`Prepared_queries`). Modifying objects in the ORM ============================ The ORM is much more than writing queries. Once the objects are persistent, they can also be simplify modified, and they will be saved in the database transparently. Let's start with a simple example. In the previous section, we retrieve an object `C` representing a customer. Let's change his name, and make sure the change is in the database:: C := Get_Customer (Session, 1); C.Set_Last ("Smit"); C.Set_First ("Andrew"); Session.Commit; A reasonable way to modify the database. However, this opens a can of complex issues that need to be dealt with. When we called `Set_Last`, this modify the objects in memory. At this point, printing the value of `C.Last` would indeed print the new value as expected. The object was also marked as modified. But no change was made in the database. Such a change in the database might in fact be rejected, depending on whether there are constraints on the field. For instance, say there existed a constraint that `Last` must be the same `First` (bear with me, this is just an example). If we call `Set_Last`, the constraint is not satisfied until we also call `Set_First`. But if the former resulted in an immediate change in the database, it would be rejected and we would not even get a change to call `Set_First`. .. highlight:: sql Instead, the session keeps a pointer to all the objects that have been modified. When it is committed, it traverses this list of objects, and commits their changes into the database. In the example we gave above, the call to `Commit` will thus commit the changes to `C` in the database. For efficiency, it uses a single SQL statement for that, which also ensures the constraint remains valid:: UPDATE customers SET first='Andrew', last='Smit' WHERE customers.id=1; .. highlight:: ada We can create a new customer by using similar code:: C := New_Customer; C.Set_First ("John"); C.Set_Last ("Lee"); Session.Persist (C); Session.Commit; `New_Customer` allocates a new object in memory. However, this object is not persistent. You can call all the `Set_*` subprograms, but the object will not be saved in the database until you add it explicitly to a session with a call to `Persist`, and then `Commit` the session as usual. Another issue can occur when objects can be modified in memory. Imagine we retrieve a customer, modify it in memory but do not commit to the database yet because there are other changes we want to do in the same SQL transaction. We then retrieve the list of all customers. Of course, the customer we just modified is part of this list, but the DBMS does not know about the change which currently only exists in memory. Thankfully, GNATColl takes care of this issue automatically: as we mentioned before, all modified objects are stored in the session. When traversing the list of results, the cursors will check whether the session already contains an element with the same id that it sees in the result, and if yes will return the existing (i.e. modified) element. For instance:: C := Get_Customer (Session, Id => 1); C.Set_Last ("Lee"); CL : Customer_List := All_Customers.Get (Session); while CL.Has_Row loop Put_Line (CL.Element.Last); CL.Next; end loop; .. index:: Flush_Before_Query The above example uses `CL.Element`, which is a light-weight `Customer` object. Such objects will only see the in-memory changes if you have set `Flush_Before_Query` to true when you configured the sessions in the call to `GNATCOLL.SQL.Sessions.Setup`. Otherwise, it will always return what's really in the database. If the example was using `Detached_Customer` object (by calling `CL.Element.Detach` for instance) then GNATColl looks up in its internal cache and returns the cached element when possible. This is a subtlety, but this is because an `Customer` only exists as long as its cursor, and therefore cannot be cached in the session. In practice, the `Flush_Before_Query` should almost always be true and there will be not surprising results. Object factories in ORM ======================= Often, a database table is used to contain objects that are semantically of a different kind. In this section, we will take a slightly different example from the library. We no longer store the books and the DVDs in separate tables. Instead, we have one single `media` table which contains the title and the author, as well as a new field `kind` which is either 0 for a book or 1 for a DVD. Let's now look at all the media borrowed by a customer:: C : constant Customer'Class := Get_Customer (Session, Id => 1); ML : Media_List := C.Borrowed_Media.Get (Session); while ML.Has_Row loop case ML.Element.Kind is when 0 => Put_Line ("A book " & ML.Element.Title); when 1 => Put_Line ("A DVD " & ML.Element.Title); end case; ML.Next; end loop; This code works, but requires a case statement. Now, let's imagine the check out procedure is different for a book and a DVD (for the latter we need to check that the disk is indeed in the box). We would have two subprograms `Checkout_Book` and `Checkout_DVD` and call them from the case. This isn't object-oriented programming. Instead, we will declare two new types:: type My_Media is abstract new ORM.Detached_Media with private; procedure Checkout (Self : My_Media) is abstract; type Detached_Book is new My_Media with private; overriding Checkout (Self : Detached_Book); type Detached_DVD is new My_Media with private; overriding Checkout (Self : Detached_DVD); We could manually declare a new Media_List and override `Element` so that it returns either of the two types instead of a `Media`. But then we would also need to override `Get` so that it returns our new list. This is tedious. We will instead use an element factory in the session. This is a function that gets a row of a table (in the form of a `Customer`), and returns the appropriate type to use when the element is detached (by default, the detached type corresponding to a `Customer` is a `Detached_Customer`, and that's what we want to change). So let's create such a factory:: function Media_Factory (From : Base_Element'Class; Default : Detached_Element'Class) return Detached_Element'Class is begin if From in Media'Class then case Media (From).Kind is when 0 => return R : Detached_Book do null; end return; when 1 => return R : Detached_DVD do null; end return; when others => return Default; end case; end if; return Default; end Media_Factory; Session.Set_Factory (Media_Factory'Access); This function is a bit tricky. It is associated with a given session (although we can also register a default factory that will be associated with all sessions by default). For all queries done through this session (and for all tables) it will be called. So we must first check whether we are dealing with a row from the `Media` table. If not, we simply return the suggested `Default` value (which has the right `Detached_*` kind corresponding to the type of `From`). If we have a row from the `Media` table, we then retrieve its kind (through the usual automatically generated function) to return an instance of `Detached_Book` or `Detached_DVD`. We use the Ada05 notation for extended return statements, but we could also use a declare block with a local variable and return that variable. The returned value does not need to be further initialized (the session will take care of the rest of the initialization). We can now write our code as such:: C : constant Customer'Class := Get_Customer (Session, Id => 1); ML : Media_List := C.Borrowed_Media.Get (Session); while ML.Has_Row loop Checkout (ML.Element.Detach); -- Dispatching ML.Next; end loop; The loop is cleaner. Of course, we still have the case statement, but it now only exists in the factory, no matter how many loops we have or how many primitive operations of the media we want to define. alire-1.2.1/deps/gnatcoll-slim/docs/storage_pools.rst000066400000000000000000000045631425465243200226700ustar00rootroot00000000000000************************************************ **Storage Pools**: controlling memory management ************************************************ Ada gives full control to the user for memory management. That allows for a number of optimization in your application. For instance, if you need to allocate a lot of small chunks of memory, it is generally more efficient to allocate a single large chunk, which is later divided into smaller chunks. That results in a single system call, which speeds up your application. This can of course be done in most languages. However, that generally means you have to remember not to use the standard memory allocations like `malloc` or `new`, and instead call one of your subprograms. If you ever decide to change the allocation strategy, or want to experiment with several strategies, that means updating your code in several places. In Ada, when you declare the type of your data, you also specify through a `'Storage_Pool` attribute how the memory for instances of that type should be allocated. And that's it. You then use the usual `new` keyword to allocate memory. GNATColl provides a number of examples for such storage pools, with various goals. There is also one advanced such pool in the GNAT run-time itself, called `GNAT.Debug_Pools`, which allows you to control memory leaks and whether all accesses do reference valid memory location (and not memory that has already been deallocated). In GNATColl, you will find the following storage pools: *`GNATCOLL.Storage_Pools.Alignment`* This pool gives you full control over the alignment of your data. In general, Ada will only allow you to specify alignments up to a limited number of bytes, because the compiler must only accept alignments that can be satisfied in all contexts, in particular on the stack. This package overcomes that limitation, by allocating larger chunks of memory than needed, and returning an address within that chunk which is properly aligned. *`GNATCOLL.Storage_Pools.Headers`* This pool allows you to allocate memory for the element and reserve extra space before it for a header. This header can be used to store per-element information, like for instance a reference counter, or next and previous links to other elements in the same collection. In many cases, this can be used to reduce the number of allocations, and thus speed up the overall application. alire-1.2.1/deps/gnatcoll-slim/docs/strings.rst000066400000000000000000000302261425465243200214740ustar00rootroot00000000000000.. highlight:: ada ************************************* **Strings**: high-performance strings ************************************* The generic package :file:`GNATCOLL.Strings_Impl` (and its default instantiation in :file:`GNATCOLL.Strings`) provides a high-performance strings implementation. It comes in addition to Ada's own `String` and `Unbounded_String` types, although it attempts to find a middle ground in between (flexibility vs performance). GNATCOLL.Strings therefore provides strings (named `XString`, as in extended-strings) that can grow as needed (up to `Natural'Last`, like standard strings), yet are faster than unbounded strings. They also come with an extended API, which includes all primitive operations from unbounded strings, in addition to some subprograms inspired from GNATCOLL.Utils and the python and C++ programming languages. Small string optimization ========================= GNATCOLL.Strings uses a number of tricks to improve on the efficiency. The most important one is to limit the number of memory allocations. For this, we use a trick similar to what all C++ implementations do nowadays, namely the small string optimization. The idea is that when a string is short, we can avoid all memory allocations altogether, while still keeping the string type itself small. We therefore use an Unchecked_Union, where a string can be viewed in two ways:: Small string [f][s][ characters of the string 23 bytes ] f = 1 bit for a flag, set to 0 for a small string s = 7 bits for the size of the string (i.e. number of significant characters in the array) Big string [f][c ][size ][data ][first ][pad ] f = 1 bit for a flag, set to 1 for a big string c = 31 bits for half the capacity. This is the size of the buffer pointed to by data, and which contains the actual characters of the string. size = 32 bits for the size of the string, i.e. the number of significant characters in the buffer. data = a pointer (32 or 64 bits depending on architecture) first = 32 bits, see the handling of substrings below pad = 32 bits on a 64 bits system, 0 otherwise. This is because of alignment issues. So in the same amount of memory (24 bytes), we can either store a small string of 23 characters or less with no memory allocations, or a big string that requires allocation. In a typical application, most strings are smaller than 23 bytes, so we are saving very significant time here. This representation has to work on both 32 bits systems and 64 bits systems, so we have careful representation clauses to take this into account. It also needs to work on both big-endian and little-endian systems. Thanks to Ada's representation clauses, this one in fact relatively easy to achieve (well, okay, after trying a few different approaches to emulate what's done in C++, and that did not work elegantly). In fact, emulating via bit-shift operations ended up with code that was less efficient than letting the compiler do it automatically because of our representation clauses. Character types =============== Applications should be able to handle the whole set of Unicode characters. In Ada, these are represented as the Wide_Character type, rather than Character, and stored on 2 bytes rather than 1. Of course, for a lot of applications it would be wasting memory to always store 2 bytes per character, so we want to give flexibility to users here. So the package GNATCOLL.Strings_Impl is a generic. It has several formal parameters, among which: * Character_Type is the type used to represent each character. Typically, it will be Character, Wide_Character, or even possibly Wide_Wide_Character. It could really be any scalar type, so for instance we could use this package to represent DNA with its 4-valued nucleobases. * Character_String is an array of these characters, as would be represented in Ada. It will typically be a String or a Wide_String. This type is used to make this package work with the rest of the Ada world. Note about Unicode: we could also always use a Character, and use UTF-8 encoding internally. But this makes all operations (from taking the length to moving the next character) slower, and more fragile. We must make sure not to cut a string in the middle of a multi-byte sequence. Instead, we manipulate a string of code points (in terms of Unicode). A similar choice is made in Ada (String vs Wide_String), Python and C++. Configuring the size of small strings ===================================== The above is what is done for most C++ implementations nowadays. The maximum 23 characters we mentioned for a small string depends in fact on several criteria, which impact the actual maximum size of a small string: * on 32 bits system, the size of the big string is 16 bytes, so the maximum size of a small string is 15 bytes. * on 64 bits system, the size of the big string is 24 bytes, so the maximum size of a small string is 23 bytes. * If using a Character as the character type, the above are the actual number of characters in the string. But if you are using a Wide_Character, this is double the maximum length of the string, so a small string is either 7 characters or 11 characters long. This is often a reasonable number, and given that applications mostly use small strings, we are already saving a lot of allocations. However, in some cases we know that the typical length of strings in a particular context is different. For instance, GNATCOLL.Traces builds messages to output in the log file. Such messages will typically be at most 100 characters, although they can of course be much larger sometimes. We have added one more formal parameter to GNATCOLL.Strings_Impl to control the maximum size of small strings. If for instance we decide that a "small" string is anywhere from 1 to 100 characters long (i.e. we do not want to allocate memory for those strings), it can be done via this parameter. Of course, in such cases the size of the string itself becomes much larger. In this example it would be 101 bytes long, rather than the 24 bytes. Although we are saving on memory allocations, we are also spending more time copying data when the string is passed around, so you'll need to measure the performance here. The maximum size for the small string is 127 bytes however, because this size and the 1-bit flag need to fit in 1 bytes in the representation clauses we showed above. We tried to make this more configurable, but this makes things significantly more complex between little-endian and big-endian systems, and having large "small" strings would not make much sense in terms of performance anyway. Typical C++ implementations do not make this small size configurable. Task safety =========== Just like unbounded strings, the strings in this package are not thread safe. This means that you cannot access the same string (read or write) from two different threads without somehow protecting the access via a protected type, locks,... In practice, sharing strings would rarely be done, so if the package itself was doing its own locking we would end up with very bad performance in all cases, for a few cases where it might prove useful. As we'll discuss below, it is possible to use two different strings that actually share the same internal buffer, from two different threads. Since this is an implementation detail, this package takes care of guaranteeing the integrity of the shared data in such a case. Copy on write ============= There is one more formal parameter, to configure whether this package should use copy-on-write or not. When copy on write is enabled, you can have multiple strings that internally share the same buffer of characters. This means that assigning a string to another one becomes a reasonably fast operation (copy a pointer and increment a refcount). Whenever the string is modified, a copy of the buffer is done so that other copies of the same string are not impacted. But in fact, there is one drawback with this scheme: we need reference counting to know when we can free the shared data, or when we need to make a copy of it. This reference counting must be thread safe, since users might be using two different strings from two different threads, but they share data internally. Thus the reference counting is done via atomic operations, which have some impact on performance. Since multiple threads try to access the same memory addresses, this is also a source of contention in multi-threaded applications. For this reason, the current C++ standard prevents the use of copy-on-write for strings. In our case, we chose to make this configurable in the generic, so that users can decide whether to pay the cost of the atomic operations, but save on the number of memory allocations and copy of the characters. Sometimes it is better to share the data, sometimes to systematically copy it. Again, actual measurements of the performance are needed for your specific application. Growth strategy =============== When the current size of the string becomes bigger than the available allocated memory (for instance because you are appending characters), this package needs to reallocate memory. There are plenty of strategies here, from allocating only the exact amount of memory needed (which saves on memory usage, but is very bad in terms of performance), to doubling the current size of the string until we have enough space, as currently done in the GNAT unbounded strings implementation. The latter approach would therefore allocate space for two characters, then for 4, then 8 and so on. This package has a slightly different strategy. Remember that we only start allocating memory past the size of small strings, so we will for instance first allocate 24 bytes. When more memory is needed, we multiply this size by 1.5, which some researchers have found to be a good comprise between waste of memory and number of allocations. For very large strings, we always allocate multiples of the memory page size (4096 bytes), since this is what the system will make available anyway. So we will basically allocate the following: 24, 36, 54, 82, 122,... An additional constraint is that we only ever allocate even number of bytes. This is called the capacity of the string. In the layout of the big string, as shown above, we store half that capacity, which saves one bit that we use for the flag. Substrings ========== One other optimization performed by this package (which is not done for unbounded strings or various C++ implementations) is to optimize substrings when also using copy-on-write. We simply store the index of the first character of the string within the shared buffer, instead of always starting at the first. From the user's point of view, this is an implementation detail. Strings are always indexed from 1, and internally we convert to an actual position in the buffer. This means that if we need to reallocate the buffer, for instance when the string is modified, we transparently change the index of the first character, but the indexes the user was using are still valid. This results in very significant savings, as shown below in the timings for Trim for instance. Also, we can do an operation like splitting a string very efficiently. For instance, the following code doesn't allocate any memory, beside setting the initial value of the string. It parses a file containing some "key=value" lines, with optional spaces, and possibly empty lines:: declare S, Key, Value : XString; L : XString_Array (1 .. 2); Last : Natural; begin S.Set ("......."); -- Get each line for Line in S.Split (ASCII.LF) loop -- Split into at most two substrings Line.Split ('=', Into => L, Last => Last); if Last = 2 then Key := L (1); Key.Trim; -- Removing leading and trailing spaces Value := L (2); Value.Trim; end if; end loop; end; API === This package provides a very extensive set of API that apply to `XString`, please check the spec in :file:`gnatcoll-strings_impl.ads` for a fully documented list. alire-1.2.1/deps/gnatcoll-slim/docs/templates.rst000066400000000000000000000056751425465243200220130ustar00rootroot00000000000000****************************** **Templates**: generating text ****************************** .. index:: templates This module provides convenient subprograms for replacing specific substrings with other values. It is typically used to replace substrings like "%{version}" in a longer string with the actual version, at run time. This module is not the same as the templates parser provided in the context of AWS, the Ada web server, where external files are parsed and processed to generate other files. The latter provides advanced features like filters, loops,... The substrings to be replaced always start with a specific delimiter, which is set to `%` by default, but can be overridden in your code. The name of the substring to be replaced is then the identifier following that delimiter, with the following rules: * If the character following the delimiter is the delimiter itself, then the final string will contain a single instance of that delimiter, and no further substitution is done for that delimiter. An example of this is `"%%"`. * If the character immediately after the delimiter is a curly brace (`{`), then the name of the identifier is the text until the next closing curly brace. It can then contain any character expect a closing curly brace. An example of this is `"%{long name}"` * If the first character after the delimiter is a digit, then the name of the identifier is the number after the delimiter. An example of this is `"%12"`. As a special case, if the first non-digit character is the symbol `-`, it is added as part of the name of the identifier, as in `"%1-"`. One use for this feature is to indicate you want to replace it with all the positional parameters %1%2%3%4. For instance, if you are writing the command line to spawn an external tool, to which the user can pass any number of parameter, you could specify that command line as `"tool -o %1 %2-"` to indicate that all parameters should be concatenated on the command line. * If the first character after the delimiter is a letter, the identifier follows the same rules as for Ada identifiers, and can contain any letter, digit, or underscore character. An example of this is `"%ab_12"`. For readability, it is recommended to use the curly brace notation when the name is complex, but that is not mandatory. * Otherwise the name of the identifier is the single character following the delimiter For each substring matching the rules above, the `Substitute` subprogram will look for possible replacement text in the following order: * If the `Substrings` parameter contains an entry for that name, the corresponding value is used. * Otherwise, if a `callback` was specified, it is called with the name of the identifier, and should return the appropriate substitution (or raise an exception if no such substitution makes sense). * A default value provided in the substring itself * When no replacement string was found, the substring is kept unmodified alire-1.2.1/deps/gnatcoll-slim/docs/terminals.rst000066400000000000000000000044651425465243200220070ustar00rootroot00000000000000************************************* **Terminal**: controlling the console ************************************* .. highlight:: ada Applications generally provide user feedback either via full-fledge graphical interfaces, or via a simpler, console-based output. The basic support for console-based output is provided directly via `Ada.Text_IO`. But more advanced features are highly system-dependent, and somewhat tricky to develop. The package `GNATCOLL.Terminal` provide cross-platform support for manipulating colors in terminals, as well as a few basic cursor manipulation subprograms. Colors ====== Most modern terminals support color output, generally with a limit set of colors. On Unix systems, these colors are set by using escape sequences in the output; on Windows systems, these are manipulated by calling functions on a file handle. GNATCOLL will automatically try to guess whether its output is sent to a color enabled terminal. In general, this will be true when outputing to standard output or standard error, and false when outputing to files or to pipes. You can override this default value to force either color support or black-and-white support. Here is an example:: with Ada.Text_IO; use Ada.Text_IO; with GNATCOLL.Terminal; use GNATCOLL.Terminal; procedure Test_Colors is Info : Terminal_Info; begin Info.Init_For_Stdout (Auto); Info.Set_Color (Standard_Output, Blue, Yellow); Put_Line ("A blue on yellow line"); Info.Set_Color (Standard_Output, Style => Reset_All); Put_Line ("Back to standard colors -- much better"); end Test_Colors; Cursors ======= It is often useful for an application to display some progress indicator during long operations. `GNATCOLL.Terminal` provides a limit set of subprograms to do so, as in:: with Ada.Text_IO; use Ada.Text_IO; with GNATCOLL.Terminal; use GNATCOLL.Terminal; procedure Test_Colors is Info : Terminal_Info; begin Info.Init_For_Stdout (Auto); for J in 1 .. 1_000 loop if J mod 10 = 0 then Put ("Processing file" & J'Img & " with long name"); else Put ("Processing file" & J'Img); end if; delay 0.1; Info.Beginning_Of_Line; Info.Clear_To_End_Of_Line; end loop; end Test_Colors; alire-1.2.1/deps/gnatcoll-slim/docs/tip.png000066400000000000000000000041371425465243200205550ustar00rootroot00000000000000‰PNG  IHDR"":G ÂbKGDÿÿÿ ½§“ pHYsHHFÉk>ÿIDATXÃÍ—klÕÇçÎìÃk¯ml‹Ä8N(!)!@bL¡P PC)êKU•Z µ¤V Vê‡B%*P¥RT)¨‘ª€ªªR*¨ú—ÔðHÄu¤«¹«»ç7ÿ{ÎÿÜ…ÿ“KÎõ€ŽlDA$Y¢ ¸ä®61¸4Jæj“¹$adÓÂY㘳C\‘DÁ%Y'&]o¯anRZ©C»}·ðùI jD@A5 ¤ÔI¢@ .Òd);ÔNQ§¨Ö£É@å³)¢#—7*QSÁñÄÉ€É"’Iæ’IæøÉs⟢”ÔÞJ‡òçV$ÐÚWA$Ù %¹ƒAœAmMÅEŠ .r¸Ø¢Ö‚u¨ZÔ)‚Ò M£2þrˆ&HYÊñQñió=mõ¼vÏä>8´/—­ŸÏ Qºþ&Ü|M¦ÒÓ›‰wçbTâôŨ«oöÙё˨§9*">‘,=9ïåfÚÿøôø€Ÿ-Ü ˜/ œß^ô½ ¨Î¡ñH”÷\¾Îí}øwm£­³QLGàBTcDm QuU¤¢aKƒŠHãeiÉdúíѵïáîë®îÿÖM_éë¹|Ãy[MR¦¶Ì'£Ó¼þæx´÷É¡OFg·?ñ«ü+¥D9®‚F 0Í¥8PmÙØ ’$Û¡&ƒñr´ø¹{¨·«‡—¾`ê¼5Q£‡×B\ièVP'à xüçÍÒÀ-ׯì+¶eÒôIS¨)¨4 šækWû™ ûü+·mº(’*N“"¨bPƤ§ Tæ½èüî\‡ñÓçbÔ…h 6HµÖè$ÍAM•U¥·[X¿Úô½ý¡ë¤5UBROk¸ûh|kÀ ”¹øÂÖL[¤:H«#ÆFŽPèl£«·lµUJ“³ä³2~\WØ÷ÕP»§fµ•™'ФDu¹Å'9L´j«h¼tŸ®²¦×yÿÐÌTX.A\;O6[&›pa™Œ136A¾Å‹´µ;°åTÁ 'NVùè¿öã­[dŠ9E“ÜhF®˜„–ŽÆ“U ;&ªúýÛ2¾¶orxzrìDóˆgåê +VgY³¡•b‡cÕº<½útv[ˆ°‹Ø°Ì»ÃálPfï¦[X¤Údh§(RwDWwFÔ:ÔZÂØn½Ý›ŽÃÊÎç^<¾¨ñ<Ø9ˆæð(‘ñ«œ×³îŠ-àûÄ•pl¬Ì¿_sï}÷VÞâ¤&Ç¥>£g!UÃ*êX‹ÚX².ÞºE^}áÕ©—^ë¤âæ ž%*A<‹¸Ú_ÉŒ^G”=>¾¦ýõ}Ý—PâB˜,? .…n‘A‹î7MX€C‰¡ŠYýU3WúÙô±K6l oÕ*å2ž±l¾,C¦v>3Þc‚°i;ÎX-§IÂ׎‹º"Húƒ‚SÏÓxtfzª488ØV(ð<8Ž9ztçâ±uýœ ZW¢ÒѨÆiAä*E÷+Ð Œ/ÁÔ®\{k|hÏžÝ3ímëׯ§³³“0 : Ã‡Ž<÷“Ì`O—œ§ƒX–¬MÂì_ö\r„ôñžyžÂýgSi¹;›Íæ}ßÇ©RY,è??¸ïàC ¡§øÆç9#ŒbèCný&+÷¼Ë•;º<ý=<óÁ¿Ø×éã&Ï8+Ä9AÎ#Â>" is used instead of ">" to redirect to that stream, the file is appended to, instead of truncated. *"&1"* This syntax is similar to the one used on Unix shells, and indicates that the output should be displayed on the standard output for the application. If the application is graphical, and in particular on Windows platforms, it is possible that there is no standard output! *"&2"* Similar to the previous one, but the output is sent to standard error. *"&syslog"* :ref:`Logging_to_syslog`. Comments in a configuration file must be on a line of their own, and start with `--`. Empty lines are ignored. The rest of the lines represent configurations, as in: * If a line contains the single character `"+"`, it activates all `trace_handle` by default. This means the rest of the configuration file should disable those handles that are not needed. The default is that all handles are disabled by default, and the configuration file should activate the ones it needs. The Ada source code can change the default status of each handles, as well * If the line starts with the character `">"`, followed by a stream name (as defined above), this becomes the default stream. All handles will be displayed on that stream, unless otherwise specified. If the stream does not exist, it defaults to standard output. * Otherwise, the first token on the line is the name of a handle. If that is the only element on the line, the handle is activated, and will be displayed on the default stream. Otherwise, the next element on the line should be a `"="` sign, followed by either `"yes"` or `"no"`, depending on whether the handle should resp. be enabled or disabled. Finally, the rest of the line can optionally contain the `">"` character followed by the name of the stream to which the handle should be directed. There is are two special cases for the names on this line: they can start with either `"\*."` or `".\*"` to indicate the settings apply to a whole set of handles. See the example below. Here is a short example of a configuration file. It activates all handles by default, and defines four handles: two of them are directed to the default stream (standard error), the third one to a file on the disk, and the last one to the system logger syslog (if your system supports it, otherwise to the default stream, ie standard error):: + >&2 MODULE1 MODULE2=yes SYSLOG=yes >&syslog:local0:info FILE=yes >/tmp/file -- decorators (see below) DEBUG.COLORS=yes -- Applies to FIRST.EXCEPTIONS, LAST.EXCEPTIONS,... -- and forces them to be displayed on stdout *.EXCEPTIONS=yes > stdout -- Applies to MODULE1, MODULE1.FIRST,... This can be used to -- disable a whole hierarchy of modules. -- As always, the latest config overrides earlier ones, so the -- module MODULE1.EXCEPTIONS would be disabled as well. MODULE1.*=no .. _Using_the_traces_module: Using the traces module ======================= If you need or want to parse an external configuration file as described in the first section, the code that initializes your application should contain a call to `GNATCOLL.Traces.Parse_Config_File`. As documented, this takes in parameter the name of the configuration file to parse. When none is specified, the algorithm specified in the previous section will be used to find an appropriate configuration:: GNATCOLL.Traces.Parse_Config_File; The code, as written, will end up looking for a file :file:`.gnatdebug` in the current directory. The function :code:`Parse_Config_File` must be called to indicate that you want to activate the traces. It must also end up finding a configuration file. If it does not, then none of the other functions will ever output anything. This is to make sure your application does not start printing extra output just because you happen to use an external library that uses :code:`GNATCOLL.Traces`. It also ensures that your application will not try to write to :code:`stdout` unless you think it is appropriate (since :code:`stdout` might not even exist in fact). You then need to declare each of the `trace_handle` (or `logger`) that your application will use. The same handle can be declared several times, so the recommended approach is to declare locally in each package body the handles it will need, even if several bodies actually need the same handle. That helps to know which traces to activate when debugging a package, and limits the dependencies of packages on a shared package somewhere that would contain the declaration of all shared handles. .. index:: Trace_Handle .. index:: Logger Function Trace_Handle Create Name Default Stream Factory Finalize This function creates (or return an existing) a `trace_handle` with the specified `Name`. Its default activation status can also be specified (through `Default`), although the default behavior is to get it from the configuration file. If a handle is created several times, only the first call that is executed can define the default activation status, the following calls will have no effect. `Stream` is the name of the stream to which it should be directed. Here as well, it is generally better to leave things to the configuration file, although in some cases you might want to force a specific behavior. `Factory` is used to create your own child types of `trace_handle` (:ref:`Log_decorators`). Here is an example with two package bodies that define their own handles, which are later used for output:: package body Pkg1 is Me : constant Trace_Handle := Create ("PKG1"); Log : constant Trace_Handle := Create ("LOG", Stream => "@syslog"); end Pkg1; package body Pkg2 is Me : constant Trace_Handle := Create ("PKG2"); Log : constant Trace_Handle := Create ("LOG", Stream => "@syslog"); end Pkg2; Once the handles have been declared, output is a matter of calling the `GNATCOLL.Traces.Trace` procedure, as in the following sample:: Trace (Me, "I am here"); An additional subprogram can be used to test for assertions (pre-conditions or post-conditions in your program), and output a message whether the assertion is met or not:: Assert (Me, A = B, "A is not equal to B"); If the output of the stream is done in color, a failed assertion is displayed with a red background to make it more obvious. Logging unexpected exceptions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A special version of `Trace` is provided, which takes an `Exception_Occurrence` as argument, and prints its message and backtrace into the corresponding log stream. This procedure will in general be used for unexcepted exceptions. Since such exceptions should be handled by developers, it is possible to configure `GNATCOLL.TRACES` to use special streams for those. `Trace (Me, E)` will therefore not used `Me` itself as the log handle, but will create (on the fly, the first time) a new handle with the same base name and and `.EXCEPTIONS` suffix. Therefore, you could put the following in your configuration file:: # Redirect all exceptions to stdout *.EXCEPTIONS=yes >& stdout and then the following code will output the exception trace to stdout:: procedure Proc is Me : Create ("MYMODULE"); begin ... exception when E : others => Trace (Me, E, Msg => "unexcepted exception:"); end Proc; Checking whether the handle is active ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As we noted before, handles can be disabled. In that case, your application should not spend time preparing the output string, since that would be wasted time. In particular, using the standard Ada string concatenation operator requires allocating temporary memory. It is therefore recommended, when the string to display is complex, to first test whether the handle is active. This is done with the following code:: if Active (Me) then Trace (Me, A & B & C & D & E); end if; .. _Log_decorators: Log decorators ============== .. index:: decorator, log Speaking of color, a number of decorators are defined by `GNATCOLL.Traces`. Their goal is not to be used for outputting information, but to configure what extra information should be output with all log messages. They are activated through the same configuration file as the traces, with the same syntax (i.e either `"=yes"` or `"=no"`). Here is an exhaustive list: *DEBUG.ABSOLUTE_TIME* If this decorator is activated in the configuration file, the absolute time when Trace is called is automatically added to the output, when the streams supports it (in particular, this has no effect for syslog, which already does this on its own). *DEBUG.MICRO_TIME* If active, the time displayed by DEBUG.ABSOLUTE_TIME will use a microseconds precision, instead of milliseconds. *DEBUG.ELAPSED_TIME* If this decorator is activated, then the elapsed time since the last call to Trace for the same handle is also displayed. *DEBUG.STACK_TRACE* If this decorator is activated, then the stack trace is also displayed. It can be converted to a symbolic stack trace through the use of the external application `addr2line`, but that would be too costly to do this automatically for each message. *DEBUG.LOCATION* If this decorator is activated, the location of the call to Trace is automatically displayed. This is a file:line:column information. This works even when the executable wasn't compiled with debug information *DEBUG.ENCLOSING_ENTITY* Activate this decorator to automatically display the name of the subprogram that contains the call to `Trace`. *DEBUG.COLORS* If this decorator is activated, the messages will use colors for the various fields, if the stream supports it (syslog doesn't). *DEBUG.COUNT* This decorator displays two additional numbers on each line: the first is the number of times this handle was used so far in the application, the second is the total number of traces emitted so far. These numbers can for instance be used to set conditional breakpoints on a specific trace (break on `gnat.traces.log` or `gnat.traces.trace` and check the value of `Handle.Count`. It can also be used to refer to a specific line in some comment file. *DEBUG.MEMORY* Every time a message is output, display the amount of memory currently in use by the application. *DEBUG.SPLIT_LINES* When this is enabled, messages are split at each newline character. Each line then starts with the name of the logger, indentation level and so on. This might result in more readable output, but is slightly slower. *DEBUG.FINALIZE_TRACES* This handle is activated by default, and indicates whether `GNATCOLL.Traces.Finalize` should have any effect. This can be set to False when debugging, to ensure that traces are available during the finalization of your application. Here is an example of output where several decorators were activated. In this example, the output is folded on several lines, but in reality everything is output on a single line:: [MODULE] 6/247 User Message (2007-07-03 13:12:53.46) (elapsed: 2ms)(loc: gnatcoll-traces.adb:224) (entity:GNATCOLL.Traces.Log) (callstack: 40FD9902 082FCFDD 082FE8DF ) Depending on your application, there are lots of other possible decorators that could be useful (for instance the current thread, or the name of the executable when you have several of them,...). Since `GNATCOLL.Traces` cannot provide all possible decorators, it provides support, through tagged types, so that you can create your own decorators. This needs you to override the `Trace_Handle_Record` tagged type. Since this type is created through calls to `GNATCOLL.Traces.Create`. This is done by providing an additional `Factory` parameter to `Create`; this is a function that allocates and returns the new handle. Then you can override either (or both) of the primitive operations `Pre_Decorator` and `Post_Decorator`. The following example creates a new type of handles, and prints a constant string just after the module name:: type My_Handle is new Trace_Handle_Record with null record; procedure Pre_Decorator (Handle : in out My_Handle; Stream : in out Trace_Stream_Record'Class; Message : String) is begin Put (Stream, "TEST"); Pre_Decorator (Trace_Handle_Record (Handle), Stream, Message); end**; function Factory return Trace_Handle is begin return new My_Handle; end; Me : Trace_Handle := Create ("MODULE", Factory => Factory'Access); As we will see below (:ref:`Dynamically_disabling_features`), you can also make all or part of your decorators conditional and configurable through the same configuration file as the trace handles themselves. .. _Defining_custom_stream_types: Defining custom stream types ============================ We noted above that several predefined types of streams exist, to output to a file, to standard output or to standard error. Depending on your specific needs, you might want to output to other media. For instance, in a graphical application, you could have a window that shows the traces (perhaps in addition to filing them in a file, since otherwise the window would disappear along with its contents if the application crashes); or you could write to a socket (or even a CORBA ORB) to communicate with another application which is charge of monitoring your application. You do not need the code below if you simply want to have a new stream in your application (for instance using one for logging Info messages, one for Error messages, and so on). In this case, the function `Create` is all you need. `GNATCOLL.Traces` provides the type `Trace_Stream_Record`, which can be overridden to redirect the traces to your own streams. Let's assume for now that you have defined a new type of stream (called `"mystream"`). To keep the example simple, we will assume this stream also redirects to a file. For flexibility, however, you want to let the user configure the file name from the traces configuration file. Here is an example of a configuration file that sets the default stream to a file called :file:`foo`, and redirects a specific handle to another file called :file:`bar`. Note how the same syntax that was used for standard output and standard error is also reused (ie the stream name starts with the `"&"` symbol, to avoid confusion with standard file names):: >&mystream:foo MODULE=yes >&mystream:bar You need of course to do a bit of coding in Ada to create the stream. This is done by creating a new child of `Trace_Stream_Record`, and override the primitive operation `Put`. The whole output message is given as a single parameter to `Put`:: type My_Stream is new Trace_Stream_Record with record File : access File_Type; end record; procedure Put (Stream : in out My_Stream; Str : Msg_Strings.XString) is S : Msg_Strings.Unconstrained_String_Access; L : Natural; begin Str.Get_String (S, L); Put (Stream.File.all, String (S (1 .. L))); end Put; The above code did not open the file itself, as you might have noticed, nor did it register the name `"mystream"` so that it can be used in the configuration file. All this is done by creating a factory, ie a function in charge of creating the new stream. A factory is also a tagged object (so that you can store custom information in it), with a single primitive operation, `New_Stream`, in charge of creating and initializing a new stream. This operation receives in parameter the argument specified by the user in the configuration file (after the `":"` character, if any), and must return a newly allocated stream. This function is also never called twice with the same argument, since `GNATCOLL.Traces` automatically reuses an existing stream when one with the same name and arguments already exists:: type My_Stream_Factory is new Stream_Factory with null record; overriding function New_Stream (Self : My_Stream_Factory; Args : String) return Trace_Stream is Str : access My_Stream := new My_Stream; begin Str.File := new File_Type; Open (Str.File, Out_File, Args); return Str; end Factory; Fact : access My_Stream_Factory := new My_Stream_Factory; Register_Stream_Factory ("mystream", Fact); .. _Logging_to_syslog: Logging to syslog ================= .. index:: syslog .. index:: gnat.traces.syslog Among the predefined streams, GNATColl gives access to the system logger `syslog`. This is a standard utility on all Unix systems, but is not available on other systems. When you compile GNATColl, you should specify the switch `--enable-syslog` to configure to activate the support. If either this switch wasn't specified, or configure could not find the relevant header files anyway, then support for `syslog` will not be available. In this case, the package `GNATCOLL.Traces.Syslog` is still available, but contains a single function that does nothing. If your configuration files redirect some trace handles to `"syslog"`, they will instead be redirect to the default stream or to standard output. Activating support for syslog requires the following call in your application:: GNATCOLL.Traces.Syslog.Register_Syslog_Stream; This procedure is always available, whether your system supports or not syslog, and will simply do nothing if it doesn't support syslog. This means that you do not need to have conditional code in your application to handle that, and you can let GNATColl take care of this. After the above call, trace handles can be redirected to a stream named `"syslog"`. The package `GNATCOLL.Traces.Syslog` also contains a low-level interface to syslog, which, although fully functional, you should probably not use, since that would make your code system-dependent. Syslog itself dispatches its output based on two criteria: the `facility`, which indicates what application emitted the message, and where it should be filed, and the `level` which indicates the urgency level of the message. Both of these criteria can be specified in the `GNATCOLL.Traces` configuration file, as follows:: MODULE=yes >&syslog:user:error The above configuration will redirect to a facility called `user`, with an urgency level `error`. See the enumeration types in :file:`gnatcoll-traces-syslog.ads` for more information on valid facilities and levels. .. _Dynamically_disabling_features: Dynamically disabling features ============================== Although the trace handles are primarily meant for outputting messages, they can be used in another context. The goal is to take advantage of the external configuration file, without reimplementing a similar feature in your application. Since the configuration file can be used to activated or de-activated a handle dynamically, you can then have conditional sections in your application that depends on that handle, as in the following example:: CONDITIONAL=yes and in the Ada code:: package Pkg is Me : constant Trace_Handle := Create ("CONDITIONAL"); begin if Active (Me) then ... conditional code end if; end Pkg; In particular, this can be used if you write your own decorators, as explained above. alire-1.2.1/deps/gnatcoll-slim/docs/tribooleans.rst000066400000000000000000000017551425465243200223310ustar00rootroot00000000000000.. _Three_state_logic: ********************************** **Tribooleans**: Three state logic ********************************** Through the package `GNATCOLL.Tribooleans`, GNATColl provides a type that extends the classical `Boolean` type with an `Indeterminate` value. There are various cases where such a type is useful. One example we have is when a user is doing a search (on a database or any set of data), and can specify some optional boolean criteria ("must the contact be french?"). He can choose to only see french people ("True"), to see no french people at all ("False"), or to get all contacts ("Indeterminate"). With a classical boolean, there is no way to cover all these cases. Of course, there are more advanced use cases for such a type. To support these cases, the `Tribooleans` package overrides the usual logical operations `"and"`, `"or"`, `"xor"`, `"not"` and provides an `Equal` function. See the specs of the package to see the truth tables associated with those operators. alire-1.2.1/deps/gnatcoll-slim/docs/vfs.rst000066400000000000000000000257071425465243200206110ustar00rootroot00000000000000*************************** **VFS**: Manipulating Files *************************** .. highlight:: ada Ada was meant from the beginning to be a very portable language, across architectures. As a result, most of the code you write on one machine has good chances of working as is on other machines. There remains, however, some areas that are somewhat system specific. The Ada run-time, the GNAT specific run-time and GNATColl all try to abstract some of those operations to help you make your code more portable. One of these areas is related to the way files are represented and manipulated. Reading or writing to a file is system independent, and taken care of by the standard run-time. Other differences between systems include the way file names are represented (can a given file be accessed through various casing or not, are directories separated with a backslash or a forward slash, or some other mean, and a few others). The GNAT run-time does a good job at providing subprograms that work on most types of filesystems, but the relevant subprograms are split between several packages and not always easy to locate. GNATColl groups all these functions into a single convenient tagged type hierarchy. In addition, it provides the framework for transparently manipulating files on other machines. Another difference is specific to the application code: sometimes, a subprogram needs to manipulate the base name (no directory information) of a file, whereas sometimes the full file name is needed. It is somewhat hard to document this in the API, and certainly fills the code with lots of conversion from full name to base name, and sometimes reverse (which, of course, might be an expansive computation). To make this easier, GNATColl provides a type that encapsulates the notion of a file, and removes the need for the application to indicate whether it needs a full name, a base name, or any other part of the file name. Filesystems abstraction ======================= There exists lots of different filesystems on all machines. These include such things as FAT, VFAT, NTFS, ext2, VMS,.... However, all these can be grouped into three families of filesystems: * windows-based filesystems On such filesystems, the full name of a file is split into three parts: the name of the drive (c:, d:,...), the directories which are separated by a backslash, and the base name. Such filesystems are sometimes inaccurately said to be case insensitive: by that, one means that the same file can be accessed through various casing. However, a user is generally expecting a specific casing when a file name is displayed, and the application should strive to preserve that casing (as opposed to, for instance, systematically convert the file name to lower cases). A special case of a windows-based filesystems is that emulated by the cygwin development environment. In this case, the filesystem is seen as if it was unix-based (see below), with one special quirk to indicate the drive letter (the file name starts with "/cygwin/c/"). * unix-based filesystems On such filesystems, directories are separated by forward slashed. File names are case sensitive, that is a directory can contain both "foo" and "Foo", which is not possible on windows-based filesystems. * vms filesystem This filesystem represents path differently than the other two, using brackets to indicate parent directories A given machine can actually have several file systems in parallel, when a remote disk is mounted through NFS or samba for instance. There is generally no easy way to guess that information automatically, and it generally does not matter since the system will convert from the native file system to that of the remote host transparently (for instance, if you mount a windows disk on a unix machine, you access its files through forward slash- separated directory names). GNATColl abstracts the differences between these filesystems through a set of tagged types in the `GNATCOLL.Filesystem` package and its children. Such a type has primitive operations to manipulate the names of files (retrieving the base name from a full name for instance), to check various attributes of the file (is this a directory, a symbolic link, is the file readable or writable), or to manipulate the file itself (copying, deleting, reading and writing). It provides similar operations for directories (creating or deleting paths, reading the list of files in a directory,...). It also provides information on the system itself (the list of available drives on a windows machine for instance). The root type `Filesystem_Record` is abstract, and is specialized in various child types. A convenient factory is provided to return the filesystem appropriate for the local machine (`Get_Local_Filesystem`), but you might chose to create your own factory in your application if you have specialized needs (:ref:`Remote_filesystems`). file names encoding ------------------- One delicate part when dealing with filesystems is handling files whose name cannot be described in ASCII. This includes names in asian languages for instance, or names with accented letters. There is unfortunately no way, in general, to know what the encoding is for a filesystem. In fact, there might not even be such an encoding (on linux, for instance, one can happily create a file with a chinese name and another one with a french name in the same directory). As a result, GNATColl always treats file names as a series of bytes, and does not try to assume any specific encoding for them. This works fine as long as you are interfacing the system (since the same series of bytes that was returned by it is also used to access the file later on). However, this becomes a problem when the time comes to display the name for the user (for instance in a graphical interface). At that point, you need to convert the file name to a specific encoding, generally UTF-8 but not necessarily (it could be ISO-8859-1 in some cases for instance). Since GNATColl cannot guess whether the file names have a specific encoding on the file system, or what encoding you might wish in the end, it lets you take care of the conversion. To do so, you can use either of the two subprograms `Locale_To_Display` and `Set_Locale_To_Display_Encoder` .. _Remote_filesystems: Remote filesystems ================== Once the abstract for filesystems exists, it is tempting to use it to access files on remote machines. There are of course lots of differences with filesystems on the local machine: their names are manipulated similarly (although you need to somehow indicate on which host they are to be found), but any operation of the file itself needs to be done on the remote host itself, as it can't be done through calls to the system's standard C library. Note that when we speak of disks on a remote machine, we indicate disks that are not accessible locally, for instance through NFS mounts or samba. In such cases, the files are accessed transparently as if they were local, and all this is taken care of by the system itself, no special layer is needed at the application level. GNATColl provides an extensive framework for manipulating such remote files. It knows what commands need to be run on the remote host to perform the operations ("cp" or "copy", "stat" or "dir /a-d",...) and will happily perform these operations when you try to manipulate such files. There are however two operations that your own application needs to take care of to take full advantage of remote files. Filesystem factory ------------------ GNATColl cannot know in advance what filesystem is running on the remote host, so it does not try to guess it. As a result, your application should have a factory that creates the proper instance of a `Filesystem_Record` depending on the host. Something like:: type Filesystem_Type is (Windows, Unix); function Filesystem_Factory (Typ : Filesystem_Type; Host : String) return Filesystem_Access is FS : Filesystem_Access; begin if Host = "" then case Typ is when Unix => FS := new Unix_Filesystem_Record; when Windows => FS := new Windows_Filesystem_Record; end case; else case Typ is when Unix => FS := new Remote_Unix_Filesystem_Record; Setup (Remote_Unix_Filesystem_Record (FS.all), Host => Host, Transport => ...); *-- see below* when Windows => FS := new Remote_Windows_Filesystem_Record; Setup (Remote_Windows_Filesystem_Record (FS.all), Host => Host, Transport => ...); end case; end if; Set_Locale_To_Display_Encoder (FS.all, Encode_To_UTF8'Access); return FS; end Filesystem_Factory; Transport layer --------------- There exists lots of protocols to communicate with a remote machine, so as to be able to perform operations on it. These include protocols such as `rsh`, `ssh` or `telnet`. In most of these cases, a user name and password is needed (and will likely be asked to the user). Furthermore, you might not want to use the same protocol to connect to different machines. GNATColl does not try to second guess your intention here. It performs all its remote operations through a tagged type defined in `GNATCOLL.Filesystem.Transport`. This type is abstract, and must be overridden in your application. For instance, GPS has a full support for choosing which protocol to use on which host, what kind of filesystem is running on that host, to recognize password queries from the transport protocol,.... All these can be encapsulated in the transport protocol. Once you have created one or more children of `Filesystem_Transport_Record`, you associate them with your instance of the filesystem through a call to the `Setup` primitive operation of the filesystem. See the factory example above. Virtual files ============= As we have seen, the filesystem type abstracts all the operations for manipulating files and their names. There is however another aspect when dealing with file names in an application: it is often unclear whether a full name (with directories) is expected, or whether the base name itself is sufficient. There are also some aspects about a file that can be cached to improve the efficiency. For these reasons, GNATColl provides a new type `GNATCOLL.VFS.Virtual_File` which abstracts the notion of file. It provides lots of primitive operations to manipulate such files (which are of course implemented based on the filesystem abstract, so support files on remote hosts among other advantages), and encapsulate the base name and the full name of a file so that your API becomes clearer (you are not expecting just any string, but really a file). This type is reference counted: it takes care of memory management on its own, and will free its internal data (file name and cached data) automatically when the file is no longer needed. This has of course a slight efficiency cost, due to controlled types, but we have found in the context of GPS that the added flexibility was well worth it. alire-1.2.1/deps/gnatcoll-slim/examples/000077500000000000000000000000001425465243200201345ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/examples/Makefile000066400000000000000000000011241425465243200215720ustar00rootroot00000000000000all: include ../Makefile.conf ADA_PROJECT_PATH:=${prefix}/lib/gnat${DIRSEP}${ADA_PROJECT_PATH}${DIRSEP}../src LD_LIBRARY_PATH:=${prefix}/lib:${LD_LIBRARY_PATH} export ADA_PROJECT_PATH export LD_LIBRARY_PATH all: gnatmake -p -Pexamples ifeq ($(WITH_GMP),yes) gprbuild -p -Pgmp/gmp_examples.gpr endif @echo "===================================================" @echo "== To run, set the environment variable LD_LIBRARY_PATH" @echo "== LD_LIBRARY_PATH=${prefix}/lib/gnat:\$$LD_LIBRARY_PATH" clean: -gprclean -q -Pexamples ifeq ($(WITH_GMP),yes) -gprclean -q -Pgmp/gmp_examples.gpr endif alire-1.2.1/deps/gnatcoll-slim/examples/common.adb000066400000000000000000000063051425465243200221000ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G P S -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Scripts; use GNATCOLL.Scripts; with GNATCOLL.Scripts.Python; use GNATCOLL.Scripts.Python; with GNATCOLL.Scripts.Shell; use GNATCOLL.Scripts.Shell; package body Common is procedure On_Hello (Data : in out Callback_Data'Class; Command : String); procedure On_Hello (Data : in out Callback_Data'Class; Command : String) is pragma Unreferenced (Command); begin Set_Return_Value (Data, "Hello " & Nth_Arg (Data, 1, "world") & " !"); end On_Hello; ------------------------------------ -- Register_Scripts_And_Functions -- ------------------------------------ function Register_Scripts_And_Functions return Scripts_Repository is Repo : Scripts_Repository; begin -- Register all scripting languages. In practice, you only need to -- register those you intend to support Repo := new Scripts_Repository_Record; Register_Shell_Scripting (Repo); Register_Python_Scripting (Repo, "Hello"); Register_Standard_Classes (Repo, "Console"); -- Now register our custom functions. Note that we do not need to -- register them once for every support language, once is enough, they -- are automatically exported to all registered languages. -- Available as "Hello.hello("world")" in python, -- and "hello world" in shell script Register_Command (Repo, "hello", 0, 1, Handler => On_Hello'Unrestricted_Access); return Repo; end Register_Scripts_And_Functions; end Common; alire-1.2.1/deps/gnatcoll-slim/examples/common.ads000066400000000000000000000037441425465243200221250ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G P S -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Shell registration for the examples with GNATCOLL.Scripts; package Common is function Register_Scripts_And_Functions return GNATCOLL.Scripts.Scripts_Repository; -- Register the various scripting languages and the functions we export -- to them end Common; alire-1.2.1/deps/gnatcoll-slim/examples/examples.gpr000066400000000000000000000004651425465243200224710ustar00rootroot00000000000000with "gnatcoll_python"; project Examples is for Object_Dir use "obj"; for Exec_Dir use "."; for Main use ("newclass.adb"); for Source_Files use ("common.ads", "common.adb", "textconsole.ads", "textconsole.adb", "newclass.adb"); end Examples; alire-1.2.1/deps/gnatcoll-slim/examples/library/000077500000000000000000000000001425465243200216005ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/examples/library/.gnatdebug000066400000000000000000000000161425465243200235360ustar00rootroot00000000000000+ SESSION=yes alire-1.2.1/deps/gnatcoll-slim/examples/library/README000066400000000000000000000001101425465243200224500ustar00rootroot00000000000000This is the library example declared in the GNATCOLL.SQL documentation. alire-1.2.1/deps/gnatcoll-slim/examples/library/build.sh000066400000000000000000000010731425465243200232340ustar00rootroot00000000000000cd obj # Create the database from the schema (remove the old one, just in case) rm -f library.db gnatcoll_db2ada -dbtype=sqlite -dbname=library.db -dbmodel=../dbschema.txt -createdb # Generate the Ada API gnatcoll_db2ada -api=Database -orm=ORM -dbmodel=../dbschema.txt cd .. # -m switch is so that gnatmake does not use timestamps but checksums # for dependencies (otherwise since we regenerate the files every time # we also recompile every time) gnatmake -q -g -m -Pdefault.gpr # Run the executable # ./obj/library # valgrind --leak-check=full ./obj/library alire-1.2.1/deps/gnatcoll-slim/examples/library/dbschema.txt000066400000000000000000000024511425465243200241110ustar00rootroot00000000000000# for Emacs: -*- mode: org; mode: flyspell; fill-column: 79 -*- | TABLE | customers | customer | | The customer for the library | | id | AUTOINCREMENT | PK | | Auto-generated id | | first | TEXT | NOT NULL | | Customers' first name | | last | TEXT | NOT NULL, INDEX | | Customers' last name | | ABSTRACT TABLE | media | media | | The contents of the library | | id | AUTOINCREMENT | PK | | Auto-generated id | | title | TEXT | | | The title of the media | | author | TEXT | | | The author | | published | DATE | | | Publication date | | TABLE (media) | books | book | | The books in the library | | pages | INTEGER | | 100 | | | borrowed_by | FK customers(borrowed_books) | NULL | | Who borrowed the media | | TABLE (media) | dvds | dvd | | The dvds in the library | | region | INTEGER | | 1 | | | borrowed_by | FK customers(borrowed_dvds) | NULL | | Who borrowed the media | alire-1.2.1/deps/gnatcoll-slim/examples/library/default.gpr000066400000000000000000000007241425465243200237410ustar00rootroot00000000000000with "gnatcoll"; with "gnatcoll_sqlite"; -- or "gnatcoll_postgres" project Default is for Source_Dirs use ("obj", -- automatically generated files "src"); -- example files for Object_Dir use "obj"; for Main use ("library.adb"); package Compiler is for Switches ("Ada") use ("-g"); end Compiler; package Binder is for Switches ("Ada") use ("-E"); -- Get backtrace for exceptions end Binder; end Default; alire-1.2.1/deps/gnatcoll-slim/examples/library/fixture.txt000066400000000000000000000014541425465243200240330ustar00rootroot00000000000000# for Emacs: -*- mode: org; mode: flyspell; fill-column: 79 -*- | TABLE | customers | | | id | first | last | |-------+-----------+--------| | 1 | John | Smith | | 2 | Alain | Dupont | | TABLE | books | | | | | title | author | pages | published | borrowed_by | |------------+---------+-------+------------+-------------| | Art of War | Sun Tzu | 90 | 01-01-2000 | 1 | | Ada RM | WRG | 250 | 01-07-2005 | | | TABLE | dvds | | | | title | author | region | borrowed_by(&last) | |--------------+----------+--------+--------------------| | The Birds | Hitchcok | 1 | &Smith | | The Dictator | Chaplin | 3 | &Dupont | alire-1.2.1/deps/gnatcoll-slim/examples/library/src/000077500000000000000000000000001425465243200223675ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/examples/library/src/library.adb000066400000000000000000000141431425465243200245060ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2011-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.SQL; use GNATCOLL.SQL; with GNATCOLL.SQL.Exec; use GNATCOLL.SQL.Exec; with GNATCOLL.SQL.Sqlite; with GNATCOLL.SQL.Inspect; use GNATCOLL.SQL.Inspect; with GNATCOLL.SQL.Sessions; use GNATCOLL.SQL.Sessions; with GNATCOLL.VFS; use GNATCOLL.VFS; with Database; use Database; with ORM; use ORM; with Ada.Text_IO; use Ada.Text_IO; with GNATCOLL.Traces; use GNATCOLL.Traces; procedure Library is Descr : Database_Description := GNATCOLL.SQL.Sqlite.Setup ("obj/library.db"); DB : Database_Connection; Q : SQL_Query; R : Forward_Cursor; Stmt : Prepared_Statement; begin GNATCOLL.Traces.Parse_Config_File (".gnatdebug"); -- show traces DB := Descr.Build_Connection; -- Load the fixture file -- Since we are using "&" references, we need to load the schema too Load_Data (DB, Create ("fixture.txt"), Schema => New_Schema_IO (Create ("dbschema.txt")).Read_Schema); DB.Commit; --------------------------------------------------- -- Part 1: using GNATCOLL.SQL -- In this part, we are still manipulating SQL queries ourselves --------------------------------------------------- -- Get all the books borrowed by the customer "Smith" Q := SQL_Select (Fields => Books.Title & Books.Pages, From => Books & Customers, Where => Books.FK (Customers) and Customers.Last = "Smith"); R.Fetch (DB, Q); while R.Has_Row loop Put_Line ("Borrowed by smith: " & R.Value (0) & " pages=" & R.Integer_Value (1)'Img); R.Next; end loop; -- Same as above, using a prepared query. If we had lots of similar -- queries to do, this would be much more efficient. The preparation -- could also be done in a global variable at elaboration time. Q := SQL_Select (Fields => Books.Title & Books.Pages, From => Books & Customers, Where => Books.FK (Customers) and Customers.Last = Text_Param (1)); Stmt := Prepare (Q, On_Server => True, Name => "books_borrowed_by"); declare Smith : aliased String := "Smith"; begin R.Fetch (DB, Stmt, Params => (1 => +Smith'Access)); while R.Has_Row loop Put_Line ("Borrowed by smith: " & R.Value (0) & " pages=" & R.Integer_Value (1)'Img); R.Next; end loop; end; -- Free memory for part 1 R := No_Element; Free (DB); Free (Descr); --------------------------------------------------- -- Part 2: using GNATCOLL.SQL.ORM -- The following code does the same queries as above, but using the -- ORM. --------------------------------------------------- GNATCOLL.SQL.Sessions.Setup (Descr => GNATCOLL.SQL.Sqlite.Setup ("obj/library.db"), Max_Sessions => 2); declare Session : constant Session_Type := Get_New_Session; B : Book_List; CL : Customer_List; C : ORM.Detached_Customer'Class := Get_Customer (Session, Id => 1); begin Put_Line ("Customer id 1 is " & C.Last); -- SQL-like query B := All_Books.Filter (Books.FK (Customers) and Customers.Last = "Smith") .Select_Related (1, Follow_Left_Join => True) .Get (Session); while B.Has_Row loop Put_Line ("Borrowed by " & B.Element.Borrowed_By.Last & " title=" & B.Element.Title & " pages=" & B.Element.Pages'Img); B.Next; end loop; -- Using the more powerful ORM B := C.Borrowed_Books.Get (Session); while B.Has_Row loop Put_Line ("Borrowed by smith: " & B.Element.Title); B.Next; end loop; -- Change a customer, but do not commit to the database yet. So -- the change only exists in memory C.Set_Last ("Smit"); C.Set_First ("Andrew"); -- Retrieve the list of all customers, and make sure the modified -- one is indeed seen with the new values, even though the DBMS -- doesn't know about the changes. CL := All_Customers.Get (Session); while CL.Has_Row loop Put_Line ("Customer: " & CL.Element.First & " " & CL.Element.Last); CL.Next; end loop; Session.Commit; end; GNATCOLL.SQL.Sessions.Free; --------------------------------------------------- -- Free memory --------------------------------------------------- GNATCOLL.Traces.Finalize; end Library; alire-1.2.1/deps/gnatcoll-slim/examples/newclass.adb000066400000000000000000000050651425465243200224310ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G P S -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Text_IO; use Ada.Text_IO; with Common; use Common; with GNATCOLL.Scripts; use GNATCOLL.Scripts; with TextConsole; use TextConsole; procedure NewClass is Repo : Scripts_Repository := Common.Register_Scripts_And_Functions; Buffer : String (1 .. 1000); Last : Integer; Errors : Boolean; Console : aliased Text_Console; begin Put_Line ("Please type python commands:"); Set_Default_Console (Lookup_Scripting_Language (Repo, "python"), Console'Unchecked_Access); loop Get_Line (Buffer, Last); Execute_Command (Script => Lookup_Scripting_Language (Repo, "python"), Command => Buffer (1 .. Last), Show_Command => False, Hide_Output => False, Errors => Errors); end loop; exception when End_Error => Destroy (Repo); end NewClass; alire-1.2.1/deps/gnatcoll-slim/examples/textconsole.adb000066400000000000000000000053071425465243200231600ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G P S -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.IO; use GNAT.IO; with GNATCOLL.Scripts; use GNATCOLL.Scripts; package body TextConsole is procedure Set_Data_Primitive (Instance : Class_Instance; Console : access Text_Console) is begin Set (Console.Instances, Instance); end Set_Data_Primitive; function Get_Instance (Script : access Scripting_Language_Record'Class; Console : access Text_Console) return Class_Instance is begin return Get (Console.Instances, Script); end Get_Instance; procedure Insert_Text (Console : access Text_Console; Txt : String) is pragma Unreferenced (Console); begin Put (Txt); end Insert_Text; procedure Insert_Prompt (Console : access Text_Console; Txt : String) is pragma Unreferenced (Console); begin Put (Txt); end Insert_Prompt; procedure Insert_Error (Console : access Text_Console; Txt : String) is pragma Unreferenced (Console); begin Put (Standard_Error, Txt); end Insert_Error; end TextConsole; alire-1.2.1/deps/gnatcoll-slim/examples/textconsole.ads000066400000000000000000000051071425465243200231770ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G P S -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Scripts; package TextConsole is type Text_Console is new GNATCOLL.Scripts.Virtual_Console_Record with private; overriding procedure Insert_Text (Console : access Text_Console; Txt : String); overriding procedure Insert_Prompt (Console : access Text_Console; Txt : String); overriding procedure Insert_Error (Console : access Text_Console; Txt : String); overriding procedure Set_Data_Primitive (Instance : GNATCOLL.Scripts.Class_Instance; Console : access Text_Console); overriding function Get_Instance (Script : access GNATCOLL.Scripts.Scripting_Language_Record'Class; Console : access Text_Console) return GNATCOLL.Scripts.Class_Instance; private type Text_Console is new GNATCOLL.Scripts.Virtual_Console_Record with record Instances : GNATCOLL.Scripts.Instance_List; end record; end TextConsole; alire-1.2.1/deps/gnatcoll-slim/gnat_debug.adc000066400000000000000000000000331425465243200210620ustar00rootroot00000000000000pragma Initialize_Scalars; alire-1.2.1/deps/gnatcoll-slim/gnatcoll.gpr000066400000000000000000000151461425465243200206420ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2015-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ project GnatColl is Version := External ("GNATCOLL_VERSION", "0.0"); Name := "gnatcoll"; type Yes_No is ("yes", "no"); Mmap : Yes_No := External ("GNATCOLL_MMAP", "yes"); Madvise : Yes_No := External ("GNATCOLL_MADVISE", "yes"); type Atomics_Kind is ("intrinsic", "mutex"); Atomics : Atomics_Kind := External ("GNATCOLL_ATOMICS", "intrinsic"); type Build_Type is ("DEBUG", "PROD"); Build : Build_Type := External ("BUILD"); type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := External ("LIBRARY_TYPE"); for Source_Dirs use ("src", "src/paragraph_filling"); for Library_Kind use Library_Type; for Object_Dir use "obj/gnatcoll/" & Project'Library_Kind; for Library_Dir use "lib/gnatcoll/" & Project'Library_Kind; for Library_Name use Name; for Languages use ("Ada", "C"); type OS_Kind is ("windows", "unix", "osx"); OS : OS_Kind := External ("GNATCOLL_OS", "unix"); Extra_Switches := (); Extra_Libs := (); case OS is when "windows" => Extra_Libs := ("-lpsapi"); -- For gnatcoll.memory when others => case Mmap is when "yes" => Extra_Switches := ("-DHAVE_MMAP"); case Madvise is when "yes" => Extra_Switches := Extra_Switches & ("-DHAVE_MADVISE"); when "no" => null; end case; when others => null; end case; end case; So_Ext := ""; case OS is when "windows" => So_Ext := ".dll"; when "osx" => So_Ext := ".dylib"; when others => So_Ext := ".so"; end case; for Library_Version use "lib" & Name & So_Ext & "." & Version; case Atomics is when "intrinsic" => Extra_Switches := Extra_Switches & ("-DATOMIC_INTRINSICS"); when "mutex" => null; end case; case Library_Type is when "relocatable" => for Library_Options use Extra_Libs; when others => null; end case; package Compiler is case Build is when "DEBUG" => for Switches ("Ada") use ("-g", "-O0", "-gnata", "-gnatVa", "-gnatQ", "-gnaty", "-gnateE", "-gnatwaCJe", "-fstack-check"); for Switches ("C") use ("-g", "-Wunreachable-code"); when "PROD" => -- Do not use -gnatwe for production mode for Switches ("Ada") use ("-O2", "-gnatn", "-gnatwaCJ"); for Switches ("C") use ("-O2", "-Wunreachable-code"); end case; for Switches ("gnatcoll_support.c") use Compiler'Switches ("C") & Extra_Switches; end Compiler; package Binder is case Build is when "DEBUG" => for Switches ("Ada") use ("-E"); when "PROD" => null; end case; end Binder; package Builder is case Build is when "DEBUG" => for Global_Configuration_Pragmas use "gnat_debug.adc"; when "PROD" => null; end case; end Builder; package Ide is for VCS_Kind use "Git"; end Ide; package Naming is for Specification ("GNATCOLL.OS.Constants") use "gnatcoll-os-constants__" & OS & ".ads"; case OS is when "unix" | "osx" => for Specification ("GNATCOLL.Mmap.System") use "gnatcoll-mmap-system__unix.ads"; for Implementation ("GNATCOLL.Mmap.System") use "gnatcoll-mmap-system__unix.adb"; for Implementation ("GNATCOLL.IO.Native.Codec") use "gnatcoll-io-native-codec__unix.adb"; for Implementation ("GNATCOLL.Plugins") use "gnatcoll-plugins__unix.adb"; when "windows" => for Specification ("GNATCOLL.Mmap.System") use "gnatcoll-mmap-system__win32.ads"; for Implementation ("GNATCOLL.Mmap.System") use "gnatcoll-mmap-system__win32.adb"; for Implementation ("GNATCOLL.IO.Native.Codec") use "gnatcoll-io-native-codec__win32.adb"; for Implementation ("GNATCOLL.Plugins") use "gnatcoll-plugins__windows.adb"; end case; case Atomics is when "intrinsic" => for Implementation ("GNATCOLL.Atomic") use "gnatcoll-atomic__intrinsic.ada"; when "mutex" => for Implementation ("GNATCOLL.Atomic") use "gnatcoll-atomic__mutex.ada"; end case; end Naming; package Linker is for Linker_Options use Extra_Libs; end Linker; package Install is for Artifacts ("share/examples/gnatcoll") use ("examples/*"); for Artifacts ("share/doc/gnatcoll/html") use ("docs/_build/html"); for Artifacts ("share/doc/gnatcoll") use ("docs/_build/latex/GNATColl.pdf"); end Install; end GnatColl; alire-1.2.1/deps/gnatcoll-slim/src/000077500000000000000000000000001425465243200171055ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/src/getRSS.c000066400000000000000000000072631425465243200204300ustar00rootroot00000000000000/* * Author: David Robert Nadeau * Site: http://NadeauSoftware.com/ * License: Creative Commons Attribution 3.0 Unported License * http://creativecommons.org/licenses/by/3.0/deed.en_US */ #if defined(_WIN32) #include #include #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) #include #include #if defined(__APPLE__) && defined(__MACH__) #include #elif (defined(_AIX) || defined(__TOS__AIX__)) #include #include #elif (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) #include #include #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) #include #endif #else #error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS." #endif /** * Returns the peak (maximum so far) resident set size (physical * memory use) measured in bytes, or zero if the value cannot be * determined on this OS. */ size_t gnatcoll_getPeakRSS( ) { #if defined(_WIN32) /* Windows -------------------------------------------------- */ PROCESS_MEMORY_COUNTERS info; GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); return (size_t)info.PeakWorkingSetSize; #elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) /* AIX and Solaris ------------------------------------------ */ struct psinfo psinfo; int fd = -1; if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 ) return (size_t)0L; /* Can't open? */ if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) ) { close( fd ); return (size_t)0L; /* Can't read? */ } close( fd ); return (size_t)(psinfo.pr_rssize * 1024L); #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) /* BSD, Linux, and OSX -------------------------------------- */ struct rusage rusage; getrusage( RUSAGE_SELF, &rusage ); #if defined(__APPLE__) && defined(__MACH__) return (size_t)rusage.ru_maxrss; #else return (size_t)(rusage.ru_maxrss * 1024L); #endif #else /* Unknown OS ----------------------------------------------- */ return (size_t)0L; /* Unsupported. */ #endif } /** * Returns the current resident set size (physical memory use) measured * in bytes, or zero if the value cannot be determined on this OS. */ size_t gnatcoll_getCurrentRSS( ) { #if defined(_WIN32) /* Windows -------------------------------------------------- */ PROCESS_MEMORY_COUNTERS info; GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); return (size_t)info.WorkingSetSize; #elif defined(__APPLE__) && defined(__MACH__) /* OSX ------------------------------------------------------ */ struct mach_task_basic_info info; mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount ) != KERN_SUCCESS ) return (size_t)0L; /* Can't access? */ return (size_t)info.resident_size; #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) /* Linux ---------------------------------------------------- */ long rss = 0L; FILE* fp = NULL; if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL ) return (size_t)0L; /* Can't open? */ if ( fscanf( fp, "%*s%ld", &rss ) != 1 ) { fclose( fp ); return (size_t)0L; /* Can't read? */ } fclose( fp ); return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE); #else /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ return (size_t)0L; /* Unsupported. */ #endif } alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-any_types.adb000066400000000000000000000045461425465243200234020ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Any_Types is ---------- -- Free -- ---------- procedure Free (X : in out Any_Type) is begin case X.T is when Integer_Type | String_Type | No_Type => -- Nothing to free for these types null; when List_Type => for J in X.List'Range loop Free (X.List (J).all); Unchecked_Free (X.List (J)); end loop; when Tuple_Type => for J in X.Tuple'Range loop Free (X.Tuple (J).all); Unchecked_Free (X.Tuple (J)); end loop; end case; end Free; end GNATCOLL.Any_Types; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-any_types.ads000066400000000000000000000062261425465243200234200ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides a few utilities to manipulate types that can have -- multiple forms. In particular this is used to provide a convenient way -- of manipulating Python objects, without having the need to manipulate -- PyObject in the Ada code. -- See GNATCOLL.Any_Types.Python. with Ada.Unchecked_Deallocation; with Interfaces.C; package GNATCOLL.Any_Types is -------------- -- Any_Type -- -------------- -- This type provides an Ada encapsulation of certain types type Types is (No_Type, Integer_Type, String_Type, Tuple_Type, List_Type); type Any_Type; type Any_Type_Access is access Any_Type; type Any_Type_Array is array (Natural range <>) of Any_Type_Access; type Any_Type (T : Types; Length : Natural) is record case T is when No_Type => null; when Integer_Type => Int : Interfaces.C.long; when String_Type => Str : String (1 .. Length); when Tuple_Type => Tuple : Any_Type_Array (1 .. Length); when List_Type => List : Any_Type_Array (1 .. Length); end case; end record; procedure Free (X : in out Any_Type); -- Free memory associated to X Empty_Any_Type : constant Any_Type := (No_Type, 0); private procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Any_Type, Any_Type_Access); end GNATCOLL.Any_Types; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-arg_lists.adb000066400000000000000000000422461425465243200233550ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.OS_Lib; use GNAT.OS_Lib; with Ada.Unchecked_Deallocation; with Ada.Containers; use Ada.Containers; with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Strings.Fixed; use Ada.Strings.Fixed; with Ada.Strings.Maps; use Ada.Strings.Maps; with GNATCOLL.Scripts.Utils; use GNATCOLL.Scripts.Utils; package body GNATCOLL.Arg_Lists is procedure Parse_Command_Line_String (CL : in out Arg_List; Text : String); -- Factor code between variants of Parse_String. -- This processes Text as if it were passed on a command line (for instance -- the bash command line) and adds the arguments to CL. function Escape_Backslashes (A : Unbounded_String) return Unbounded_String; -- Escape backslashes in A ------------------------ -- Escape_Backslashes -- ------------------------ function Escape_Backslashes (A : Unbounded_String) return Unbounded_String is S : constant String := To_String (A); R : Unbounded_String; begin for J in S'Range loop case S (J) is when '\' => Append (R, "\\"); when others => Append (R, S (J)); end case; end loop; return R; end Escape_Backslashes; ------------------------------- -- Parse_Command_Line_String -- ------------------------------- procedure Parse_Command_Line_String (CL : in out Arg_List; Text : String) is function Process (A : String) return Argument_Type; -- Post-process on each argument returned by Argument_String_To_List ------------- -- Process -- ------------- function Process (A : String) return Argument_Type is begin if A = "" then return (One_Arg, Null_Unbounded_String); end if; -- Argument_String_To_List does not remove single quotes around an -- argument: do this now. if A (A'First) = '"' and then A (A'Last) = '"' then return (One_Arg, To_Unbounded_String (A (A'First + 1 .. A'Last - 1))); end if; return (Expandable, To_Unbounded_String (A)); end Process; Local_Args : Argument_List_Access; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Argument_List, Argument_List_Access); begin -- If we are parsing an argument in Separate_Args mode, get rid of the -- leading spaces, as this would result in multiple arguments in -- the call to Argument_String_To_List_With_Triple_Quotes -- Also remove trailing spaces, since otherwise the last argument on -- the command line, when surrounded with quotes, will be seen by -- Process as ending with ASCII.LF, and therefore the quotes will not be -- removed. if CL.Mode = Separate_Args then Local_Args := Argument_String_To_List_With_Triple_Quotes (Trim (Text, Left => To_Set (' ' & ASCII.LF & ASCII.HT), Right => To_Set (' ' & ASCII.LF & ASCII.HT))); else Local_Args := Argument_String_To_List_With_Triple_Quotes (Text); end if; if Local_Args = null then return; end if; for J in Local_Args'Range loop CL.V.Append (Process (Local_Args (J).all)); Free (Local_Args (J)); end loop; Unchecked_Free (Local_Args); end Parse_Command_Line_String; ------------------ -- Parse_String -- ------------------ function Parse_String (Text : String; Mode : Command_Line_Mode) return Arg_List is CL : Arg_List; begin CL.Mode := Mode; if Mode = Separate_Args then Parse_Command_Line_String (CL, Text); else CL.V.Append ((One_Arg, To_Unbounded_String (Text))); end if; return CL; end Parse_String; ------------------ -- Parse_String -- ------------------ function Parse_String (Command : String; Text : String) return Arg_List is CL : Arg_List := Create (Command); begin Parse_Command_Line_String (CL, Text); return CL; end Parse_String; ----------------- -- Get_Command -- ----------------- function Get_Command (C : Arg_List) return String is begin if C.V.Is_Empty then return ""; else return To_String (C.V.Element (0).Text); end if; end Get_Command; ------------ -- Create -- ------------ function Create (Command : String) return Arg_List is C : Arg_List; begin C.V.Append ((One_Arg, To_Unbounded_String (Command))); return C; end Create; --------------------- -- Append_Argument -- --------------------- procedure Append_Argument (C : in out Arg_List; Argument : String; Mode : Argument_Mode) is begin C.V.Append ((Mode, To_Unbounded_String (Argument))); end Append_Argument; ------------- -- To_List -- ------------- function To_List (C : Arg_List; Include_Command : Boolean) return GNAT.OS_Lib.Argument_List is First : Natural; begin if Include_Command then First := 0; else First := 1; end if; declare L : GNAT.OS_Lib.Argument_List (1 .. Natural (C.V.Length) - First); begin for J in First .. Natural (C.V.Length) - 1 loop L (J + 1 - First) := new String' (To_String (C.V.Element (J).Text)); end loop; return L; end; end To_List; ----------------------- -- To_Display_String -- ----------------------- function To_Display_String (C : Arg_List; Include_Command : Boolean := True; Max_Arg_Length : Positive := Positive'Last) return String is Result : Unbounded_String := To_Unbounded_String (""); Start : Natural := 1; begin if not Include_Command then Start := 2; end if; for Index in Start .. Natural (C.V.Length) loop declare Arg_Len : constant Natural := Length (C.V.Element (Index - 1).Text); begin if Arg_Len > Max_Arg_Length then Append (Result, Unbounded_Slice (C.V.Element (Index - 1).Text, 1, Max_Arg_Length - 1)); Append (Result, "..."); else Append (Result, C.V.Element (Index - 1).Text); end if; end; if Index < Natural (C.V.Length) then Append (Result, " "); end if; end loop; return To_String (Result); end To_Display_String; --------------------- -- To_Debug_String -- --------------------- function To_Debug_String (C : Arg_List) return String is Result : Unbounded_String := To_Unbounded_String ("Command: "); begin Append (Result, C.V.Element (0).Text); for J in 1 .. Natural (C.V.Length) - 1 loop Append (Result, ASCII.LF & "Arg: " & C.V.Element (J).Text); end loop; return To_String (Result); end To_Debug_String; ---------------------- -- To_Script_String -- ---------------------- function To_Script_String (C : Arg_List) return String is function Arg (A : Unbounded_String) return Unbounded_String; -- Auxiliary function to process one arg --------- -- Arg -- --------- function Arg (A : Unbounded_String) return Unbounded_String is S : constant String := To_String (A); R : Unbounded_String; begin for J in S'Range loop case S (J) is when '\' => Append (R, "\\"); when ' ' => Append (R, "\ "); when '"' => Append (R, "\"""); when others => Append (R, S (J)); end case; end loop; return R; end Arg; Result : Unbounded_String; begin if C = Empty_Command_Line then return ""; end if; if C.Mode = Raw_String then return To_String (C.V.Element (0).Text); end if; -- Convert all arguments for J in 1 .. Natural (C.V.Length) loop Append (Result, Arg (C.V.Element (J - 1).Text)); Append (Result, ' '); end loop; -- Return result without the trailing space declare R : constant String := To_String (Result); begin return R (R'First .. R'Last - 1); end; end To_Script_String; ---------------- -- Substitute -- ---------------- procedure Substitute (CL : in out Arg_List; Char : Character; Callback : Substitution_Function) is New_CL : Arg_List; function Expand_In_String (A : Unbounded_String) return Unbounded_String; -- Expand the argument in place in S and return the result ---------------------- -- Expand_In_String -- ---------------------- function Expand_In_String (A : Unbounded_String) return Unbounded_String is S : constant String := To_String (A); U : Unbounded_String; J : Natural; Beg : Natural; New_CL : Arg_List; Skip_Ending_Bracket : Boolean := False; begin if S = "" then return Null_Unbounded_String; end if; J := S'First; while J <= S'Last loop if S (J) = Char then -- Skip to the next separator J := J + 1; Beg := J; if S (J) = '{' then -- An '{' immediately follows the special character: -- the parameter should be the whole string contained -- between this and the ending '}'. Skip_Ending_Bracket := True; J := J + 1; Beg := J; while J <= S'Last and then S (J) /= '}' loop J := J + 1; end loop; else Skip_Ending_Bracket := False; while J <= S'Last and then (Is_Alphanumeric (S (J)) or else S (J) = '*' or else S (J) = '-' or else S (J) = '@') loop J := J + 1; end loop; end if; -- A doubling of the special character indicates that we -- are inserting it. if S (J - 1) = Char then Append (U, Char); J := J + 1; else New_CL := Callback (S (Beg .. J - 1), Raw_String); for K in 0 .. Natural (New_CL.V.Length) - 1 loop if CL.Mode = Raw_String then Append (U, Escape_Backslashes (New_CL.V.Element (K).Text)); else Append (U, New_CL.V.Element (K).Text); end if; if K < Natural (New_CL.V.Length) - 1 then Append (U, ' '); end if; end loop; end if; if Skip_Ending_Bracket then J := J + 1; end if; else Append (U, S (J)); J := J + 1; end if; end loop; return U; end Expand_In_String; begin New_CL.Mode := CL.Mode; if CL = Empty_Command_Line then return; end if; if Callback = null then return; end if; case CL.Mode is when Raw_String => declare U : constant Unbounded_String := Expand_In_String (CL.V.Element (0).Text); begin CL.V.Replace_Element (0, (One_Arg, U)); end; when Separate_Args => for J in 0 .. Natural (CL.V.Length) - 1 loop case CL.V.Element (J).Mode is when One_Arg => declare U : constant Unbounded_String := Expand_In_String (CL.V.Element (J).Text); begin New_CL.V.Append ((One_Arg, U)); end; when Expandable => declare P : constant Unbounded_String := CL.V.Element (J).Text; begin if Element (P, 1) = Char then New_CL.V.Append (Callback (Slice (P, 2, Length (P)), Separate_Args).V); else New_CL.V.Append ((Expandable, Expand_In_String (P))); end if; end; end case; end loop; CL := New_CL; end case; end Substitute; ----------------- -- Args_Length -- ----------------- function Args_Length (C : Arg_List) return Integer is begin return Natural (C.V.Length) - 1; end Args_Length; ------------- -- Nth_Arg -- ------------- function Nth_Arg (C : Arg_List; N : Natural) return String is begin return To_String (C.V.Element (N).Text); end Nth_Arg; function Nth_Arg (C : Arg_List; N : Natural) return Unbounded_String is begin return C.V.Element (N).Text; end Nth_Arg; ----------------- -- Set_Nth_Arg -- ----------------- procedure Set_Nth_Arg (C : in out Arg_List; N : Natural; Arg : String) is begin -- If there are not enough arguments, create them while N > Args_Length (C) loop C.V.Append ((One_Arg, Null_Unbounded_String)); end loop; C.V.Replace_Element (N, (C.V.Element (N).Mode, To_Unbounded_String (Arg))); end Set_Nth_Arg; ----------------------------- -- Argument_List_To_String -- ----------------------------- function Argument_List_To_String (List : GNAT.Strings.String_List; Protect_Quotes : Boolean := True) return String is Length : Natural := 0; begin for L in List'Range loop Length := Length + List (L)'Length + 1; if Protect_Quotes then for S in List (L)'Range loop if List (L)(S) = '"' or else List (L)(S) = ' ' or else List (L) (S) = '\' or else List (L) (S) = ''' then Length := Length + 1; end if; end loop; end if; end loop; declare S : String (1 .. Length); Index : Positive := S'First; begin for L in List'Range loop for J in List (L)'Range loop if Protect_Quotes then if List (L) (J) = '"' or else List (L) (J) = ' ' or else List (L) (J) = '\' or else List (L) (J) = ''' then S (Index) := '\'; Index := Index + 1; end if; end if; S (Index) := List (L)(J); Index := Index + 1; end loop; S (Index) := ' '; Index := Index + 1; end loop; return S (1 .. S'Last - 1); -- Ignore last space end; end Argument_List_To_String; end GNATCOLL.Arg_Lists; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-arg_lists.ads000066400000000000000000000157071425465243200234000ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides a type useful to manipulate command lines with GNAT.OS_Lib; with GNAT.Strings; with Ada.Containers.Vectors; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package GNATCOLL.Arg_Lists is type Command_Line_Mode is (Raw_String, Separate_Args); -- There are two ways to treat a command line in GNATCOLL. -- Raw_String: these command lines should never be parsed for arguments -- and processing should be minimal. -- Separate_Args: these command lines need argument handling. type Argument_Mode is (Expandable, One_Arg); -- This type controls the behavior of arguments with respect to expansion. -- Expandable means that this argument can be expanded into multiple -- arguments. -- One_Arg means that this argument will only remain one argument, -- even if it gets expanded to separate space-separated strings. type Arg_List is private; -- A command line. -- This contains one command (an executable, typically) and a list of -- arguments. Empty_Command_Line : constant Arg_List; function Get_Command (C : Arg_List) return String; -- Return the command contained in C function Create (Command : String) return Arg_List; -- Create a command line from command. -- This creates a command line which has Command as a command and -- no arguments. function Argument_List_To_String (List : GNAT.Strings.String_List; Protect_Quotes : Boolean := True) return String; -- Concatenate all the elements in List into a single string. -- Argument_String_To_List (Argument_List_To_String (X)) = X -- The returned string ends with a space. -- If Protect_Quotes is True, then all quotes (single and double) are -- preceded by a backslash. function Parse_String (Text : String; Mode : Command_Line_Mode) return Arg_List; -- Parse Text and return a Arg_List, assuming that Text contains both -- the command and the arguments function Parse_String (Command : String; Text : String) return Arg_List; -- Return a command line, assuming Command contains the command and -- Text contains the arguments procedure Append_Argument (C : in out Arg_List; Argument : String; Mode : Argument_Mode); -- Append Argument to the list of arguments in C function Args_Length (C : Arg_List) return Integer; -- Return the length of the arguments. The command is not included in this -- count. -- Return 0 if there is only a command and no arguments. -- Return -1 if the command is empty. function Nth_Arg (C : Arg_List; N : Natural) return String; -- Return the Nth argument. Nth_Arg (0) returns the command function Nth_Arg (C : Arg_List; N : Natural) return Unbounded_String; -- Return the Nth argument. Nth_Arg (0) returns the command procedure Set_Nth_Arg (C : in out Arg_List; N : Natural; Arg : String); -- Set the Nth arg. -- If there are not enough args, create them. ------------------ -- Substitution -- ------------------ type Substitution_Function is access function (Param : String; Mode : Command_Line_Mode) return Arg_List; procedure Substitute (CL : in out Arg_List; Char : Character; Callback : Substitution_Function); -- Substitute all parameters that start with Char using the mechanisms -- specified in Callback. function To_List (C : Arg_List; Include_Command : Boolean) return GNAT.OS_Lib.Argument_List; -- Return as an Argument_List: -- - the whole command line if Include_Command is True -- - only the arguments if Include_Command is False -- Caller must free the result. --------------------------- -- Conversions to string -- --------------------------- function To_Display_String (C : Arg_List; Include_Command : Boolean := True; Max_Arg_Length : Positive := Positive'Last) return String; -- Return a string that represents C, for display purposes. -- For instance -- cmd /c make LIBRARY_TYPE=static -- If Include_Command is False, display only the arguments. -- Max_Arg_Length is the maximum length returned for each argument in C. function To_Debug_String (C : Arg_List) return String; -- Return a string that represents C, for display purposes. -- For instance: -- command: "cmd" -- arg: "/c" -- arg: "make LIBRARY_TYPE=static" function To_Script_String (C : Arg_List) return String; -- Return a string that represents C, ready to be sent to a script -- For instance: -- cmd /c make\ LIBRARY_TYPE=static private type Argument_Type is record Mode : Argument_Mode; Text : Unbounded_String; end record; package Arg_List_Vector is new Ada.Containers.Vectors (Natural, Argument_Type); type Arg_List is record Mode : Command_Line_Mode := Separate_Args; V : Arg_List_Vector.Vector; -- The element number 0 is the command, and the following elements are -- arguments. end record; Empty_Command_Line : constant Arg_List := (Mode => Separate_Args, V => Arg_List_Vector.Empty_Vector); end GNATCOLL.Arg_Lists; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-asserts.adb000066400000000000000000000211151425465243200230420ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Assertions; package body GNATCOLL.Asserts is ------------------------- -- On_Assertion_Failed -- ------------------------- overriding procedure On_Assertion_Failed (Self : Exception_Reporter; Msg : String; Details : String; Location : String; Entity : String) is pragma Unreferenced (Self); begin raise Ada.Assertions.Assertion_Error with Msg & " " & Details & " at " & Location & " in " & Entity; end On_Assertion_Failed; ------------- -- Asserts -- ------------- package body Asserts is ------------------- -- Assert_Failed -- ------------------- procedure Assert_Failed (Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin Report.On_Assertion_Failed (Msg => Msg, Details => "", Location => Location, Entity => Entity); end Assert_Failed; ------------ -- Equals -- ------------ package body Equals is ------------------ -- Assert_Equal -- ------------------ procedure Assert_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Enabled and then not "=" (Left, Right) then Report.On_Assertion_Failed (Details => Image (Left) & " = " & Image (Right), Msg => Msg, Location => Location, Entity => Entity); end if; end Assert_Equal; ---------------------- -- Assert_Not_Equal -- ---------------------- procedure Assert_Not_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Enabled and then "=" (Left, Right) then Report.On_Assertion_Failed (Details => Image (Left) & " /= " & Image (Right), Msg => Msg, Location => Location, Entity => Entity); end if; end Assert_Not_Equal; end Equals; ------------- -- Compare -- ------------- package body Compare is ------------------ -- Assert_Equal -- ------------------ procedure Assert_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Enabled and then not "=" (Left, Right) then Report.On_Assertion_Failed (Details => Image (Left) & " = " & Image (Right), Msg => Msg, Location => Location, Entity => Entity); end if; end Assert_Equal; ---------------------- -- Assert_Not_Equal -- ---------------------- procedure Assert_Not_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Enabled and then "=" (Left, Right) then Report.On_Assertion_Failed (Details => Image (Left) & " /= " & Image (Right), Msg => Msg, Location => Location, Entity => Entity); end if; end Assert_Not_Equal; ----------------- -- Assert_Less -- ----------------- procedure Assert_Less (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Enabled and then not "<" (Left, Right) then Report.On_Assertion_Failed (Details => Image (Left) & " < " & Image (Right), Msg => Msg, Location => Location, Entity => Entity); end if; end Assert_Less; -------------------------- -- Assert_Less_Or_Equal -- -------------------------- procedure Assert_Less_Or_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Enabled and then not ("<" (Left, Right) or else "=" (Left, Right)) then Report.On_Assertion_Failed (Details => Image (Left) & " = " & Image (Right), Msg => Msg, Location => Location, Entity => Entity); end if; end Assert_Less_Or_Equal; ----------------------------- -- Assert_Greater_Or_Equal -- ----------------------------- procedure Assert_Greater_Or_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Enabled and then "<" (Left, Right) then Report.On_Assertion_Failed (Details => Image (Left) & " = " & Image (Right), Msg => Msg, Location => Location, Entity => Entity); end if; end Assert_Greater_Or_Equal; -------------------- -- Assert_Greater -- -------------------- procedure Assert_Greater (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Enabled and then ("<" (Left, Right) or else "=" (Left, Right)) then Report.On_Assertion_Failed (Details => Image (Left) & " = " & Image (Right), Msg => Msg, Location => Location, Entity => Entity); end if; end Assert_Greater; end Compare; end Asserts; end GNATCOLL.Asserts; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-asserts.ads000066400000000000000000000223471425465243200230730ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides support for writing assertions in source code, -- while getting proper error messages. -- -- GNAT's "pragma Assert" does not display the expression that was tested, -- so users end up writing the name of the variables in the message string -- itself. This message is then associated with the Assertion_Error exception -- that is raised. But exceptions limit the maximal length of such messages, -- so again it is hard to have a meaningful message. -- -- GNATCOLL.Traces provides an Assert procedure which tests the boolean -- expression and displays a log message if it is false (and optionally -- raises an exception). But the expression still needs to be manually -- described in the message. -- -- This package intends to ease the writing of the error messages, by -- automatically generating messages that include the expression that -- was tested, as well as the source location for that test. -- The result of a failed assertion is left under control of an error -- reporter, which you can customize in your application to raise -- exceptions, log error messages, write to a GUI console, send to a -- socket,... with GNAT.Source_Info; use GNAT.Source_Info; package GNATCOLL.Asserts is -------------------- -- Error_Reporter -- -------------------- type Error_Reporter is interface; -- This type is responsible for reacting when an assertion fails. procedure On_Assertion_Failed (Self : Error_Reporter; Msg : String; Details : String; Location : String; Entity : String) is abstract; -- Report the assertion error. -- The exact behavior depends on your application, and you will in -- general provide your own implementation of Error_Reporter unless -- one of the basic ones provided below works for you. -- Self will often be a global variable, and should therefore be -- stateless as much as possible (if your application is multi-threaded, -- it will be shared among the threads). For this reason, the parameter -- is set as "in". ------------------------ -- Exception_Reporter -- ------------------------ type Exception_Reporter is new Error_Reporter with null record; overriding procedure On_Assertion_Failed (Self : Exception_Reporter; Msg : String; Details : String; Location : String; Entity : String); -- An error reporter that simply raises an Assertion_Error and sets a -- message for it. Due to limitations in the implementation of -- exceptions, the length of the message is limited, and thus Msg will -- be truncated as needed. ---------------- -- Assertions -- ---------------- -- The following packages provides multiple ways to test values. These -- are implemented as generic packages so that they can also be applied -- to user-defined types. -- All the Assert_* procedures receives some common parameters: -- Msg : String -- Is an extra message that should be part of the error message, -- and can be used to provide additional explanations. For -- efficiency, this should be a static string as much as possible, -- since the compiler will always need to build that string to -- pass it to Assert_*, even if the latter does not use it in the -- end. -- Location, Entity -- These are used to compute statically the source location of -- the failed assertion. You should not provide actual values for -- these. generic Report : Error_Reporter'Class; -- The error reporter used by all Assert_* procedures below. This -- will in general be a global variable. Enabled : Boolean := True; -- If you set this to False, none of the Assertions will perform any -- work, and they might be omitted from the final binary altogether. package Asserts is procedure Assert_Failed (Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); -- Unconditionally report an error. generic type T (<>) is limited private; with function Image (V : T) return String is <>; with function "=" (Left, Right : T) return Boolean is <>; package Equals is procedure Assert_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); procedure Assert (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) renames Assert_Equal; -- Left must be equal to Right, using the "=" operator. procedure Assert_Not_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); -- Left must be different from Right, using the "=" operator. end Equals; generic type T (<>) is limited private; with function Image (V : T) return String is <>; with function "=" (Left, Right : T) return Boolean is <>; with function "<" (Left, Right : T) return Boolean is <>; package Compare is procedure Assert_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); procedure Assert (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) renames Assert_Equal; -- Left must be equal to Right, using the "=" operator. procedure Assert_Not_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); -- Left must be different from Right, using the "=" operator. procedure Assert_Less (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); -- asserts Left < Right procedure Assert_Less_Or_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); -- asserts Left <= Right procedure Assert_Greater_Or_Equal (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); -- asserts Left >= Right procedure Assert_Greater (Left, Right : T; Msg : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); -- asserts Left > Right end Compare; end Asserts; end GNATCOLL.Asserts; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-atomic.ads000066400000000000000000000131751425465243200226620ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides a number of low-level primitives to execute -- task-safe operations. -- When possible, these operations are executed via one of the intrinsic -- atomic operations of the compiler (generally implemented with special -- support from the CPU). with System.Atomic_Counters; package GNATCOLL.Atomic is subtype Atomic_Counter is System.Atomic_Counters.Atomic_Unsigned; Minus_One : constant Atomic_Counter := System.Atomic_Counters."-" (0, 1); function Is_Lock_Free return Boolean; -- Whether the implementation uses the processor's atomic operations -- or falls back on using locks function Sync_Add_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) return Atomic_Counter with Inline_Always; -- Increment Ptr by Value. This is task safe (either using a lock or -- intrinsic atomic operations). Returns the new value (as set, it -- might already have been changed by another task by the time this -- function returns. function Sync_Sub_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) return Atomic_Counter with Inline_Always; -- Decrement Ptr by Value. procedure Sync_Add_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) with Inline_Always; procedure Sync_Sub_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) with Inline_Always; -- Same as above, but ignore the return value. procedure Increment (Value : aliased in out Atomic_Counter) with Inline_Always; procedure Decrement (Value : aliased in out Atomic_Counter) with Inline_Always; function Decrement (Value : aliased in out Atomic_Counter) return Boolean with Inline_Always; -- Similar to the Sync_Add_And_Fetch and Sync_Sub_And_And, but -- always increment or decrement by one. -- On some systems (x86) this uses faster assembly instructions. -- Decrement returns True if the value reaches 0. function "+" (Left, Right : Atomic_Counter) return Atomic_Counter is abstract; function "-" (Left, Right : Atomic_Counter) return Atomic_Counter is abstract; -- Prevent standard operations on these counters function Unsafe_Decrement (Value : in out Atomic_Counter) return Boolean with Inline_Always; procedure Unsafe_Increment (Value : in out Atomic_Counter) with Inline_Always; -- These are unsafe operations. If you have two threads, and they all try -- to do "Unsafe_Add (A, 2)" at the same time, when A was initially 0, -- you could end up with the following values in A: -- 2 (both threads have read 0, then added 2) -- 4 (thread 1 has read and incremented, then thread 2) -- If you use the other operations above, you always end up with 4. function "=" (Left, Right : Atomic_Counter) return Boolean renames System.Atomic_Counters."="; -- Make the operator visible generic type Element_Type (<>) is limited private; type Element_Access is access Element_Type; function Sync_Bool_Compare_And_Swap (Ptr : access Element_Access; Oldval : Element_Access; Newval : Element_Access) return Boolean; -- If Ptr is equal to Oldval, set it to Newval and return True. -- Otherwise, return False and do not modify the current value. -- This operation is task safe and atomic. function Sync_Bool_Compare_And_Swap_Counter (Ptr : access Atomic_Counter; Oldval : Atomic_Counter; Newval : Atomic_Counter) return Boolean; function Sync_Val_Compare_And_Swap_Counter (Ptr : access Atomic_Counter; Oldval : Atomic_Counter; Newval : Atomic_Counter) return Atomic_Counter; -- A version that works with Atomic_Counter. -- Ptr.all is set to Newval if and only if it is currently set to Oldval. -- Returns True if the value was changed. -- The second version returns the initial value of Ptr.all end GNATCOLL.Atomic; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-atomic__intrinsic.ada000066400000000000000000000151471425465243200250620ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Interfaces; use Interfaces; package body GNATCOLL.Atomic is function Intrinsic_Sync_Bool_Compare_And_Swap (Ptr : access Atomic_Counter; Oldval : Atomic_Counter; Newval : Atomic_Counter) return Boolean; pragma Import (Intrinsic, Intrinsic_Sync_Bool_Compare_And_Swap, External_Name => "__sync_bool_compare_and_swap_4"); function Intrinsic_Sync_Val_Compare_And_Swap (Ptr : access Atomic_Counter; Oldval : Atomic_Counter; Newval : Atomic_Counter) return Atomic_Counter; pragma Import (Intrinsic, Intrinsic_Sync_Val_Compare_And_Swap, External_Name => "__sync_val_compare_and_swap_4"); function Intrinsic_Sync_Add_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) return Atomic_Counter; pragma Import (Intrinsic, Intrinsic_Sync_Add_And_Fetch, External_Name => "__sync_add_and_fetch_4"); function Intrinsic_Sync_Sub_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) return Atomic_Counter; pragma Import (Intrinsic, Intrinsic_Sync_Sub_And_Fetch, External_Name => "__sync_sub_and_fetch_4"); ------------------ -- Is_Lock_Free -- ------------------ function Is_Lock_Free return Boolean is (True); ------------------------ -- Sync_Add_And_Fetch -- ------------------------ function Sync_Add_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) return Atomic_Counter is begin return Intrinsic_Sync_Add_And_Fetch (Ptr, Value); end Sync_Add_And_Fetch; procedure Sync_Add_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) is Dummy : Atomic_Counter with Unreferenced; begin Dummy := Intrinsic_Sync_Add_And_Fetch (Ptr, Value); end Sync_Add_And_Fetch; ------------------------ -- Sync_Sub_And_Fetch -- ------------------------ function Sync_Sub_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) return Atomic_Counter is begin return Intrinsic_Sync_Sub_And_Fetch (Ptr, Value); end Sync_Sub_And_Fetch; procedure Sync_Sub_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) is Dummy : Atomic_Counter with Unreferenced; begin Dummy := Intrinsic_Sync_Sub_And_Fetch (Ptr, Value); end Sync_Sub_And_Fetch; --------------- -- Increment -- --------------- procedure Increment (Value : aliased in out Atomic_Counter) is begin System.Atomic_Counters.Increment (Value); end Increment; --------------- -- Decrement -- --------------- procedure Decrement (Value : aliased in out Atomic_Counter) is begin System.Atomic_Counters.Decrement (Value); end Decrement; function Decrement (Value : aliased in out Atomic_Counter) return Boolean is begin return System.Atomic_Counters.Decrement (Value); end Decrement; ---------------------- -- Unsafe_Increment -- ---------------------- procedure Unsafe_Increment (Value : in out Atomic_Counter) is begin Value := Atomic_Counter'Succ (Value); end Unsafe_Increment; ---------------------- -- Unsafe_Decrement -- ---------------------- function Unsafe_Decrement (Value : in out Atomic_Counter) return Boolean is begin Value := Atomic_Counter'Pred (Value); return Value = 0; end Unsafe_Decrement; -------------------------------- -- Sync_Bool_Compare_And_Swap -- -------------------------------- function Sync_Bool_Compare_And_Swap (Ptr : access Element_Access; Oldval : Element_Access; Newval : Element_Access) return Boolean is function Intrinsic_Sync_Bool_And_Swap_Access (Ptr : access Element_Access; Oldval, Newval : Element_Access) return Interfaces.Integer_8; pragma Import (Intrinsic, Intrinsic_Sync_Bool_And_Swap_Access, External_Name => "gnatcoll_sync_bool_compare_and_swap_access"); begin return Intrinsic_Sync_Bool_And_Swap_Access (Ptr, Oldval, Newval) /= 0; end Sync_Bool_Compare_And_Swap; ---------------------------------------- -- Sync_Bool_Compare_And_Swap_Counter -- ---------------------------------------- function Sync_Bool_Compare_And_Swap_Counter (Ptr : access Atomic_Counter; Oldval : Atomic_Counter; Newval : Atomic_Counter) return Boolean is begin return Intrinsic_Sync_Bool_Compare_And_Swap (Ptr, Oldval, Newval); end Sync_Bool_Compare_And_Swap_Counter; --------------------------------------- -- Sync_Val_Compare_And_Swap_Counter -- --------------------------------------- function Sync_Val_Compare_And_Swap_Counter (Ptr : access Atomic_Counter; Oldval : Atomic_Counter; Newval : Atomic_Counter) return Atomic_Counter is begin return Intrinsic_Sync_Val_Compare_And_Swap (Ptr, Oldval, Newval); end Sync_Val_Compare_And_Swap_Counter; end GNATCOLL.Atomic; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-atomic__mutex.ada000066400000000000000000000141521425465243200242150ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ pragma Ada_2012; with GNAT.Task_Lock; package body GNATCOLL.Atomic is ------------------ -- Is_Lock_Free -- ------------------ function Is_Lock_Free return Boolean is (False); ------------------------ -- Sync_Add_And_Fetch -- ------------------------ function Sync_Add_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) return Atomic_Counter is Result : Atomic_Counter; begin GNAT.Task_Lock.Lock; Ptr.all := Atomic_Counter (Natural (Ptr.all) + Natural (Value)); Result := Ptr.all; -- ??? Should use a memory barriere here GNAT.Task_Lock.Unlock; return Result; end Sync_Add_And_Fetch; procedure Sync_Add_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) is Dummy : Atomic_Counter; pragma Unreferenced (Dummy); begin Dummy := Sync_Add_And_Fetch (Ptr, Value); end Sync_Add_And_Fetch; ------------------------ -- Sync_Sub_And_Fetch -- ------------------------ function Sync_Sub_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) return Atomic_Counter is Result : Atomic_Counter; begin GNAT.Task_Lock.Lock; Ptr.all := Atomic_Counter (Natural (Ptr.all) - Natural (Value)); Result := Ptr.all; -- ??? Should use a memory barriere here GNAT.Task_Lock.Unlock; return Result; end Sync_Sub_And_Fetch; procedure Sync_Sub_And_Fetch (Ptr : access Atomic_Counter; Value : Atomic_Counter) is Dummy : Atomic_Counter; pragma Unreferenced (Dummy); begin Dummy := Sync_Sub_And_Fetch (Ptr, Value); end Sync_Sub_And_Fetch; --------------- -- Increment -- --------------- procedure Increment (Value : aliased in out Atomic_Counter) is begin Sync_Add_And_Fetch (Value'Unrestricted_Access, 1); end Increment; --------------- -- Decrement -- --------------- procedure Decrement (Value : aliased in out Atomic_Counter) is begin Sync_Sub_And_Fetch (Value'Unrestricted_Access, 1); end Decrement; function Decrement (Value : aliased in out Atomic_Counter) return Boolean is begin return Sync_Sub_And_Fetch (Value'Unrestricted_Access, 1) = 0; end Decrement; ---------------------- -- Unsafe_Increment -- ---------------------- procedure Unsafe_Increment (Value : in out Atomic_Counter) is begin Value := Atomic_Counter (Natural (Value) + 1); end Unsafe_Increment; ---------------------- -- Unsafe_Decrement -- ---------------------- function Unsafe_Decrement (Value : in out Atomic_Counter) return Boolean is begin Value := Atomic_Counter (Natural (Value) - 1); return Value = 0; end Unsafe_Decrement; -------------------------------- -- Sync_Bool_Compare_And_Swap -- -------------------------------- function Sync_Bool_Compare_And_Swap (Ptr : access Element_Access; Oldval : Element_Access; Newval : Element_Access) return Boolean is begin GNAT.Task_Lock.Lock; if Ptr.all = Oldval then Ptr.all := Newval; GNAT.Task_Lock.Unlock; return True; else GNAT.Task_Lock.Unlock; return False; end if; end Sync_Bool_Compare_And_Swap; -------------------------------- -- Sync_Bool_Compare_And_Swap -- -------------------------------- function Sync_Bool_Compare_And_Swap_Counter (Ptr : access Atomic_Counter; Oldval : Atomic_Counter; Newval : Atomic_Counter) return Boolean is begin GNAT.Task_Lock.Lock; if Ptr.all = Oldval then Ptr.all := Newval; GNAT.Task_Lock.Unlock; return True; else GNAT.Task_Lock.Unlock; return False; end if; end Sync_Bool_Compare_And_Swap_Counter; ------------------------------- -- Sync_Val_Compare_And_Swap -- ------------------------------- function Sync_Val_Compare_And_Swap_Counter (Ptr : access Atomic_Counter; Oldval : Atomic_Counter; Newval : Atomic_Counter) return Atomic_Counter is Initial : Atomic_Counter; begin GNAT.Task_Lock.Lock; Initial := Ptr.all; if Ptr.all = Oldval then Ptr.all := Newval; GNAT.Task_Lock.Unlock; return Initial; else GNAT.Task_Lock.Unlock; return Initial; end if; end Sync_Val_Compare_And_Swap_Counter; end GNATCOLL.Atomic; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-boyer_moore.adb000066400000000000000000000306351425465243200237060ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2001-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- The search is done right-to-left. In the best cases (the text doesn't -- contain any character from the pattern), this results in -- string_length / pattern_length, characters being examined, instead of -- string_length characters. -- -- Compiling the pattern generates two lookup-tables: -- -- The Last Occurrence Function -- ============================ -- -- The Last-Ocurrence-Function returns the right-most location for each -- character in the alphabet in the pattern. -- When a character is seen in the searched string, this array will suggest -- the offset by which we should move the character: -- string: "revolution in the treatment of" -- pattern: " reminiscence" -- ^ when we see the 'h', we can move to: -- " reminiscence" -- -- string: "written notice that" -- pattern: " reminiscence" -- ^ when the see the 'i', we can move to: -- " reminiscence" -- -- string: "golden fleece of" -- pattern: " reminiscence" -- ^ when we see the 'e', no move can be suggested, -- since 'e' appears at the right-most position -- in the pattern. -- -- The Good Suffix Function -- ======================== -- -- This function reports the least amount that garantees that any pattern -- characters that align with the good suffix previously found in the text -- will match those suffix characters. -- For instance: -- -- string: "written notice that" -- pattern: " reminiscence" -- ^ The pattern would be moved so that the "ce" -- vv we have already found match some text. -- " reminiscence" -- -- Combination -- =========== -- -- The two functions above can be computed statically based only on the -- pattern, and without any knowledge of the text. -- When we try to match a pattern with a text, these two functions are -- combined, and the pattern is moved forward by the maximum amount reported -- by the two functions. with Unchecked_Deallocation; with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; with GNAT.Case_Util; use GNAT.Case_Util; package body GNATCOLL.Boyer_Moore is Debug : constant Boolean := False; Debug_Run : constant Boolean := False; procedure Dump_Str (Str : String); -- Print string, replacing the newlines with spaces for clarity procedure Dump (M, Shift, J : Natural; Num_Comp : in out Natural; Motif : Pattern; In_String : String); -- Print the current state of the search. -- The parameters are the internal state in Search. We do not use a -- nested subprogram for efficiency reasons ------------- -- Compile -- ------------- procedure Compile (Motif : in out Pattern; From_String : String; Case_Sensitive : Boolean := True) is -- Prefix contains the following: -- Prefix (J) is the length of the longest prefix of Motif -- which is also a suffix of -- Motif (Motif'First .. Motif'First + J - 1) -- ie of the motif made of the j-th first characters of Motif -- -- Reverse_Prefix is the Prefix function applied to the reverse of Motif -- -- Motif.Last_Occurrence contains the index of the last occurrence of -- the character in the motif. This is in the range 1 .. Motif'Length -- -- Good_Suffix at index J: -- If a mismatch occurs in the j-th character of the pattern, we -- can safely advance by good_suffix (j). -- m = Motif'Length -- GS(J) = m -- - Max (k; 0<=k 0); Motif.Motif := new String (1 .. From_String'Length); Motif.Motif.all := From_String; if not Case_Sensitive then To_Lower (Motif.Motif.all); end if; Prefix (Prefix'First) := 0; Reverse_Prefix (Reverse_Prefix'First) := 0; Motif.Last_Occurrence (Motif.Motif (1)) := 1; for Q in 2 .. Motif.Motif'Last loop -- Compute Last occurrence Motif.Last_Occurrence (Motif.Motif (Q)) := Q; -- Compute prefix function while K > 0 and then Motif.Motif (K + 1) /= Motif.Motif (Q) loop K := Prefix (K); end loop; if Motif.Motif (K + 1) = Motif.Motif (Q) then K := K + 1; end if; Prefix (Q) := K; -- Compute the reverse prefix function while K2 > 0 and then Motif.Motif (Motif.Motif'Last - K2) /= Motif.Motif (Motif.Motif'Last + 1 - Q) loop K2 := Reverse_Prefix (K2); end loop; if Motif.Motif (Motif.Motif'Last - K2) = Motif.Motif (Motif.Motif'Last + 1 - Q) then K2 := K2 + 1; end if; Reverse_Prefix (Q) := K2; end loop; -- Compute the good suffix function K := From_String'Length - Prefix (From_String'Length); Motif.Good_Suffix := new Offset_Array'(0 .. From_String'Length => K); for L in Motif.Motif'Range loop K := From_String'Length - Reverse_Prefix (L); Tmp := L - Reverse_Prefix (L); if Motif.Good_Suffix (K) > Tmp then Motif.Good_Suffix (K) := Tmp; end if; end loop; if Debug then Put (" i = "); for J in Motif.Motif'Range loop Put (Item => J, Width => 3); end loop; New_Line; Put (" Pat[i]= "); for J in Motif.Motif'Range loop Put (" " & Motif.Motif (J)); end loop; New_Line; Put (" Pre[i]= "); for J in Prefix'Range loop Put (Item => Prefix (J), Width => 3); end loop; New_Line; Put ("RevPre[i]= "); for J in Reverse_Prefix'Range loop Put (Item => Reverse_Prefix (J), Width => 3); end loop; New_Line; Put ("GoodSu[i]= "); for J in Motif.Good_Suffix'Range loop Put (Item => Motif.Good_Suffix (J), Width => 3); end loop; New_Line; end if; end Compile; ---------- -- Free -- ---------- procedure Free (Motif : in out Pattern) is procedure Internal is new Unchecked_Deallocation (Offset_Array, Offset_Array_Access); procedure Internal is new Unchecked_Deallocation (String, String_Access); begin Internal (Motif.Good_Suffix); Internal (Motif.Motif); end Free; -------------- -- Dump_Str -- -------------- procedure Dump_Str (Str : String) is begin for S in Str'Range loop if Str (S) = ASCII.LF then Put (' '); else Put (Str (S)); end if; end loop; New_Line; end Dump_Str; ---------- -- Dump -- ---------- procedure Dump (M, Shift, J : Natural; Num_Comp : in out Natural; Motif : Pattern; In_String : String) is begin -- Show current automaton state Num_Comp := Num_Comp + M - J + 1; if Debug_Run then New_Line; Put_Line ("Offset : Shift+j=" & Integer'Image (Shift + J) & " J=" & J'Img & " Last_Occ=" & In_String (Shift + J) & " Max (" & Motif.Good_Suffix (J)'Img & "," & Integer'Image (J - Motif.Last_Occurrence (In_String (Shift + J))) & ")"); if In_String'Length < 400 then Dump_Str (In_String); Put ((1 .. Shift - In_String'First + 1 => ' ')); end if; Dump_Str (Motif.Motif.all); if Shift + J - In_String'First < 400 then Put ((1 .. Shift + J - In_String'First => ' ')); Put_Line ("^"); end if; end if; if J = 0 then Put_Line ("Matched at position" & Natural'Image (Shift + 1) & " after" & Num_Comp'Img & " comparisons"); end if; end Dump; ------------ -- Search -- ------------ function Search (Motif : Pattern; In_String : String) return Integer is M : Natural; Shift : Natural := In_String'First - 1; J : Natural; Num_Comp : Natural := 0; begin if Motif.Motif = null then return -1; end if; M := Motif.Motif'Length; -- length of pattern pragma Assert (Motif.Motif'First = 1); if not Motif.Case_Sensitive then while Shift <= In_String'Last - M loop J := M; while J > 0 and then Motif.Motif (J) = To_Lower (In_String (Shift + J)) loop J := J - 1; end loop; if J = 0 then return Shift + 1; elsif Debug then Dump (M, Shift, J, Num_Comp, Motif, In_String); end if; Shift := Shift + Natural'Max (Motif.Good_Suffix (J), J - Motif.Last_Occurrence (To_Lower (In_String (Shift + J)))); end loop; else while Shift <= In_String'Last - M loop J := M; while J > 0 and then Motif.Motif (J) = In_String (Shift + J) loop J := J - 1; end loop; if J = 0 then return Shift + 1; elsif Debug then Dump (M, Shift, J, Num_Comp, Motif, In_String); end if; Shift := Shift + Natural'Max (Motif.Good_Suffix (J), J - Motif.Last_Occurrence (In_String (Shift + J))); end loop; end if; return -1; end Search; end GNATCOLL.Boyer_Moore; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-boyer_moore.ads000066400000000000000000000072661425465243200237330ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2001-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package implements the Boyer-Moore algorithm for string searching, -- as described in the book "Algorithms" by T. Cormen (McGrawHill edts) -- -- This is a very efficient string searching algorithm, where the key being -- search is preprocessed to speed up further searches. However, unlike some -- other search algorithms, the text being searched does not need any -- pre-processing. package GNATCOLL.Boyer_Moore is type Pattern is private; Max_Pattern_Length : constant := Integer'Last; -- Maximal length for patterns that can be searched. -- Changing this means that patterns will simply use more space. procedure Compile (Motif : in out Pattern; From_String : String; Case_Sensitive : Boolean := True); -- Compile the required tables to match From_String anywhere. -- Motif needs to be freed when you are done using it. -- -- Note: A case_sensitive search is always more efficient, and should -- be used if you don't specifically need a case insensitive search. procedure Free (Motif : in out Pattern); -- Free the memory occupied by the motif function Search (Motif : Pattern; In_String : String) return Integer; -- Return the location of the match for Motif in In_String, or -1 if there -- is no match; private subtype Offset is Natural range 0 .. Max_Pattern_Length; -- This is the maximal offset reported by pattern. This might result in -- a slightly less efficient processing for patterns longer than this in -- extreme cases, but these are for very rare cases. type Occurrence_Array is array (Character) of Offset; type Offset_Array is array (Natural range <>) of Offset; type Offset_Array_Access is access Offset_Array; type String_Access is access String; type Pattern is record Last_Occurrence : Occurrence_Array; Good_Suffix : Offset_Array_Access; Motif : String_Access; Case_Sensitive : Boolean; end record; end GNATCOLL.Boyer_Moore; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-config.adb000066400000000000000000000376261425465243200226410ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Strings.Fixed; use Ada.Strings.Fixed; with Ada.Strings.Maps; use Ada.Strings.Maps; with GNAT.Directory_Operations; use GNAT.Directory_Operations; with GNAT.OS_Lib; use GNAT.OS_Lib; with GNATCOLL.Mmap; use GNATCOLL.Mmap; with GNATCOLL.Strings; use GNATCOLL.Strings; with GNATCOLL.Templates; use GNATCOLL.Templates; with GNATCOLL.Utils; use GNATCOLL.Utils; with GNATCOLL.VFS; use GNATCOLL.VFS; package body GNATCOLL.Config is use String_Maps; No_Value : constant Config_Value := (Len => 0, System_Id => Null_XString, Value => (others => ' ')); Whitespaces : constant Character_Set := To_Set (" " & ASCII.CR & ASCII.HT & ASCII.LF & ASCII.VT & ASCII.FF); function Internal_Get (Self : Config_Pool; Key : String; Section : String := Section_From_Key) return Config_Value; -- Internal version of Get function At_Index (Value : Config_Value; Index : Natural := Whole_Value) return String; -- Extract an element from a comma-separated list function Substitute (Self : INI_Parser'Class; Value : String) return String; -- Substitute various strings in the value read from the config file, -- for instance $HOME. ------------------- -- Set_System_Id -- ------------------- procedure Set_System_Id (Self : in out Config_Parser; System_ID : String) is begin Self.System_ID := To_XString (Normalize_Pathname (System_ID)); end Set_System_Id; ---------------- -- As_Integer -- ---------------- function As_Integer (Self : Config_Parser) return Integer is begin return Integer'Value (Value (Config_Parser'Class (Self))); end As_Integer; ---------------- -- As_Boolean -- ---------------- function As_Boolean (Self : Config_Parser) return Boolean is begin return Boolean'Value (Value (Config_Parser'Class (Self))); end As_Boolean; ---------------------- -- As_Absolute_File -- ---------------------- function As_Absolute_File (Self : Config_Parser) return String is Val : constant String := Value (Config_Parser'Class (Self)); begin if Val = "" then return ""; elsif Val (Val'First) = '/' then return Val; else return Normalize_Pathname (Val, To_String (Self.System_ID)); end if; end As_Absolute_File; --------------------- -- As_Absolute_Dir -- --------------------- function As_Absolute_Dir (Self : Config_Parser) return String is V : constant String := As_Absolute_File (Config_Parser'Class (Self)); begin if V = "" then return ""; elsif V (V'Last) = Directory_Separator then return V; else return V & Directory_Separator; end if; end As_Absolute_Dir; ---------- -- Open -- ---------- procedure Open (Self : in out File_Config_Parser; Filename : String) is F : Mapped_File; Str : Str_Access; begin F := Open_Read (Filename); Read (F); Str := Data (F); Self.Contents := To_XString (String (Str (1 .. Last (F)))); Self.System_ID := To_XString (Normalize_Pathname (Dir_Name (Filename))); Self.First := 1; Close (F); end Open; ------------ -- At_End -- ------------ overriding function At_End (Self : File_Config_Parser) return Boolean is begin return Self.First > Length (Self.Contents); end At_End; ---------- -- Open -- ---------- overriding procedure Open (Self : in out INI_Parser; Filename : String) is begin Open (File_Config_Parser (Self), Filename); Self.Eol := 0; Self.Current_Section := To_XString (""); Next (Self); end Open; ---------- -- Next -- ---------- overriding procedure Next (Self : in out INI_Parser) is Eol : Integer; First_Non_WS : Integer; Last_Non_WS : Integer; Last : constant Integer := Length (Self.Contents); Comment : constant Integer := Length (Self.Comment_Start); begin -- Mark begining of the line. Self.First := Self.Eol + 1; while Self.First <= Last loop Eol := Self.First; Self.Equal := 0; First_Non_WS := 0; Last_Non_WS := 0; -- Search end of current line and presence of '=' while Eol <= Last loop declare CC : constant Character := Self.Contents (Eol); begin case CC is when ASCII.LF => exit; when '=' => if Self.Equal = 0 then Self.Equal := Eol; end if; when ' ' | ASCII.CR | ASCII.HT | ASCII.VT | ASCII.FF => null; when others => if First_Non_WS = 0 then First_Non_WS := Eol; Last_Non_WS := Eol; else Last_Non_WS := Eol; end if; if Self.Equal = 0 and then CC = '=' then Self.Equal := Eol; end if; end case; end; Eol := Eol + 1; end loop; Self.Eol := Eol; if First_Non_WS = 0 then -- line containing only whitespaces null; elsif First_Non_WS + Comment - 1 <= Eol and then Slice (Self.Contents, First_Non_WS, First_Non_WS + Comment - 1) = Self.Comment_Start then -- This is comment line so skip it null; elsif Self.Equal /= 0 then -- We have an equal sign so this an assignement exit; elsif Self.Use_Sections and then Self.Contents (First_Non_WS) = '[' and then Self.Contents (Last_Non_WS) = ']' then -- This is a section declaration. Self.Current_Section := Self.Contents.Slice (First_Non_WS + 1, Last_Non_WS - 1); end if; Self.First := Eol + 1; end loop; end Next; --------------- -- Configure -- --------------- procedure Configure (Self : in out INI_Parser; Comment_Start : String := "#"; Handles_Sections : Boolean := True; Home : String := "") is begin Self.Comment_Start := To_XString (Comment_Start); Self.Use_Sections := Handles_Sections; if Home /= "" then Self.Home := Create (+Home); end if; end Configure; ---------------- -- Substitute -- ---------------- function Substitute (Self : INI_Parser'Class; Value : String) return String is function Callback (Name : String; Quoted : Boolean) return String; function Callback (Name : String; Quoted : Boolean) return String is pragma Unreferenced (Quoted); begin if Name = "HOME" then return +Self.Home.Full_Name; else raise Invalid_Substitution; end if; end Callback; begin return Substitute (Str => Value, Callback => Callback'Unrestricted_Access, Delimiter => '$'); exception when others => return Value; end Substitute; ------------- -- Section -- ------------- overriding function Section (Self : INI_Parser) return String is begin return Self.Current_Section.To_String; end Section; --------- -- Key -- --------- overriding function Key (Self : INI_Parser) return String is begin return Self.Contents.Slice (Self.First, Self.Equal - 1).Trim.To_String; end Key; ----------- -- Value -- ----------- overriding function Value (Self : INI_Parser) return String is begin return Substitute (Self, Trim (Self.Contents.Slice (Self.Equal + 1, Self.Eol - 1).To_String, Whitespaces, Whitespaces)); end Value; ---------- -- Fill -- ---------- procedure Fill (Self : in out Config_Pool; Config : in out Config_Parser'Class) is begin Set_System_Id (Self, To_String (Config.System_ID)); while not At_End (Config) loop Set (Self, Section (Config), Key (Config), Value (Config)); Next (Config); end loop; end Fill; ------------------- -- Set_System_Id -- ------------------- procedure Set_System_Id (Self : in out Config_Pool; System_ID : String) is begin Self.System_ID := To_XString (Normalize_Pathname (System_ID)); end Set_System_Id; ------------------ -- Internal_Get -- ------------------ function Internal_Get (Self : Config_Pool; Key : String; Section : String := Section_From_Key) return Config_Value is C : String_Maps.Cursor; begin if Section = Section_From_Key then for D in Key'Range loop if Key (D) = '.' then C := Self.Keys.Find (Key (Key'First .. D - 1) & '=' & Key (D + 1 .. Key'Last)); if C = No_Element then return No_Value; else return Element (C); end if; end if; end loop; C := Self.Keys.Find ('=' & Key); else C := Self.Keys.Find (Section & '=' & Key); end if; if C = No_Element then return No_Value; else return Element (C); end if; end Internal_Get; -------------- -- At_Index -- -------------- function At_Index (Value : Config_Value; Index : Natural := Whole_Value) return String is S : String_List_Access; begin if Index = Whole_Value then return Value.Value; else S := Split (Value.Value, ','); if Index > S'Last then Free (S); return ""; else return R : constant String := S (Index).all do Free (S); end return; end if; end if; end At_Index; --------- -- Get -- --------- function Get (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Index : Natural := Whole_Value) return String is begin return At_Index (Internal_Get (Self, Key, Section), Index); end Get; ----------------- -- Get_Integer -- ----------------- function Get_Integer (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Index : Natural := Whole_Value) return Integer is begin return Integer'Value (Get (Self, Key, Section, Index)); end Get_Integer; ----------------- -- Get_Boolean -- ----------------- function Get_Boolean (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Index : Natural := Whole_Value) return Boolean is begin return Boolean'Value (Get (Self, Key, Section, Index)); end Get_Boolean; -------------- -- Get_File -- -------------- function Get_File (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Index : Natural := Whole_Value) return String is Val : constant Config_Value := Internal_Get (Self, Key, Section); V : constant String := At_Index (Val, Index); begin if V = "" then return ""; elsif Is_Absolute_Path (V) then return V; else return Normalize_Pathname (V, To_String (Val.System_ID)); end if; end Get_File; ------------- -- To_File -- ------------- function To_File (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Value : String) return Virtual_File is Val : constant Config_Value := Internal_Get (Self, Key, Section); begin if Value = "" then return GNATCOLL.VFS.No_File; elsif Is_Absolute_Path (Value) then return Create (+Value); else return Create (+Normalize_Pathname (Value, To_String (Val.System_ID))); end if; end To_File; --------- -- Set -- --------- procedure Set (Self : in out Config_Pool; Section, Key, Value : String) is begin Include (Self.Keys, Section & "=" & Key, Config_Value' (Len => Value'Length, Value => Value, System_ID => Self.System_ID)); end Set; ------------ -- Create -- ------------ function Create (Key : String; Section : String := "") return Config_Key is begin return Config_Key'(Section => To_XString (Section), Key => To_XString (Key)); end Create; --------- -- Get -- --------- function Get (Self : Config_Key; Conf : Config_Pool'Class; Index : Natural := Whole_Value) return String is begin return Get (Conf, To_String (Self.Key), To_String (Self.Section), Index); end Get; ----------------- -- Get_Integer -- ----------------- function Get_Integer (Self : Config_Key; Conf : Config_Pool'Class; Index : Natural := Whole_Value) return Integer is begin return Get_Integer (Conf, To_String (Self.Key), To_String (Self.Section), Index); end Get_Integer; ----------------- -- Get_Boolean -- ----------------- function Get_Boolean (Self : Config_Key; Conf : Config_Pool'Class; Index : Natural := Whole_Value) return Boolean is begin return Get_Boolean (Conf, To_String (Self.Key), To_String (Self.Section), Index); end Get_Boolean; -------------- -- Get_File -- -------------- function Get_File (Self : Config_Key; Conf : Config_Pool'Class; Index : Natural := Whole_Value) return String is begin return Get_File (Conf, To_String (Self.Key), To_String (Self.Section), Index); end Get_File; ------------- -- To_File -- ------------- function To_File (Self : Config_Key; Conf : Config_Pool'Class; Value : String) return Virtual_File is begin return To_File (Conf, To_String (Self.Key), To_String (Self.Section), Value); end To_File; end GNATCOLL.Config; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-config.ads000066400000000000000000000305661425465243200226560ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides a general handling mechanism for config files. -- Any format of config files can be supported. The default implementation -- provides support for Windows-like .ini files, that is: -- -- # Comment -- [Section] -- key1 = value1 -- key2 = value2 -- -- .ini file format is not a very strict parser. Statement types are -- considered in that order: -- -- 1- comment -- 2- assigment -- 3- section declaration -- -- Thus for example: -- -- [key1 = key2] -- -- Will be parsed as "[key1" = "key2]" and not as a section declaration. -- -- Any line that does not correspond to any of the previous types will be -- ignored. Leading and trailing whitespaces are ignored. Whitespaces around -- the first '=' are also ignored. -- -- As a special case, some strings are automatically substituted in the values -- - HOME: home directory for the user, as configured in the parser -- -- This package is build through several layers of tagged objects: -- - the first layer provides the parsing of config files, and through a -- callback returns the (key, value) pairs to the application -- - the second layer provides a pool of these pairs, ie provides the storage -- on top of the first layer. Queries are done through strings -- - a third layer makes the keys as real objects, so that you build the key -- once, and then query the value from it directly. This is mostly syntactic -- sugar, although it helps ensure that you are always reading existing keys -- (if your coding convention forces users to use these keys). private with Ada.Containers.Indefinite_Hashed_Maps; private with Ada.Strings.Hash; private with GNATCOLL.Strings; with GNATCOLL.VFS; package GNATCOLL.Config is -------------------------- -- Parsing config files -- -------------------------- type Config_Parser is abstract tagged private; -- Abstract type for all config streams (files, in-memory,...), with any -- format. Concrete types below will provide the actual implementation. -- Typical usage looks like: -- declare -- C : File_Config_Parser; -- begin -- Open (C, "filename.txt"); -- while not C.At_End loop -- Put_Line (C.Key & " = " & C.Value); -- C.Next; -- end loop; -- end; function At_End (Self : Config_Parser) return Boolean is abstract; -- Whether the config parsing is at the end procedure Next (Self : in out Config_Parser) is abstract; -- Move to the next (key, value) in the configuration. Before that call, -- the parser is left on the first value in the configuration. function Section (Self : Config_Parser) return String is abstract; function Key (Self : Config_Parser) return String is abstract; function Value (Self : Config_Parser) return String is abstract; -- Return the current (section, key, value); procedure Set_System_Id (Self : in out Config_Parser; System_ID : String); -- Sets the system ID for the config. -- If the config is found in a file, this should be the absolute path name -- to that file. This will generally be called automatically when opening -- the file. -- This system id is used to resolve absolute file names. function As_Integer (Self : Config_Parser) return Integer; function As_Boolean (Self : Config_Parser) return Boolean; function As_Absolute_File (Self : Config_Parser) return String; function As_Absolute_Dir (Self : Config_Parser) return String; -- Assuming the current value is a file or directory, converts it to an -- absolute name, where relative paths are resolved relative to the -- config's system_id. -- These will raise Constraint_Error if used on non-matching values. ----------------- -- File config -- ----------------- type File_Config_Parser is abstract new Config_Parser with private; -- A special implementation for config streams based on actual files procedure Open (Self : in out File_Config_Parser; Filename : String); -- Open a file overriding function At_End (Self : File_Config_Parser) return Boolean; --------------- -- INI files -- --------------- type INI_Parser is new File_Config_Parser with private; -- a special parser for Windows' .ini files procedure Configure (Self : in out INI_Parser; Comment_Start : String := "#"; Handles_Sections : Boolean := True; Home : String := ""); -- "Home" is the substitution pattern for "HOME" in the values. If -- unspecified, it is computed automatically. overriding procedure Open (Self : in out INI_Parser; Filename : String); overriding procedure Next (Self : in out INI_Parser); overriding function Section (Self : INI_Parser) return String; overriding function Key (Self : INI_Parser) return String; overriding function Value (Self : INI_Parser) return String; ------------------- -- Resource pool -- ------------------- type Config_Pool is tagged private; -- This type provides storage for a config file procedure Set_System_Id (Self : in out Config_Pool; System_ID : String); -- Set the absolute name used to resolve file names in Get_File procedure Fill (Self : in out Config_Pool; Config : in out Config_Parser'Class); -- Load all keys from Config, and store the (key, value) pairs in Self. -- Multiple files can be merged into the same pool. -- Set_System_Id is automatically called, thus file names will be resolved -- relative to the last Config loaded in the pool. Section_From_Key : constant String; -- Indicates that the section should in fact be read from the key (as -- opposed to being specified separately). In this case, the key is split -- at the first "." (if there is none, the section name is empty). -- For instance: "section1.key1" or "section1.key2". -- -- It is often more convenient to specify the section that way, in exchange -- for a small performance penalty and a possible ambiguity if the key -- itself contains a ".", which is not recommended. Whole_Value : constant Natural := 0; function Get (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Index : Natural := Whole_Value) return String; -- Return the value associated with Key. -- Index is used for comma-separated lists of values, and will retrieve -- one of the specific elements of the list. The whole value (no splitting) -- is returned if Index is Whole_Value. The empty string is returned if -- there is no such item in the list function Get_Integer (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Index : Natural := Whole_Value) return Integer; function Get_Boolean (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Index : Natural := Whole_Value) return Boolean; function Get_File (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Index : Natural := Whole_Value) return String; -- Same as above, but returns an absolute filename. Relative paths are -- resolved relative to the config location where Key was declared. function To_File (Self : Config_Pool; Key : String; Section : String := Section_From_Key; Value : String) return GNATCOLL.VFS.Virtual_File; -- Converts value to a file. It is relative to the location of the config -- file that provided Key. This is similar to calling Get_File directly, -- but is useful in contexts where you need to first manipulate the value -- read from the config and then interpret it as a file. procedure Set (Self : in out Config_Pool; Section, Key, Value : String); -- Override a specific key -------------------------------- -- Resource pool, static keys -- -------------------------------- type Config_Key is tagged private; function Create (Key : String; Section : String := "") return Config_Key; -- Create a new config key function Get (Self : Config_Key; Conf : Config_Pool'Class; Index : Natural := Whole_Value) return String; function Get_Integer (Self : Config_Key; Conf : Config_Pool'Class; Index : Natural := Whole_Value) return Integer; function Get_Boolean (Self : Config_Key; Conf : Config_Pool'Class; Index : Natural := Whole_Value) return Boolean; function Get_File (Self : Config_Key; Conf : Config_Pool'Class; Index : Natural := Whole_Value) return String; function To_File (Self : Config_Key; Conf : Config_Pool'Class; Value : String) return GNATCOLL.VFS.Virtual_File; -- Read the key from the configuration. -- Using this API might help ensure that you are always accessing existing -- keys. In this case, you would have a global package that defines all -- valid keys: -- -- Key1 : constant Config_Key := Create ("..."); -- Key2 : constant Config_Key := Create ("..."); -- -- Then your coding standard should specify that you can only access the -- configuration via those keys: -- -- Put_Line (Key1.Get); -- -- There is therefore no possible typo in the name of the key, and if you -- rename the key in the configuration file, you have a single place to -- change. private Section_From_Key : constant String := "="; -- Choose = as special name as it cannot appears in a section name. type Config_Parser is abstract tagged record System_ID : Strings.XString; end record; type File_Config_Parser is abstract new Config_Parser with record Contents : Strings.XString; First : Integer := Integer'Last; end record; type INI_Parser is new File_Config_Parser with record Equal, Eol : Integer; Current_Section : Strings.XString; Comment_Start : Strings.XString := Strings.To_XString ("#"); Use_Sections : Boolean := True; Home : VFS.Virtual_File := VFS.Get_Home_Directory; end record; type Config_Value (Len : Natural) is record System_ID : Strings.XString; Value : String (1 .. Len); end record; package String_Maps is new Ada.Containers.Indefinite_Hashed_Maps (Key_Type => String, -- "section=key" Element_Type => Config_Value, Hash => Ada.Strings.Hash, Equivalent_Keys => "=", "=" => "="); type Config_Key is tagged record Section, Key : Strings.XString; end record; type Config_Pool is tagged record System_ID : Strings.XString; Keys : String_Maps.Map; end record; end GNATCOLL.Config; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-email-mailboxes.adb000066400000000000000000000723041425465243200244340ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Calendar; use Ada.Calendar; with Ada.Containers.Indefinite_Hashed_Maps; with Ada.IO_Exceptions; with Ada.Strings.Hash; with Ada.Unchecked_Deallocation; with GNATCOLL.Boyer_Moore; use GNATCOLL.Boyer_Moore; with GNATCOLL.Email.Parser; use GNATCOLL.Email.Parser; with GNATCOLL.Email.Utils; use GNATCOLL.Email.Utils; with GNATCOLL.Mmap; use GNATCOLL.Mmap; with GNATCOLL.VFS; use GNATCOLL.VFS; with GNAT.Strings; use GNAT.Strings; package body GNATCOLL.Email.Mailboxes is use Message_Info_List, Cursor_List; From_Pattern : GNATCOLL.Boyer_Moore.Pattern; -- An efficient search pattern for the From_ lines that separate messages -- in a mbox procedure Internal_Search_Start (Self : Mbox'Class; Buffer : String; From : in out Integer); -- Search the start of the next message after the position From. -- It should return -1 if no further message exists. -- This is for the implementation of new mailbox types only, and is not -- needed when using standard mailboxes. function Earlier_Than (Left, Right : Abstract_Message_Info'Class) return Boolean; -- Compare two elements by date type Container; type Container_Access is access Container; type Container is record Msg : Message; Parent : Container_Access; Child : Container_Access; Next : Container_Access; end record; package Container_Hash is new Ada.Containers.Indefinite_Hashed_Maps (Key_Type => String, Element_Type => Container_Access, Hash => Ada.Strings.Hash, Equivalent_Keys => "="); use Container_Hash; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Container, Container_Access); ------------------ -- Earlier_Than -- ------------------ function Earlier_Than (Left, Right : Abstract_Message_Info'Class) return Boolean is Date1 : constant Time := Get_Date (Left.Msg); Date2 : constant Time := Get_Date (Right.Msg); begin return Date1 < Date2; end Earlier_Than; package Pkg_Sort_By_Date is new Message_Info_List.Generic_Sorting ("<" => Earlier_Than); ----------------- -- Free_String -- ----------------- procedure Free_String (Str : in out GNAT.Strings.String_Access) is begin GNAT.Strings.Free (Str); end Free_String; ---------------- -- Set_Parser -- ---------------- procedure Set_Parser (Self : in out Cursor; Factory : Message_Factory := Email.Parser.Parse'Access) is begin Self.Factory := Factory; end Set_Parser; ---------- -- Open -- ---------- procedure Open (Self : in out Mbox; Fp : access String; On_Close : Destructor := Free_String'Access) is begin Self.Fp := GNAT.Strings.String_Access (Fp); Self.On_Close := On_Close; end Open; ---------- -- Open -- ---------- procedure Open (Self : in out Mbox; Filename : Virtual_File) is begin Self.Fp := Read_File (Filename); Self.On_Close := Free_String'Access; if Self.Fp = null then raise Ada.IO_Exceptions.Name_Error with Filename.Display_Full_Name; end if; end Open; ----------- -- First -- ----------- function First (Self : Mbox) return Cursor'Class is begin declare Cur : Cursor'Class := Mbox_Cursor' (Cursor with Max => Self.Fp'Last, Start => Self.Fp'First, Stop => 0, Current => Null_Message); begin Next (Cur, Self); return Cur; end; end First; ----------------- -- Has_Element -- ----------------- function Has_Element (Self : Mbox_Cursor) return Boolean is begin return Self.Stop <= Self.Max; end Has_Element; ----------------- -- Get_Message -- ----------------- procedure Get_Message (Self : in out Mbox_Cursor; Box : Mailbox'Class; Msg : out Message) is Buffer : Str_Access; begin -- Already cached ? if Self.Current /= Null_Message then Msg := Self.Current; -- Already past the end ? elsif Self.Stop > Self.Max or else Self.Factory = null then Msg := Null_Message; else if Mbox (Box).Fp /= null then Buffer := GNATCOLL.Mmap.Short.To_Str_Access (Mbox (Box).Fp); end if; Self.Factory (String (Buffer (Self.Start .. Self.Stop)), Self.Current); Msg := Self.Current; end if; end Get_Message; ---------- -- Next -- ---------- procedure Next (Self : in out Mbox_Cursor; Box : Mailbox'Class) is Buffer : Str_Access; First : Integer; Skip_Separating_Newline : constant Integer := 2; -- Number of characters to move backward from a "From_" substring to -- find the end of the previous message. This includes skipping over the -- newline character that must separate messages. begin Self.Current := Null_Message; -- Already past the end ? if Self.Stop >= Self.Max then Self.Stop := Self.Max + 1; return; end if; if Mbox (Box).Fp /= null then Buffer := GNATCOLL.Mmap.Short.To_Str_Access (Mbox (Box).Fp); First := Mbox (Box).Fp'First; else return; -- Nothing to parse end if; -- Find start of first message if needed. If we are past this first -- message, we know we left the pointer to the start of a message, no -- need to check again. if Self.Stop = 0 then if String (Buffer (First .. 5)) /= "From " then Self.Stop := First; Internal_Search_Start (Mbox'Class (Box), String (Buffer (First .. Self.Max)), Self.Stop); if Self.Stop = -1 then Self.Stop := Integer'Last; Self.Current := Null_Message; return; else Self.Stop := Self.Stop - Skip_Separating_Newline; end if; else Self.Stop := First - Skip_Separating_Newline; end if; end if; -- At this point Self.Stop points to the first character before the -- beginning of the next message if Self.Stop >= Self.Max then return; end if; Self.Start := Self.Stop + Skip_Separating_Newline; -- Search end of message -- Skip current From_ line Self.Stop := Self.Start + 5; -- "From_"'Length Internal_Search_Start (Mbox'Class (Box), String (Buffer (Self.Stop .. Self.Max)), Self.Stop); if Self.Stop < 0 then -- No message after this one => it extends till the end of the buffer Self.Stop := Self.Max; else Self.Stop := Self.Stop - Skip_Separating_Newline; end if; end Next; --------------------------- -- Internal_Search_Start -- --------------------------- procedure Internal_Search_Start (Self : Mbox'Class; Buffer : String; From : in out Integer) is pragma Unreferenced (Self); begin -- Note: we used to treat a From_ line that does not contain a colon -- as part of the message body. This was not the intent of the code, -- and in any case was a questionable heuristic, since all From_ lines -- in bodies should really be assumed to have been escaped as >From_. -- So, we now just search for From_ at beginning of line. -- put in place a heuristic From := Search (From_Pattern, Buffer (From .. Buffer'Last)); if From /= -1 then -- Match present: skip initial ASCII.LF From := From + 1; end if; end Internal_Search_Start; -------------- -- Finalize -- -------------- procedure Finalize (Self : in out Mailbox) is pragma Unreferenced (Self); begin null; end Finalize; -------------- -- Finalize -- -------------- procedure Finalize (Self : in out Mbox) is begin if Self.On_Close /= null and then Self.Fp /= null then Self.On_Close (Self.Fp); Self.Fp := null; end if; end Finalize; ----------- -- Store -- ----------- procedure Store (Self : out Stored_Mailbox; Box : in out Mailbox'Class; Factory : Message_Factory := Email.Parser.Parse'Access) is begin Store (Self, Box, Factory, First (Box)); end Store; ----------- -- Store -- ----------- procedure Store (Self : out Stored_Mailbox; Box : in out Mailbox'Class; Factory : Message_Factory := Email.Parser.Parse'Access; From : Cursor'Class) is Msg : Message; Curs : Cursor'Class := From; begin Set_Parser (Curs, Factory); while Has_Element (Curs) loop Get_Message (Curs, Box, Msg); if Msg /= Null_Message then Append (Self, Msg); end if; Next (Curs, Box); end loop; end Store; ------------ -- Append -- ------------ procedure Append (Self : in out Stored_Mailbox; Msg : Message) is begin Append (Self.Messages, Message_Info'(Msg => Msg, Children => Message_Info_List.Empty_List)); Self.Sorted_By := Sort_None; end Append; ----------- -- First -- ----------- function First (Self : Stored_Mailbox) return Cursor'Class is begin return First (Self, Recurse => False); end First; ----------- -- First -- ----------- function First (Self : Stored_Mailbox; Recurse : Boolean) return Stored_Mailbox_Cursor'Class is L : Stored_Mailbox_Cursor; begin L.Recurse := Recurse; L.Thread_Level := 1; if not Is_Empty (Self.Messages) then Append (L.Cursors, First (Self.Messages)); end if; return L; end First; --------------------- -- First_In_Thread -- --------------------- function First_In_Thread (Self : Stored_Mailbox; Parent : Stored_Mailbox_Cursor'Class) return Stored_Mailbox_Cursor'Class is L : Stored_Mailbox_Cursor; procedure Get_First (M : Abstract_Message_Info'Class); procedure Get_First (M : Abstract_Message_Info'Class) is begin if Has_Element (First (Message_Info (M).Children)) then Append (L.Cursors, First (Message_Info (M).Children)); else L.Cursors := Cursor_List.Empty_List; end if; end Get_First; begin if Self.Threaded and then not Is_Empty (Parent.Cursors) and then Has_Element (Element (Last (Parent.Cursors))) then L.Recurse := False; L.Thread_Level := Parent.Thread_Level + 1; Query_Element (Element (Last (Parent.Cursors)), Get_First'Unrestricted_Access); return L; else L.Cursors := Cursor_List.Empty_List; return L; end if; end First_In_Thread; ----------------- -- Has_Element -- ----------------- function Has_Element (Self : Stored_Mailbox_Cursor) return Boolean is begin return not Is_Empty (Self.Cursors); end Has_Element; ----------------- -- Get_Message -- ----------------- procedure Get_Message (Self : in out Stored_Mailbox_Cursor; Box : Mailbox'Class; Msg : out Message) is pragma Unreferenced (Box); Saved : Message_Info_List.Cursor; begin if Is_Empty (Self.Cursors) then Msg := Null_Message; else Saved := Element (Last (Self.Cursors)); Msg := Message_Info (Element (Saved)).Msg; end if; end Get_Message; ---------------------- -- Get_Thread_Level -- ---------------------- function Get_Thread_Level (Iter : Stored_Mailbox_Cursor) return Positive is begin if Is_Empty (Iter.Cursors) then return 1; else return Iter.Thread_Level; end if; end Get_Thread_Level; ---------- -- Next -- ---------- procedure Next (Self : in out Stored_Mailbox_Cursor; Box : Mailbox'Class) is pragma Unreferenced (Box); M : Message_Info; Saved : Message_Info_List.Cursor; procedure Move_To_Next (C : in out Message_Info_List.Cursor); procedure Move_To_Next (C : in out Message_Info_List.Cursor) is begin Next (C); end Move_To_Next; begin if not Is_Empty (Self.Cursors) then Saved := Element (Last (Self.Cursors)); M := Message_Info (Element (Saved)); -- If we have children for the current element, return these next if Self.Recurse and then not Is_Empty (M.Children) then declare procedure Get_First (M : Abstract_Message_Info'Class); procedure Get_First (M : Abstract_Message_Info'Class) is begin Append (Self.Cursors, First (Message_Info (M).Children)); end Get_First; begin Self.Thread_Level := Self.Thread_Level + 1; Query_Element (Saved, Get_First'Unrestricted_Access); end; else -- Otherwise move to the next element at the same level if there's -- one. Or move to the next element at the parent level, -- recursively Update_Element (Self.Cursors, Last (Self.Cursors), Move_To_Next'Unrestricted_Access); if Self.Recurse then while not Has_Element (Element (Last (Self.Cursors))) loop -- Else move to the next element at the parent level, -- recursively Delete_Last (Self.Cursors); exit when Is_Empty (Self.Cursors); Self.Thread_Level := Self.Thread_Level - 1; Update_Element (Self.Cursors, Last (Self.Cursors), Move_To_Next'Unrestricted_Access); end loop; elsif not Has_Element (Element (Last (Self.Cursors))) then Self.Cursors := Cursor_List.Empty_List; end if; end if; end if; end Next; -------------------- -- Remove_Threads -- -------------------- procedure Remove_Threads (Stored : in out Stored_Mailbox) is begin if Stored.Threaded then declare Iter : Stored_Mailbox_Cursor'Class := First (Stored, Recurse => True); Tmp : Message_Info_List.List; Msg : Message; begin while Has_Element (Iter) loop Get_Message (Iter, Stored, Msg); if Msg /= Null_Message then Append (Tmp, Message_Info'(Msg => Msg, Children => Message_Info_List.Empty_List)); end if; Next (Iter, Stored); end loop; Move (Target => Stored.Messages, Source => Tmp); Stored.Threaded := False; Stored.Sorted_By := Sort_None; end; end if; end Remove_Threads; ------------------ -- Sort_By_Date -- ------------------ procedure Sort_By_Date (Self : in out Stored_Mailbox) is procedure Sort_Level (List : in out Message_Info_List.List); procedure Sort_Info (Info : in out Abstract_Message_Info'Class); -- Sort List, and all children procedure Sort_Info (Info : in out Abstract_Message_Info'Class) is begin Sort_Level (Message_Info (Info).Children); end Sort_Info; procedure Sort_Level (List : in out Message_Info_List.List) is C : Message_Info_List.Cursor; begin Pkg_Sort_By_Date.Sort (List); C := First (List); while Has_Element (C) loop if not Is_Empty (Message_Info (Element (C)).Children) then Update_Element (List, C, Sort_Info'Unrestricted_Access); end if; Next (C); end loop; end Sort_Level; begin if Self.Sorted_By /= Sort_Date then if Self.Threaded then Sort_Level (Self.Messages); else Pkg_Sort_By_Date.Sort (Self.Messages); end if; Self.Sorted_By := Sort_Date; end if; end Sort_By_Date; --------------------- -- Thread_Messages -- --------------------- procedure Thread_Messages (Self : in out Stored_Mailbox) is Ids : Container_Hash.Map; procedure Store_Parent_Of (Parent_Cont : in out Container_Access; Id : String); -- Memorize that Parent_Cont is the parent of the message whose -- Message-ID is Id. -- On exit, Parent_Cont is set to the container used for the message -- itself. procedure Set_Parent_For_All_Ids (Parent_Cont : in out Container_Access; H : Header); -- For each message-id found in H, call Store_Parent_Of. This -- sets a list of dependencies between mail messages. procedure Set_Parent_Of (Cont : Container_Access; Parent_Cont : Container_Access; Override : Boolean := False); -- Set the parent of Cont to be Parent_Cont. -- If Cont already has a parent and Override is True, it is replaced. -- This is only needed when processing the last item in the References: -- field, which we know is the real parent. Previous parents might have -- been set while processing References: fields in other messages. -- This also update child links procedure Put_Threads_In_Message (Parent : in out Message_Info_List.List; Root : Container_Access; Root_Level : Boolean); -- Put Root in Parent, and all its children recursively function Is_Reachable (A, B : Container_Access) return Boolean; -- Return True if B is part of the descendant of A. This doesn't test -- that A /= B. ------------------ -- Is_Reachable -- ------------------ function Is_Reachable (A, B : Container_Access) return Boolean is C : Container_Access := A.Child; C2 : Container_Access; begin if A = B then return True; end if; while C /= null loop if C = B then return True; end if; C2 := C.Child; while C2 /= null loop if Is_Reachable (C2, B) then return True; end if; C2 := C2.Next; end loop; C := C.Next; end loop; return False; end Is_Reachable; ------------------- -- Set_Parent_Of -- ------------------- procedure Set_Parent_Of (Cont : Container_Access; Parent_Cont : Container_Access; Override : Boolean := False) is C : Container_Access; begin if Parent_Cont = null or else Parent_Cont = Cont then return; end if; if Cont.Parent /= null and then not Override then return; end if; -- Check we do not introduce a loop A -> B -> A. This must be done -- before removing the old parent if Is_Reachable (Cont, Parent_Cont) or else Is_Reachable (Parent_Cont, Cont) then return; end if; -- Set the new parent (remove the old one, since if we reach here -- with an old parent, we are in Override mode) if Cont.Parent /= null then if Cont.Parent.Child = Cont then Cont.Parent.Child := Cont.Next; else C := Cont.Parent.Child; while C.Next /= null loop if C.Next = Cont then C.Next := Cont.Next; exit; end if; C := C.Next; end loop; end if; Cont.Parent := null; Cont.Next := null; end if; Cont.Parent := Parent_Cont; if Parent_Cont /= null then if Parent_Cont.Child = null then Parent_Cont.Child := Cont; else C := Parent_Cont.Child; while C.Next /= null loop C := C.Next; end loop; C.Next := Cont; end if; end if; Cont.Next := null; end Set_Parent_Of; --------------------- -- Store_Parent_Of -- --------------------- procedure Store_Parent_Of (Parent_Cont : in out Container_Access; Id : String) is Id_C : Container_Hash.Cursor; Cont : Container_Access; begin Id_C := Find (Ids, Id); if Has_Element (Id_C) then Cont := Element (Id_C); else Cont := new Container; -- Null_Message; Insert (Ids, Id, Cont); end if; if Parent_Cont /= null and then Cont.Parent = null then Set_Parent_Of (Cont => Cont, Parent_Cont => Parent_Cont); end if; Parent_Cont := Cont; end Store_Parent_Of; ---------------------------- -- Set_Parent_For_All_Ids -- ---------------------------- procedure Set_Parent_For_All_Ids (Parent_Cont : in out Container_Access; H : Header) is Flat : Unbounded_String; Index : Natural; Stop : Natural; begin if H /= Null_Header then Flatten (Get_Value (H), Flat); declare StrA : constant String := To_String (Flat); begin Index := StrA'First; while Index <= StrA'Last loop Index := Next_Occurrence (StrA (Index .. StrA'Last), '<'); Stop := Next_Occurrence (StrA (Index + 1 .. StrA'Last), '>'); Store_Parent_Of (Parent_Cont => Parent_Cont, Id => StrA (Index + 1 .. Stop - 1)); Index := Stop + 1; end loop; end; end if; end Set_Parent_For_All_Ids; ---------------------------- -- Put_Threads_In_Message -- ---------------------------- procedure Put_Threads_In_Message (Parent : in out Message_Info_List.List; Root : Container_Access; Root_Level : Boolean) is C : Container_Access; M : Message_Info; begin -- Do not insert dummy containers if Root.Msg = Null_Message then if Root.Child = null then return; end if; -- Promote the children one level up C := Root.Child; while C /= null loop Put_Threads_In_Message (Parent, C, Root_Level); C := C.Next; end loop; return; else M.Msg := Root.Msg; Append (Parent, M); C := Root.Child; end if; while C /= null loop declare procedure Add_Child (MI : in out Abstract_Message_Info'Class); procedure Add_Child (MI : in out Abstract_Message_Info'Class) is begin Put_Threads_In_Message (Message_Info (MI).Children, C, False); end Add_Child; begin Update_Element (Parent, Last (Parent), Add_Child'Unrestricted_Access); end; C := C.Next; end loop; end Put_Threads_In_Message; C : Message_Info_List.Cursor; Msg : Message; Msg_Cont : Container_Access; Parent_Cont : Container_Access; Id_C : Container_Hash.Cursor; Dummy_Id : Natural := 0; -- For those messages that have no Message-Id: field, so that we don't -- lose any... begin -- See algorithm at http://www.jwz.org/doc/threading.html if not Self.Threaded then C := First (Self.Messages); while Has_Element (C) loop Msg := Element (C).Msg; -- Store a new container for this message-id in the table declare Id : constant String := Get_Message_Id (Msg); begin Msg_Cont := null; Store_Parent_Of (Parent_Cont => Msg_Cont, Id => Id); -- If there was already such a message-id (in theory not -- possible, in practice we might have messages with no -- Message-Id: header, and we still want to keep all messages. -- We create a dummy, unique, invalid ID containing a space. while Msg_Cont.Msg /= Null_Message loop Msg_Cont := null; Store_Parent_Of (Parent_Cont => Msg_Cont, Id => Id & Integer'Image (Dummy_Id)); Dummy_Id := Dummy_Id + 1; end loop; end; Msg_Cont.Msg := Element (C).Msg; -- For each of the References: id: Parent_Cont := null; Set_Parent_For_All_Ids (Parent_Cont => Parent_Cont, H => Get_Header (Msg, "References")); -- Take into account the In-Reply-To field. In most cases, this -- should duplicate the last element of References:, but some -- mailers do not behave correctly, so it doesn't harm to -- do the work again Set_Parent_For_All_Ids (Parent_Cont => Parent_Cont, H => Get_Header (Msg, "In-Reply-To")); Set_Parent_Of (Msg_Cont, Parent_Cont => Parent_Cont, Override => True); Next (C); end loop; -- Prune empty containers. These come from invalid references in -- the headers -- ??? Nothing do do in fact, we'll just ignore these when putting -- messages back in Self.Messages. -- We would also promote the child of empty containers with one child -- and no parent to the root set. -- Find all elements of the root set -- ??? Not needed, we do it when we put messages back in -- Self.Messages -- Sort messages by Subject, to find additional threads -- ??? Disabled for now Clear (Self.Messages); Id_C := First (Ids); while Has_Element (Id_C) loop if Element (Id_C).Parent = null then Put_Threads_In_Message (Parent => Self.Messages, Root => Element (Id_C), Root_Level => True); end if; Next (Id_C); end loop; -- Free memory Id_C := First (Ids); while Has_Element (Id_C) loop Msg_Cont := Element (Id_C); Unchecked_Free (Msg_Cont); Next (Id_C); end loop; Self.Threaded := True; case Self.Sorted_By is when Sort_None => null; when Sort_Date => Self.Sorted_By := Sort_None; Sort_By_Date (Self); end case; end if; end Thread_Messages; ----------------- -- Is_Threaded -- ----------------- function Is_Threaded (Self : Stored_Mailbox) return Boolean is begin return Self.Threaded; end Is_Threaded; begin -- Can't include two ASCII.LF, since officially mboxes should even use -- ASCII.CR & ASCII.LF, although most don't Compile (From_Pattern, ASCII.LF & "From "); end GNATCOLL.Email.Mailboxes; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-email-mailboxes.ads000066400000000000000000000302551425465243200244540ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package handles mailboxes that contain one or more email messages with Ada.Containers.Indefinite_Doubly_Linked_Lists; with Ada.Containers.Doubly_Linked_Lists; with Ada.Finalization; with GNATCOLL.Email.Parser; with GNAT.Strings; with GNATCOLL.VFS; package GNATCOLL.Email.Mailboxes is -- ??? Would be nice to have a function to write back a message in a -- mailbox (with proper message separators). --------------- -- Mailboxes -- --------------- type Mailbox is abstract tagged limited private; -- This type describes a mailbox, which contains several email messages in -- some defined format. See the children of this type for the various -- supported formats. -- This mailbox can be iterated: to get all messages, you would do the -- following: -- Box : Mbox; -- -- Open (Box, File_Contents) -- -- Curs : Cursor'Class := First (Box); -- while Has_Element (Curs) loop -- Get_Message (Curs, Box, Msg); -- if Msg /= Null_Message then -- -- test above is in case of parsing error -- ... -- Next (Curs, Box); -- end loop; type Message_Factory is access procedure (Str : String; Msg : out Message); -- Builds a message from a string. It should return Null_Message if the -- message could not be parsed. -- You can provide a different function if you simply want to get the text -- of all messages (for instance for a search function), and do not need to -- waste time actually parsing the message. type Cursor is abstract tagged private; -- An iterator over the contents of a mailbox function First (Self : Mailbox) return Cursor'Class is abstract; -- Return a cursor to iterator over all messages of the mailbox procedure Set_Parser (Self : in out Cursor; Factory : Message_Factory := Email.Parser.Parse'Access); -- Set the factory used to create the messages parsed from the mailbox. -- It can be used to limit which fields should be parsed, whether the body -- should be returned,... function Has_Element (Self : Cursor) return Boolean is abstract; -- True if Self points to a message in the mailbox, False if past the last -- message. procedure Get_Message (Self : in out Cursor; Box : Mailbox'Class; Msg : out Message) is abstract; -- Return the current message. -- If there is no such message or the message could not be parsed, returns -- Null_Message. -- The message is generated from the text representing the mailbox by -- calling the factory. procedure Next (Self : in out Cursor; Box : Mailbox'Class) is abstract; -- Moves to the next message in Self -------------------- -- Unix mailboxes -- -------------------- type Mbox is new Mailbox with private; -- This type describes a mail box in the traditional format used by Unix -- systems. Messages are appended one after another, separated by a blank -- line and a line starting with "From ". overriding function First (Self : Mbox) return Cursor'Class; -- Return an instance of Mbox_Cursor type Destructor is access procedure (S : in out GNAT.Strings.String_Access); -- Free the memory associated with the "Fp" parameter given to Open procedure Free_String (Str : in out GNAT.Strings.String_Access); procedure Open (Self : in out Mbox; Fp : access String; On_Close : Destructor := Free_String'Access); -- Initializes the internal data for the mailbox. This procedure must be -- called by the various *Open functions below, but doesn't need to be -- called by the user. -- No copy of Fp is made. On_Close (if defined) is called when the mbox no -- longer needs access to Fp. As a result, you can either give control over -- Fp to the mailbox (and leave the default value for On_Close), or keep -- control of the string, and pass null to On_Close. procedure Open (Self : in out Mbox; Filename : GNATCOLL.VFS.Virtual_File); -- Same as Open, but takes care of opening the file. -- If the file could not be open, Name_Error is raised. type Mbox_Cursor is new Cursor with private; overriding function Has_Element (Self : Mbox_Cursor) return Boolean; overriding procedure Next (Self : in out Mbox_Cursor; Box : Mailbox'Class); overriding procedure Get_Message (Self : in out Mbox_Cursor; Box : Mailbox'Class; Msg : out Message); -- See inherited documentation ------------------------- -- In-Memory mailboxes -- ------------------------- type Stored_Mailbox is new Mailbox with private; -- This type represents the contents of a mailbox in memory. All messages -- that are part of a file mailbox are read and kept in memory. This -- provides a convenient way to keep messages in memory while they are in -- use, and in particular provides ways to sort them. -- This type is limited since it would be costly to copy instances of a -- mailbox otherwise (duplicating all messages in memory). procedure Store (Self : out Stored_Mailbox; Box : in out Mailbox'Class; Factory : Message_Factory := Email.Parser.Parse'Access); procedure Store (Self : out Stored_Mailbox; Box : in out Mailbox'Class; Factory : Message_Factory := Email.Parser.Parse'Access; From : Cursor'Class); -- Parse a mailbox and store all its messages in memory. -- All messages previously in Self are kept. -- Box must already have been Open'ed. -- The second version allows you to skip messages if needed procedure Append (Self : in out Stored_Mailbox; Msg : Message); -- Appends a new message to Self. The current sorting order is not -- preserved, and you should call Sort_* again after you have added one or -- more messages. procedure Thread_Messages (Self : in out Stored_Mailbox); -- Sort all messages in Self by threads. This preserves the sort order. -- This does nothing if Self is already threaded. procedure Remove_Threads (Stored : in out Stored_Mailbox); -- Removing all threading information from Stored. The mailbox is no -- longer sorted as a result. function Is_Threaded (Self : Stored_Mailbox) return Boolean; -- Whether Self is sorted by threads procedure Sort_By_Date (Self : in out Stored_Mailbox); -- Sort all messages by Date. This preserves threading information if -- available. type Stored_Mailbox_Cursor is new Cursor with private; -- Iterate over the contents of a mailbox overriding function First (Self : Stored_Mailbox) return Cursor'Class; function First (Self : Stored_Mailbox; Recurse : Boolean) return Stored_Mailbox_Cursor'Class; -- Starts iteration over all elements in Self, in the order they were -- sorted. -- If Recurse is False and messages have been sorted by threads, this will -- only iterate over the root message of each thread. Use First_In_Thread -- to iterate recursively over each thread. Traversal is depth-first. -- If Recurse is True, then all messages will eventually be returned. -- The iterator becomes invalid when you call one of the Sort_* functions. -- The first version of First returns a cursor that iterates not -- recursively. function First_In_Thread (Self : Stored_Mailbox; Parent : Stored_Mailbox_Cursor'Class) return Stored_Mailbox_Cursor'Class; -- Return the first child of Msg in its thread. If the threads are -- organized as: -- Msg1 (thread level 1) -- |_ Msg1.1 (thread level 2) -- |_ Msg1.1.1 (thread level 3) -- |_ Msg1.2 (thread level 2) -- Msg2 (thread level 1); -- and Msg1 is passed in argument, then the iterator will return -- Msg1.1 and Msg1.2, not Msg1.1.1 nor Msg2. -- This function always returns an empty iterator if the mailbox is not -- sorted by threads. overriding procedure Next (Self : in out Stored_Mailbox_Cursor; Box : Mailbox'Class); -- See inherited documentation overriding procedure Get_Message (Self : in out Stored_Mailbox_Cursor; Box : Mailbox'Class; Msg : out Message); function Get_Thread_Level (Iter : Stored_Mailbox_Cursor) return Positive; -- Return the current message in the mailbox, or Null_Message if there are -- no more messages. See the small drawing above for the meaning of -- Thread_Level. If the mailbox has not been sorted by threads, the level -- is always 1. overriding function Has_Element (Self : Stored_Mailbox_Cursor) return Boolean; -- Whether calling Next on Iter will return a Message private type Mailbox is abstract new Ada.Finalization.Limited_Controlled with record null; end record; type Cursor is abstract tagged record Factory : Message_Factory := Email.Parser.Parse'Access; end record; type Mbox_Cursor is new Cursor with record Start, Stop : Integer; Max : Integer; Current : Message; -- Cache the current message end record; procedure Finalize (Self : in out Mailbox); pragma Finalize_Storage_Only (Mailbox); type Mbox is new Mailbox with record Fp : GNAT.Strings.String_Access; On_Close : Destructor; Previous_Line_Empty : Boolean := True; end record; overriding procedure Finalize (Self : in out Mbox); -- See inherited documentation type Abstract_Message_Info is abstract tagged record Msg : Message; end record; package Message_Info_List is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Abstract_Message_Info'Class); type Message_Info is new Abstract_Message_Info with record Children : Message_Info_List.List; end record; type Sort_Order is (Sort_None, Sort_Date); type Stored_Mailbox is new Mailbox with record Messages : Message_Info_List.List; -- Contains Message_Info Sorted_By : Sort_Order := Sort_None; Threaded : Boolean := False; end record; package Cursor_List is new Ada.Containers.Doubly_Linked_Lists (Message_Info_List.Cursor, Message_Info_List."="); type Stored_Mailbox_Cursor is new Cursor with record Cursors : Cursor_List.List; Recurse : Boolean; Thread_Level : Integer; end record; -- If the specified thread level is 0, all messages are returned. -- Otherwise, only the messages at the right level. end GNATCOLL.Email.Mailboxes; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-email-parser.adb000066400000000000000000000317111425465243200237420ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ pragma Warnings (Off, "*internal GNAT unit*"); with Ada.Strings.Unbounded.Aux; pragma Warnings (On, "*internal GNAT unit*"); with GNAT.Case_Util; use GNAT.Case_Util; with GNATCOLL.VFS; use GNATCOLL.VFS; with GNAT.Strings; use GNAT.Strings; package body GNATCOLL.Email.Parser is function Preserve_Header (Name : String) return Boolean; pragma Inline (Preserve_Header); -- Whether the given header should be preserved in the generated message procedure Parse_Payload (Msg : in out Message; Unparsed : String); -- Parse the payload, as read in Unparsed, into its various components, -- and store them in the message appropriately --------------------- -- Preserve_Header -- --------------------- function Preserve_Header (Name : String) return Boolean is N : String := Name; begin To_Lower (N); case N (N'First) is when 'c' => return N = "cc" or else N = "content-type"; when 'd' => return N = "date"; when 'f' => return N = "from"; when 'i' => return N = "in-reply-to"; when 'm' => return N = "message-id" or else N = "mime-version"; when 'r' => return N = "references" or else N = "reply-to"; when 's' => return N = "subject"; when 't' => return N = "to"; when 'x' => return True; -- All X-* headers when others => return False; end case; end Preserve_Header; ----------- -- Parse -- ----------- procedure Parse (Str : String; Msg : out Message) is begin Full_Parse (Str, Msg, Store_Headers => True, Store_Payload => True, Parse_Payload => True); end Parse; -------------------------- -- Parse_Ignore_Headers -- -------------------------- procedure Parse_Ignore_Headers (Str : String; Msg : out Message) is begin Full_Parse (Str, Msg, Store_Headers => False, Store_Payload => True, Parse_Payload => False); end Parse_Ignore_Headers; --------------------------- -- Parse_Minimal_Headers -- --------------------------- procedure Parse_Minimal_Headers (Str : String; Msg : out Message) is begin Full_Parse (Str, Msg, Store_Headers => True, Store_Payload => True, Parse_Payload => True, Filter => Preserve_Header'Access); end Parse_Minimal_Headers; ---------------------- -- Parse_No_Payload -- ---------------------- procedure Parse_No_Payload (Str : String; Msg : out Message) is begin Full_Parse (Str, Msg, Store_Headers => True, Store_Payload => True, Parse_Payload => False); end Parse_No_Payload; -------------------------------------- -- Parse_No_Payload_Minimal_Headers -- -------------------------------------- procedure Parse_No_Payload_Minimal_Headers (Str : String; Msg : out Message) is begin Full_Parse (Str, Msg, Store_Headers => True, Store_Payload => True, Parse_Payload => False, Filter => Preserve_Header'Access); end Parse_No_Payload_Minimal_Headers; ---------------- -- Full_Parse -- ---------------- procedure Full_Parse (Str : String; Msg : out Message; Store_Headers : Boolean := True; Store_Payload : Boolean := True; Parse_Payload : Boolean := True; Filter : Header_Filter := null) is Index : Integer := Str'First; Stop : constant Integer := Str'Last; Colon : Integer; Eol : Integer; Next, Eol2 : Integer; Is_Continuation : Boolean; Value : Unbounded_String; function RTrim_CR (Item : String) return String is (if Item /= "" and then Item (Item'Last) = ASCII.CR then Item (Item'First .. Item'Last - 1) else Item); function LTrim_Space (Item : String) return String is (if Item /= "" and then Item (Item'First) = ' ' then Item (Item'First + 1 .. Item'Last) else Item); begin Msg := New_Message (MIME_Type => ""); -- Do we have an envelope for the message ? if Index + 4 < Str'Last and then Str (Index .. Index + 4) = "From " then Eol := Next_Occurrence (Str (Index .. Stop), ASCII.LF); Set_Envelope_From (Msg, Str (Index .. Eol - 1)); Index := Eol + 1; end if; -- Find the headers block. It is defined as being the set of lines up -- to the first line that doesn't match the headers format. This can be -- an empty line (and should generally be the case according to -- RFC2822), but could be anything else, in which case the extra line -- is assumed to belong to the body while Index <= Stop loop Eol := Next_Occurrence (Str (Index .. Stop), ASCII.LF); Colon := Next_Occurrence (Str (Index .. Eol), ':'); exit when Colon > Eol; -- ??? Header names are characters between 33 and 126 inclusive. We -- should check -- Check for continuation lines: if the next line starts with a -- whitespace but contains other characters than whitespaces, it is -- part of the same header. We have this whitespace handling because -- of cases where the subject line is followed by the separator line, -- itself starting with a space. This is not full RFC2822 of course, -- but it is nice to handle this correctly anyway Value := To_Unbounded_String (LTrim_Space (RTrim_CR (Str (Colon + 1 .. Eol - 1)))); while Eol < Str'Last and then Is_Whitespace (Str (Eol + 1)) loop Next := Eol + 1; Is_Continuation := False; Eol2 := Next_Occurrence (Str (Next .. Stop), ASCII.LF); for F in Next + 1 .. Eol2 - 1 loop if not Is_Whitespace (Str (F)) then Append (Value, ' ' & RTrim_CR (Str (F .. Eol2 - 1))); Is_Continuation := True; exit; end if; end loop; exit when not Is_Continuation; Eol := Eol2; end loop; if Store_Headers and then (Filter = null or else Filter (Str (Index .. Colon - 1))) then Add_Header (Msg, Create (Name => Str (Index .. Colon - 1), Value => To_String (Value))); end if; Index := Eol + 1; end loop; -- A blank line is not part of the body, any other line is if Index <= Str'Last and then Str (Index) = ASCII.LF then Index := Index + 1; end if; if Store_Payload then if not Parse_Payload then -- Note: do not use Set_Text_Payload here, as this would reset -- the Content-Type header. Msg.Contents.Payload := (Multipart => False, Text => To_Unbounded_String (Str (Index .. Str'Last))); else Email.Parser.Parse_Payload (Msg, Str (Index .. Str'Last)); end if; end if; exception when others => Msg := Null_Message; end Full_Parse; ------------------- -- Parse_Payload -- ------------------- procedure Parse_Payload (Msg : in out Message; Unparsed : String) is Boundary : constant String := Get_Boundary (Msg); Length : constant Natural := Boundary'Length; Index : Integer := Unparsed'First; Tmp : Integer; Is_Last_Boundary : Boolean := False; Is_Boundary : Boolean; Start : Integer := -1; Attachment : Message; begin if Boundary = "" then Set_Text_Payload (Msg, Unparsed, MIME_Type => ""); else while not Is_Last_Boundary and then Index + Length < Unparsed'Last loop if Unparsed (Index) = '-' and then Unparsed (Index + 1) = '-' and then Unparsed (Index + 2 .. Index + 1 + Length) = Boundary then Tmp := Index + 2 + Length; if Unparsed (Tmp) = '-' and then Unparsed (Tmp + 1) = '-' then Is_Last_Boundary := True; Tmp := Tmp + 2; end if; Is_Boundary := True; while Tmp <= Unparsed'Last and then Unparsed (Tmp) /= ASCII.LF loop if not Is_Whitespace (Unparsed (Tmp)) then -- Not a boundary after all Is_Boundary := False; Is_Last_Boundary := False; exit; end if; Tmp := Tmp + 1; end loop; if Is_Boundary then if Start /= -1 then Full_Parse (Str => Unparsed (Start .. Index - 2), Msg => Attachment, Store_Headers => True, Store_Payload => True, Parse_Payload => True); if Attachment /= Null_Message then Add_Payload (Msg, Attachment); else -- Should exit with error message I guess null; end if; else Set_Preamble (Msg, Unparsed (Unparsed'First .. Index - 2)); end if; Start := Tmp + 1; Is_Last_Boundary := Is_Last_Boundary or else Tmp + Length >= Unparsed'Last; end if; Index := Next_Occurrence (Unparsed (Tmp .. Unparsed'Last), ASCII.LF) + 1; else Index := Next_Occurrence (Unparsed (Index .. Unparsed'Last), ASCII.LF) + 1; end if; end loop; end if; if Index < Unparsed'Last and then Start /= -1 then Set_Epilogue (Msg, Unparsed (Start .. Unparsed'Last)); end if; end Parse_Payload; -------------------------- -- Full_Parse_From_File -- -------------------------- procedure Full_Parse_From_File (Filename : Virtual_File; Msg : out Message; Store_Headers : Boolean := True; Store_Payload : Boolean := True; Parse_Payload : Boolean := True; Filter : Header_Filter := null) is Str : GNAT.Strings.String_Access; begin Str := Read_File (Filename); Full_Parse (Str.all, Msg, Store_Headers, Store_Payload, Parse_Payload, Filter); Free (Str); end Full_Parse_From_File; ------------------- -- Parse_Payload -- ------------------- procedure Parse_Payload (Msg : in out Message) is use Ada.Strings.Unbounded.Aux; Payload : constant Unbounded_String := Msg.Contents.Payload.Text; Payload_Str : Big_String_Access; Payload_Len : Natural; begin Msg.Contents.Payload.Text := Null_Unbounded_String; Get_String (Payload, Payload_Str, Payload_Len); Parse_Payload (Msg, Payload_Str (1 .. Payload_Len)); end Parse_Payload; end GNATCOLL.Email.Parser; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-email-parser.ads000066400000000000000000000111311425465243200237550ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides a parser that creates an email message from a textual -- representation of it. with GNATCOLL.VFS; package GNATCOLL.Email.Parser is procedure Parse (Str : String; Msg : out Message); -- Default message parser procedure Parse_Ignore_Headers (Str : String; Msg : out Message); -- Same as Parse, but the headers are not stored into the final Msg. -- This significantly speeds up the parser, and should be used if you don't -- need access to headers later on. procedure Parse_Minimal_Headers (Str : String; Msg : out Message); -- Same as Parse, but only keep a subset of the headers. This removes -- headers like 'Received:', which are generally not useful to manipulate -- the message. procedure Parse_No_Payload (Str : String; Msg : out Message); -- Parse the message, but store its body unparsed (ie nested parts are -- not analyzed). procedure Parse_No_Payload_Minimal_Headers (Str : String; Msg : out Message); -- Parse the message, but store its body unparsed (ie nested parts are -- not analyzed). Ignore headers that are generally not useful to -- manipulate a message. type Header_Filter is access function (Name : String) return Boolean; procedure Full_Parse (Str : String; Msg : out Message; Store_Headers : Boolean := True; Store_Payload : Boolean := True; Parse_Payload : Boolean := True; Filter : Header_Filter := null); -- Internal version of Parse. You could implement your own Parse by -- calling this one with the appropriate parameters. For instance, you -- can choose the list of headers to store. -- If Store_Headers is false, then the headers will not be stored in the -- final message. Some of them are still taken into account to properly -- parse the message (MIME contents,...). This significantly speeds up the -- processing since less memory needs to be allocated. -- If Filter is specified, only those headers matching Filter will be -- stored. If Store_Headers is False, no header is stored. -- If Store_Payload is False, then the payload is not analyzed nor parsed, -- simply ignored. When the payload is stored, it can additionally be -- parsed, ie when it is a multipart message, each of the part is -- extracted separately. To save time, they are not MIME-decoded though. procedure Full_Parse_From_File (Filename : GNATCOLL.VFS.Virtual_File; Msg : out Message; Store_Headers : Boolean := True; Store_Payload : Boolean := True; Parse_Payload : Boolean := True; Filter : Header_Filter := null); -- Same as Full_Parse, but reads the message directly from a file. -- Name_Error is raised if the file could not be read. procedure Parse_Payload (Msg : in out Message); -- Parse previously unparsed payload end GNATCOLL.Email.Parser; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-email-utils.adb000066400000000000000000002012201425465243200236000ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ pragma Ada_2012; with Ada.Calendar; use Ada.Calendar; with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones; with Ada.Calendar.Formatting; use Ada.Calendar.Formatting; with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Strings.Hash_Case_Insensitive; with GNATCOLL.Utils; use GNATCOLL.Utils; with Interfaces; use Interfaces; with System.WCh_Con; use System.WCh_Con; with GNAT.Decode_String; pragma Warnings (Off); -- Ada.Strings.Unbounded.Aux is an internal GNAT unit with Ada.Strings.Unbounded.Aux; pragma Warnings (On); package body GNATCOLL.Email.Utils is U_Charset_US_ASCII : constant Unbounded_String := To_Unbounded_String (Charset_US_ASCII); package Decode_Shift_JIS is new GNAT.Decode_String (WCEM_Shift_JIS); package Decode_EUC is new GNAT.Decode_String (WCEM_EUC); package Decode_UTF8 is new GNAT.Decode_String (WCEM_UTF8); type Next_Char_Acc is access procedure (S : String; Index : in out Natural); -- Procedure moving Index from one character to the next in S, -- taking multi-byte encodings into account. procedure Single_Byte_Next_Char (S : String; Index : in out Natural); -- Default version for single-byte charsets, simply incrementing Index --------------------------- -- Single_Byte_Next_Char -- --------------------------- procedure Single_Byte_Next_Char (S : String; Index : in out Natural) is pragma Unreferenced (S); begin Index := Index + 1; end Single_Byte_Next_Char; function Next_Char_For_Charset (Charset : String) return Next_Char_Acc is (if Charset = Charset_Shift_JIS then Decode_Shift_JIS.Next_Wide_Character'Access elsif Charset = Charset_EUC then Decode_EUC.Next_Wide_Character'Access elsif Charset = Charset_UTF_8 then Decode_UTF8.Next_Wide_Character'Access else Single_Byte_Next_Char'Access); -- Next_Char procedure for the named Charset procedure Next_Char_Ignore_Invalid (NC : Next_Char_Acc; S : String; Index : in out Natural); pragma Inline (Next_Char_Ignore_Invalid); -- Call NC (S, Index), but if an exception is raised (e.g. due to -- an invalid encoding in S, fall back to incrementing Index by 1. ------------------------------ -- Next_Char_Ignore_Invalid -- ------------------------------ procedure Next_Char_Ignore_Invalid (NC : Next_Char_Acc; S : String; Index : in out Natural) is Orig_Index : constant Natural := Index; begin NC (S, Index); exception when others => Index := Orig_Index + 1; end Next_Char_Ignore_Invalid; function Needs_Quoting (Char : Character; Where : Region; Is_EOL : Boolean) return Boolean; -- Return True if C needs to be quoted when appearing in Region, False -- otherwise. Is_EOL indicates whether Char is last of its line. function Needs_Quoting (U : Unbounded_String; Where : Region; Is_EOL : Boolean) return Boolean; -- True if any non-whitespace character in U needs to be quoted per -- the above function. Is_EOL indicates whehter the last character of U is -- last of its line. procedure Read_Integer (S : String; Index : in out Integer; Value : out Integer); -- return the integer starting at Index, and moves Index after the integer procedure Skip_Comment (S : String; Index : in out Integer); -- Skip the comment, if any, that starts at Index. -- In RFC 2822, comments are between parenthesis, and can be nested procedure Skip_Quoted_String (S : String; Index : in out Integer); -- Skip a quoted string, taking properly into account the backslashes -- Index should point after the opening quote. procedure Parse_And_Skip_Address (From_C : in out Charset_String_List.Cursor; From : in out Integer; Address : out Email_Address); -- Parse the first email address at (From_C, From), and leaves them after -- it, so that if there are more addresses in From_C they can all be parsed -- easily. procedure Parse_And_Skip_Address (Str : String; From : in out Integer; Buffer : in out Unbounded_String; Buffer_Has_At : in out Boolean; In_Quote : in out Boolean; Comment : in out Unbounded_String; Address : in out Email_Address; Found : out Boolean); -- Internal version of Parse_And_Skip_Address, which applies to a -- us-ascii string. It maintains internal data. -- In_Quote indicates whether we are initially within an open quote ("), -- and on exit whether we are still processing a quoted string. procedure Post_Process_Address (Address : in out Email_Address; Buffer, Comment : Unbounded_String; Buffer_Has_At : Boolean); -- Complete the data in Address, given Buffer and Comment that were -- generated by Parse_And_Skip_Address. This procedure should be called -- after Parse_And_Skip_Address, before returning an address to the user. Special_Chars : constant array (Character) of Boolean := ('[' | ']' | '\' | '(' | ')' | '<' | '>' | '@' | ',' => True, ':' | ';' | '"' | '.' => True, others => False); Quoted_Chars : constant array (Character) of Boolean := ('[' | ']' | '\' | '(' | ')' | '"' => True, others => False); Qp_Convert : constant array (Character) of Short_Integer := ('0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15, 'a' => 10, 'b' => 11, 'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15, others => -1); type Byte is mod 256; Base64_Convert : constant array (Character) of Byte := ('+' => 62, '/' => 63, '0' => 52, '1' => 53, '2' => 54, '3' => 55, '4' => 56, '5' => 57, '6' => 58, '7' => 59, '8' => 60, '9' => 61, 'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, 'H' => 7, 'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25, 'a' => 26, 'b' => 27, 'c' => 28, 'd' => 29, 'e' => 30, 'f' => 31, 'g' => 32, 'h' => 33, 'i' => 34, 'j' => 35, 'k' => 36, 'l' => 37, 'm' => 38, 'n' => 39, 'o' => 40, 'p' => 41, 'q' => 42, 'r' => 43, 's' => 44, 't' => 45, 'u' => 46, 'v' => 47, 'w' => 48, 'x' => 49, 'y' => 50, 'z' => 51, others => -1); type Mod64 is mod 2 ** 6; To_Base64 : constant array (Mod64) of Character := (00 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G', 7 => 'H', 8 => 'I', 9 => 'J', 10 => 'K', 11 => 'L', 12 => 'M', 13 => 'N', 14 => 'O', 15 => 'P', 16 => 'Q', 17 => 'R', 18 => 'S', 19 => 'T', 20 => 'U', 21 => 'V', 22 => 'W', 23 => 'X', 24 => 'Y', 25 => 'Z', 26 => 'a', 27 => 'b', 28 => 'c', 29 => 'd', 30 => 'e', 31 => 'f', 32 => 'g', 33 => 'h', 34 => 'i', 35 => 'j', 36 => 'k', 37 => 'l', 38 => 'm', 39 => 'n', 40 => 'o', 41 => 'p', 42 => 'q', 43 => 'r', 44 => 's', 45 => 't', 46 => 'u', 47 => 'v', 48 => 'w', 49 => 'x', 50 => 'y', 51 => 'z', 52 => '0', 53 => '1', 54 => '2', 55 => '3', 56 => '4', 57 => '5', 58 => '6', 59 => '7', 60 => '8', 61 => '9', 62 => '+', 63 => '/'); Hex_Chars : constant array (0 .. 15) of Character := "0123456789ABCDEF"; ------------------------ -- Skip_Quoted_String -- ------------------------ procedure Skip_Quoted_String (S : String; Index : in out Integer) is begin while Index <= S'Last loop if S (Index) = '"' then Index := Index + 1; return; elsif S (Index) = '\' then Index := Index + 2; else Index := Index + 1; end if; end loop; -- There is no closing '"' Index := S'Last + 1; end Skip_Quoted_String; ------------------ -- Skip_Comment -- ------------------ procedure Skip_Comment (S : String; Index : in out Integer) is Par : Natural := 1; begin if S (Index) = '(' then Index := Index + 1; while Index <= S'Last loop if S (Index) = ')' then Par := Par - 1; if Par = 0 then Index := Index + 1; return; else Index := Index + 1; end if; elsif S (Index) = '(' then Par := Par + 1; Index := Index + 1; elsif S (Index) = '\' then Index := Index + 2; else Index := Index + 1; end if; end loop; -- No closing ')' Index := S'Last + 1; end if; end Skip_Comment; ------------------ -- Read_Integer -- ------------------ procedure Read_Integer (S : String; Index : in out Integer; Value : out Integer) is Start : constant Integer := Index; begin if S (Index) = '-' or else S (Index) = '+' then Index := Index + 1; end if; while Index <= S'Last and then S (Index) in '0' .. '9' loop Index := Index + 1; end loop; Value := Integer'Value (S (Start .. Index - 1)); end Read_Integer; ------------- -- To_Time -- ------------- function To_Time (Date : String; Format : Time_Format := Time_RFC2822) return Ada.Calendar.Time is Index : Integer := Date'First; Index2 : Integer; Year : Year_Number := Year_Number'First; Month : Month_Number := Month_Number'First; Day : Day_Number := Day_Number'First; Seconds : Day_Duration := 0.0; TZ : Time_Offset := 0; Time_Error : exception; procedure Read_Day; procedure Read_Month; procedure Read_Year; procedure Read_Time; -- Read the day of month or the year procedure Read_Time_Zone; procedure Read_Day is begin Read_Integer (Date (Index .. Date'Last), Index, Value => Index2); Day := Day_Number (Index2); Skip_Whitespaces (Date (Index .. Date'Last), Index); end Read_Day; procedure Read_Month is pragma Warnings (Off); type Month_Name is (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec); pragma Warnings (On); begin Month := Month_Name'Pos (Month_Name'Value (Date (Index .. Index + 2))) + 1; -- Some mailers print the month in full, not just the first three -- chars. Although this isn't part of the RFC 2822, we still want to -- handle these Index := Index + 3; while Index <= Date'Last and then not Is_Whitespace (Date (Index)) loop Index := Index + 1; end loop; Skip_Whitespaces (Date (Index .. Date'Last), Index); exception when others => -- This really means the date format is incorrect! null; end Read_Month; procedure Read_Year is begin Read_Integer (Date (Index .. Date'Last), Index, Value => Index2); if Index2 < 0 then raise Time_Error; elsif Index2 <= 49 then Year := Year_Number (2000 + Index2); elsif Index2 <= 99 then Year := Year_Number (1900 + Index2); else Year := Year_Number (Index2); end if; Skip_Whitespaces (Date (Index .. Date'Last), Index); end Read_Year; procedure Read_Time is begin Read_Integer (Date (Index .. Date'Last), Index, Value => Index2); Seconds := Seconds + Day_Duration (Index2) * 3600.0; if Date (Index) /= ':' then raise Time_Error; end if; Index := Index + 1; Read_Integer (Date (Index .. Date'Last), Index, Value => Index2); Seconds := Seconds + Day_Duration (Index2) * 60.0; if Date (Index) = ':' then Index := Index + 1; Read_Integer (Date (Index .. Date'Last), Index, Value => Index2); Seconds := Seconds + Day_Duration (Index2); end if; Skip_Whitespaces (Date (Index .. Date'Last), Index); end Read_Time; procedure Read_Time_Zone is TZ_Local : Integer; type Named_TZ is (AST, ADT, EST, EDT, CST, CDT, MST, MDT, PST, PDT); Named_TZ_Offset : constant array (Named_TZ) of Time_Offset := (AST => -240, ADT => -180, EST => -300, EDT => -240, CST => -360, CDT => -300, MST => -420, MDT => -360, PST => -480, PDT => -420); begin -- Timezone (we might have none in badly formed dates) if Index < Date'Last then if Date (Index) = '-' or else Date (Index) = '+' or else Date (Index) in '0' .. '9' then Read_Integer (Date (Index .. Date'Last), Index, Value => TZ_Local); TZ := Time_Offset ((TZ_Local / 100) * 60 + TZ_Local mod 100); else -- The timezone table does not include the military time zones -- defined in RFC822, other than Z. According to RFC1123, the -- description in RFC822 gets the signs wrong, so we can't rely -- on any such time zones. RFC1123 recommends that numeric -- timezone indicators be used instead of timezone names. if Date (Index .. Index + 1) = "UT" or else Date (Index .. Index + 2) = "UTC" or else Date (Index) = 'Z' then TZ := 0; else TZ := Named_TZ_Offset (Named_TZ'Value (Date (Index .. Index + 2))); end if; end if; end if; exception when Constraint_Error => -- Invalid time zone, just ignore null; end Read_Time_Zone; begin -- RFC 2822 format is -- [day-of-week] ","] day month-name year FWS time-of-day FWS tz -- year := 4 * DIGIT | 2 * DIGIT -- day := 1*2DIGIT -- time-of-day := hour ":" minute [":" second] -- tz := (("+" | "-") 4DIGIT) | "UT" | "GMT" | ... -- -- Envelope format is -- Tue Jan 24 14:48:49 2006 +0100 Skip_Whitespaces (Date (Index .. Date'Last), Index); -- Day of week is optional, skip it case Format is when Time_RFC2822 => Index2 := Next_Occurrence (Date (Index .. Date'Last), ','); if Index2 <= Date'Last then Index := Index2 + 1; Skip_Whitespaces (Date (Index .. Date'Last), Index); end if; Read_Day; Read_Month; Read_Year; Read_Time; when Time_Envelope => Index := Index + 3; Skip_Whitespaces (Date (Index .. Date'Last), Index); Read_Month; Read_Day; Read_Time; Read_Year; end case; Read_Time_Zone; return Time_Of (Year, Month, Day, Seconds, Time_Zone => TZ); exception when Time_Error => return No_Time; when Constraint_Error => return No_Time; end To_Time; ----------------- -- Format_Time -- ----------------- function Format_Time (Date : Ada.Calendar.Time) return String is Result : Unbounded_String; Y : Year_Number; M : Month_Number; D : Day_Number; H : Hour_Number; Min : Minute_Number; S : Second_Number; SS : Second_Duration; begin Split (Date, Y, M, D, H, Min, S, SS, Time_Zone => 0); Result := To_Unbounded_String (Image (Integer (H), Min_Width => 2) & ":"); Append (Result, Image (Integer (Min), Min_Width => 2) & ":"); Append (Result, Image (Integer (S), Min_Width => 2)); return To_String (Result); end Format_Time; ----------------- -- Format_Date -- ----------------- Day_Names : constant array (Day_Name) of String (1 .. 3) := (Monday => "Mon", Tuesday => "Tue", Wednesday => "Wed", Thursday => "Thu", Friday => "Fri", Saturday => "Sat", Sunday => "Sun"); Month_Names : constant array (1 .. 12) of String (1 .. 3) := (1 => "Jan", 2 => "Feb", 3 => "Mar", 4 => "Apr", 5 => "May", 6 => "Jun", 7 => "Jul", 8 => "Aug", 9 => "Sep", 10 => "Oct", 11 => "Nov", 12 => "Dec"); function Format_Date (Date : Ada.Calendar.Time; Use_GMT : Boolean := False; From_Line : Boolean := False; No_TZ : Boolean := False; Show_Time : Boolean := True; Show_Seconds : Boolean := True; Show_Day : Boolean := True) return String is Result : Unbounded_String; Y : Year_Number; M : Month_Number; D : Day_Number; H : Hour_Number; Min : Minute_Number; S : Second_Number; SS : Second_Duration; TZ : Time_Offset := 0; RFC_TZ : Integer; Unknown_TZ : Boolean := False; begin if not (Use_GMT or else No_TZ) then begin -- Number of minutes difference for the timezone TZ := UTC_Time_Offset (Date); exception when Unknown_Zone_Error => Unknown_TZ := True; end; end if; -- We cannot use GNAT.Calendar.Time_IO for week days, since we always -- want the english names, not the locale's version. Split (Date, Y, M, D, H, Min, S, SS, Time_Zone => TZ); if Show_Day then -- Note: we can't just call Day_Of_Week (Date), since this gives the -- day of week for Date *in the local time zone*, and in No_TZ or -- Use_GMT mode we want the day of week for Date -- *in the UT time zone*. So, we conjure up another date whose year, -- month, and day number in month (and therefore day of week) in -- local time are the same as those of Date in GMT (namely, Y, M, -- and D). Result := To_Unbounded_String (Day_Names (Day_Of_Week (Ada.Calendar.Time_Of (Y, M, D)))); if From_Line then Append (Result, " "); else Append (Result, ", "); end if; end if; if not From_Line then Append (Result, Image (Integer (D), Min_Width => 2) & " "); end if; Append (Result, Month_Names (M) & ' '); if From_Line then Append (Result, Image (Integer (D), Min_Width => 2) & " "); else Append (Result, Image (Integer (Y), Min_Width => 2) & " "); end if; if Show_Time then Append (Result, Image (Integer (H), Min_Width => 2) & ":"); Append (Result, Image (Integer (Min), Min_Width => 2)); if Show_Seconds then Append (Result, ":" & Image (Integer (S), Min_Width => 2)); end if; end if; if From_Line then Append (Result, " " & Image (Integer (Y), Min_Width => 2)); end if; if not No_TZ then if Use_GMT then Append (Result, " GMT"); elsif Unknown_TZ then Append (Result, " -0000"); else RFC_TZ := Integer ((TZ / 60) * 100 + TZ mod 60); Append (Result, " " & Image (RFC_TZ, Min_Width => 4, Force_Sign => True)); end if; end if; return To_String (Result); end Format_Date; ------------------- -- Parse_Address -- ------------------- function Parse_Address (Email : String) return Email_Address is Index : Integer := Email'First; Result : Email_Address; Buffer : Unbounded_String; Buffer_Has_At : Boolean := False; Comment : Unbounded_String; Found : Boolean; In_Quote : Boolean := False; begin Parse_And_Skip_Address (Str => Email, From => Index, Buffer => Buffer, Buffer_Has_At => Buffer_Has_At, In_Quote => In_Quote, Comment => Comment, Address => Result, Found => Found); Post_Process_Address (Address => Result, Buffer => Buffer, Comment => Comment, Buffer_Has_At => Buffer_Has_At); return Result; end Parse_Address; ---------------------------- -- Parse_And_Skip_Address -- ---------------------------- procedure Parse_And_Skip_Address (Str : String; From : in out Integer; Buffer : in out Unbounded_String; Buffer_Has_At : in out Boolean; In_Quote : in out Boolean; Comment : in out Unbounded_String; Address : in out Email_Address; Found : out Boolean) is Index : Integer; begin if In_Quote then Index := From; Skip_Quoted_String (Str (Index .. Str'Last), Index); Address.Real_Name := Trim (To_Unbounded_String (Str (From + 1 .. Index - 2)), Ada.Strings.Both); From := Index + 1; In_Quote := False; end if; -- Skip spaces while From <= Str'Last and then (Str (From) = ASCII.LF or else Str (From) = ASCII.CR or else Str (From) = ASCII.HT or else Str (From) = ' ') loop From := From + 1; end loop; -- Only parse the contents of us-ascii strings. The rest cannot -- contain email addresses nor comments anyway. while From <= Str'Last loop if From <= Str'Last then if Str (From) = '(' then -- A comment. Ignored in general, but if we do not have a -- real name, it is likely to be contained in this -- comment, which is what some old mailers used to do: -- report@gnat.com (Report) Index := From; Skip_Comment (Str (From .. Str'Last), Index); Append (Comment, Str (From + 1 .. Index - 2)); From := Index; elsif Str (From) = '<' then -- The email address Index := From; while Index <= Str'Last and then Str (Index) /= '>' loop Index := Index + 1; end loop; Address.Address := To_Unbounded_String (Str (From + 1 .. Index - 1)); From := Index + 1; -- ',' is the standard separator in mail messages, but ';' is -- often used by users when manually typing a list of addresses elsif Str (From) = ',' or else Str (From) = ';' or else Str (From) = ASCII.LF or else Str (From) = ASCII.CR or else Str (From) = ASCII.HT or else (Buffer_Has_At and then Str (From) = ' ') then -- End of current address From := From + 1; Found := True; return; elsif Str (From) = '"' then Index := From + 1; Skip_Quoted_String (Str (Index .. Str'Last), Index); if Index > Str'Last then In_Quote := True; end if; Address.Real_Name := Trim (To_Unbounded_String (Str (From + 1 .. Index - 2)), Ada.Strings.Both); if Index <= Str'Last and then Str (Index) = ' ' then From := Index + 1; else From := Index; end if; else if Str (From) = '@' then Buffer_Has_At := True; end if; Append (Buffer, Str (From)); From := From + 1; end if; end if; end loop; Found := False; end Parse_And_Skip_Address; ---------------------------- -- Parse_And_Skip_Address -- ---------------------------- procedure Parse_And_Skip_Address (From_C : in out Charset_String_List.Cursor; From : in out Integer; Address : out Email_Address) is use Charset_String_List; Buffer : Unbounded_String; Comment : Unbounded_String; Buffer_Has_At : Boolean := False; In_Quote : Boolean := False; -- Quotes are not necessarily encoded, and we could have for instance: -- " =?iso-2022-jp?b?...?= " -- which is made of several strings: one for the opening quote, one for -- the encoded name, and a last one that includes the quote and the -- email address. Continue : Boolean; procedure Analyze (CS : Charset_String); -- Analyze a given element of the list. Done in nested procedure to -- avoid a copy of each element of Email procedure Analyze (CS : Charset_String) is Tmp : Unbounded_String; Found : Boolean := False; begin -- Only parse the contents of us-ascii strings. The rest cannot -- contain email addresses nor comments anyway if CS.Charset = Charset_US_ASCII then Parse_And_Skip_Address (Str => To_String (CS.Contents), From => From, Buffer => Buffer, Buffer_Has_At => Buffer_Has_At, In_Quote => In_Quote, Comment => Comment, Address => Address, Found => Found); else -- Reencode, to preserve names in international charsets Encode (Str => To_String (CS.Contents), Charset => To_String (CS.Charset), Where => Addr_Header, Result => Tmp); Append (Buffer, Tmp); end if; Continue := not Found; end Analyze; -- Start of processing for Parse_And_Skip_Address begin Address := Null_Address; while Has_Element (From_C) loop Query_Element (From_C, Analyze'Unrestricted_Access); exit when not Continue; Next (From_C); From := 1; end loop; Post_Process_Address (Address, Buffer, Comment, Buffer_Has_At); end Parse_And_Skip_Address; -------------------------- -- Post_Process_Address -- -------------------------- procedure Post_Process_Address (Address : in out Email_Address; Buffer, Comment : Unbounded_String; Buffer_Has_At : Boolean) is pragma Unreferenced (Buffer_Has_At); begin if Address.Address = Null_Unbounded_String then -- Ideally, we should test whether Buffer contains a @ string. But -- there are degenerate cases where we have an email address on its -- own with no @ sign, and we want to handle them for backward -- compatibility... Address.Address := Trim (Buffer, Ada.Strings.Both); else if Address.Real_Name = Null_Unbounded_String then if Buffer = Null_Unbounded_String then Address.Real_Name := Trim (Comment, Ada.Strings.Both); else Address.Real_Name := Trim (Buffer, Ada.Strings.Both); end if; end if; end if; end Post_Process_Address; ---------------- -- To_Address -- ---------------- function To_Address (Address : String; Real_Name : String := "") return Email_Address is begin return (Address => To_Unbounded_String (Address), Real_Name => To_Unbounded_String (Real_Name)); end To_Address; ------------------- -- Get_Addresses -- ------------------- function Get_Addresses (Str : String) return Address_Set.Set is use Charset_String_List; L : Charset_String_List.List; begin Append (L, (Contents => To_Unbounded_String (Str), Charset => To_Unbounded_String (Charset_US_ASCII))); return Get_Addresses (L); end Get_Addresses; function Get_Addresses (Str : Charset_String_List.List) return Address_Set.Set is use Charset_String_List, Address_Set; C : Charset_String_List.Cursor := First (Str); From : Integer := 1; Result : Address_Set.Set; Addr : Email_Address; begin while Has_Element (C) loop Parse_And_Skip_Address (C, From, Addr); if Addr /= Null_Address then Include (Result, Addr); end if; end loop; return Result; end Get_Addresses; --------------- -- To_String -- --------------- function To_String (Addresses : Address_Set.Set; Separator : String := ", "; Address_Only : Boolean := False; Charset : String := Charset_US_ASCII) return String is use Address_Set; Tmp : Unbounded_String; C : Address_Set.Cursor := First (Addresses); begin while Has_Element (C) loop if Tmp /= Null_Unbounded_String then Append (Tmp, Separator); end if; if Address_Only then Append (Tmp, Element (C).Address); else Append (Tmp, Format_Address (Element (C), Charset)); end if; Next (C); end loop; return To_String (Tmp); end To_String; -------------------- -- Format_Address -- -------------------- function Format_Address (Email : Email_Address; Charset : String := Charset_US_ASCII) return Charset_String_List.List is L : Charset_String_List.List; begin -- If Charset is US-ASCII, we can't rely on RFC 2047 encoding to -- protect any special characters, so fall back to legacy formatting -- routine, which will do backslash-escaping as needed. If nothing -- needs quoting, don't bother to go trough RFC 2047 either. if Charset = Charset_US_ASCII or else not Needs_Quoting (Email.Real_Name, Is_EOL => False, Where => Addr_Header) then L.Append ((Contents => To_Unbounded_String (Legacy_Format_Address (Real => To_String (Email.Real_Name), Address => To_String (Email.Address))), Charset => U_Charset_US_ASCII)); -- Case where we have a non-ASCII charset specified else -- Here we have a non-default Charset specified: RFC 2047 encoding -- will also take care of escaping special characters. L.Append ((Contents => Email.Real_Name, Charset => To_Unbounded_String (Charset))); -- Actual address must not be encoded in any way: add a separate -- US ASCII section. L.Append (Charset_String' (Contents => " <" & Email.Address & ">", Charset => U_Charset_US_ASCII)); end if; return L; end Format_Address; -------------------- -- Format_Address -- -------------------- function Format_Address (Email : Email_Address; Charset : String := Charset_US_ASCII) return Unbounded_String is Res : Unbounded_String; begin To_String (Format_Address (Email, Charset), Res); return Res; end Format_Address; --------------------------- -- Legacy_Format_Address -- --------------------------- function Legacy_Format_Address (Real : String; Address : String) return String is Has_Special : Boolean := False; -- True if Real contains any special character that needs to be -- escaped in an RFC 2822 address header. begin if Real = "" then return Address; else for C in Real'Range loop if Special_Chars (Real (C)) then Has_Special := True; exit; end if; end loop; if Has_Special then return '"' & Quote (Real) & """ <" & Address & '>'; else return Quote (Real) & " <" & Address & '>'; end if; end if; end Legacy_Format_Address; ----------- -- Quote -- ----------- function Quote (Str : String) return String is Result : String (Str'First .. Str'Last * 2); Index : Integer := Result'First; begin for C in Str'Range loop if Quoted_Chars (Str (C)) then Result (Index) := '\'; Index := Index + 1; end if; Result (Index) := Str (C); Index := Index + 1; end loop; return Result (Result'First .. Index - 1); end Quote; ------------- -- Unquote -- ------------- function Unquote (Str : String) return String is Result : String (Str'Range); Index : Integer := Result'First; C : Integer := Str'First; begin while C <= Str'Last loop if Str (C) = '\' and then C < Str'Last then Result (Index) := Str (C + 1); C := C + 1; else Result (Index) := Str (C); end if; C := C + 1; Index := Index + 1; end loop; return Result (Result'First .. Index - 1); end Unquote; ---------- -- Hash -- ---------- function Hash (Addr : Email_Address) return Ada.Containers.Hash_Type is begin return Ada.Strings.Hash_Case_Insensitive (To_String (Addr.Address)); end Hash; -------------------- -- Get_Recipients -- -------------------- function Get_Recipients (Msg : Message'Class; Include_From : Boolean := False) return Address_Set.Set is use Address_Set; Iter : Header_Iterator; H : Header; Result : Address_Set.Set; begin Iter := Get_Headers (Msg); loop Next (Iter, H => H); exit when H = Null_Header; if Get_Name (H) = "to" or else Get_Name (H) = "cc" or else Get_Name (H) = "resent-to" or else Get_Name (H) = "resent-cc" or else (Include_From and then Get_Name (H) = "from") then -- ??? Should avoid extra copy here Union (Result, Get_Recipients (H)); end if; end loop; return Result; end Get_Recipients; -------------------- -- Get_Recipients -- -------------------- function Get_Recipients (H : Header'Class) return Address_Set.Set is begin if H.Contents = null then return Address_Set.Empty_Set; else return Get_Addresses (H.Contents.Value); end if; end Get_Recipients; ------------- -- Flatten -- ------------- procedure Flatten (List : Charset_String_List.List; Result : out Unbounded_String) is use Charset_String_List; C : Charset_String_List.Cursor := First (List); begin Result := Null_Unbounded_String; while Has_Element (C) loop Append (Result, Element (C).Contents); Next (C); end loop; end Flatten; --------------- -- To_String -- --------------- procedure To_String (List : Charset_String_List.List; Result : out Unbounded_String; Where : Any_Header := Other_Header) is use Charset_String_List; C : Charset_String_List.Cursor := First (List); Tmp : Unbounded_String; begin Result := Null_Unbounded_String; while Has_Element (C) loop Encode (Str => To_String (Element (C).Contents), Charset => To_String (Element (C).Charset), Where => Where, Result => Tmp); Append (Result, Tmp); Next (C); end loop; end To_String; ------------------------- -- Domain_From_Address -- ------------------------- function Domain_From_Address (Email : String) return String is begin for E in Email'First .. Email'Last - 1 loop if Email (E) = '@' then return Email (E + 1 .. Email'Last); end if; end loop; return ""; end Domain_From_Address; function Domain_From_Address (Email : Email_Address) return String is begin return Domain_From_Address (To_String (Email.Address)); end Domain_From_Address; ----------------------- -- Login_From_Address -- ------------------------ function Login_From_Address (Email : String) return String is begin for E in Email'First .. Email'Last loop if Email (E) = '@' then return Email (Email'First .. E - 1); end if; end loop; return Email; end Login_From_Address; function Login_From_Address (Email : Email_Address) return String is begin return Login_From_Address (To_String (Email.Address)); end Login_From_Address; ------------------- -- Needs_Quoting -- ------------------- function Needs_Quoting (Char : Character; Where : Region; Is_EOL : Boolean) return Boolean is begin if Char = ' ' or else Char = ASCII.HT then return Is_EOL or else Where in Any_Header; elsif Char = '=' or else Char = '?' or else Character'Pos (Char) not in 32 .. 126 then return True; else return Where = Addr_Header and then Special_Chars (Char); end if; end Needs_Quoting; function Needs_Quoting (U : Unbounded_String; Where : Region; Is_EOL : Boolean) return Boolean is use Ada.Strings.Unbounded.Aux; Str : Big_String_Access; Last : Integer; EOL : Boolean; begin Get_String (U, Str, Last); for J in Str'First .. Last loop EOL := Is_EOL and then J = Last; -- No need to quote whitespace unless at EOL if (Str (J) = ' ' or else Str (J) = ASCII.HT) and then not EOL then null; elsif Needs_Quoting (Str (J), Where, EOL) then return True; end if; end loop; return False; end Needs_Quoting; ----------------------------- -- Quoted_Printable_Encode -- ----------------------------- procedure Quoted_Printable_Encode (Str : String; Charset : String; Max_Block_Len : Integer := Integer'Last; Where : Region := Text; Result : out Unbounded_String) is Block_Prefix : constant String := (if Where in Any_Header then "=?" & Charset & "?q?" else ""); Block_Suffix : constant String := (if Where in Any_Header then "?=" else ""); Block_Separator : constant String := (if Where in Any_Header then " " else "=" & ASCII.LF); -- In Text, use a soft line break Current_Len : Natural := 0; Max : constant Natural := Integer'Min (Max_Block_Len, (if Where in Any_Header then 75 else 76)) - Block_Prefix'Length - Block_Suffix'Length - (Block_Separator'Length - 1); -- Note: Block_Separator may produce a printable character, so must be -- counted against the limit. function Quote (S : String) return String; -- Encode all characters in S procedure Append (Substring : String; Splittable : Boolean); -- Append Substring to Result, taking into account the max line length. -- If Splittable is false, Substring cannot be cut ----------- -- Quote -- ----------- function Quote (S : String) return String is P : Integer; Result : String (1 .. 3 * S'Length); Last : Integer := 0; begin for J in S'Range loop if S (J) = ' ' and then Where in Any_Header then Last := Last + 1; Result (Last) := '_'; else Last := Last + 3; P := Character'Pos (S (J)); Result (Last - 2 .. Last) := ('=', Hex_Chars (P / 16), Hex_Chars (P mod 16)); end if; end loop; return Result (1 .. Last); end Quote; ------------ -- Append -- ------------ procedure Append (Substring : String; Splittable : Boolean) is S : Integer := Substring'First; begin if Substring'Length = 0 then return; end if; if Splittable then while Substring'Last - S + 1 > Max - Current_Len loop if Current_Len = 0 then Append (Result, Block_Prefix); end if; Append (Result, Substring (S .. S + Max - Current_Len - 1)); Append (Result, Block_Suffix & Block_Separator); S := S + Max - Current_Len; Current_Len := 0; -- We just started a new line end loop; if Current_Len = 0 then Append (Result, Block_Prefix); end if; Append (Result, Substring (S .. Substring'Last)); Current_Len := Current_Len + Substring'Last - S + 1; else if Current_Len + Substring'Length > Max then if Current_Len /= 0 then Append (Result, Block_Suffix & Block_Separator); end if; Current_Len := 0; Append (Result, Block_Prefix); Append (Result, Substring); Current_Len := Substring'Length; else if Current_Len = 0 then Append (Result, Block_Prefix); end if; Append (Result, Substring); Current_Len := Current_Len + Substring'Length; end if; end if; end Append; Start, Next, Last : Integer; -- Start of current encoded sequence, -- start of next encoded sequence, -- last element of previous encoded sequence. procedure Passthrough; -- Output previous span of unencoded characters, i.e. -- from Last + 1 to Start - 1. ----------------- -- Passthrough -- ----------------- procedure Passthrough is begin Append (Str (Last + 1 .. Start - 1), Splittable => True); end Passthrough; Next_Char : constant Next_Char_Acc := (if Where in Any_Header then Next_Char_For_Charset (Charset) else Single_Byte_Next_Char'Access); -- Start of processing for Quoted_Printable_Encode begin Result := Null_Unbounded_String; Next := Str'First; Last := Next - 1; loop Start := Next; exit when Start > Str'Last; -- Find end of possibly multibyte sequence starting at Start Next := Start; Next_Char_Ignore_Invalid (Next_Char, Str, Next); -- We encode single characters if needed, and always encode -- all multibyte characters. if Last > Start + 1 or else Needs_Quoting (Str (Start), Where, Is_EOL => Start = Str'Last) then Passthrough; Last := Next - 1; Append (Quote (Str (Start .. Last)), Splittable => False); end if; end loop; Passthrough; if Current_Len /= 0 then Append (Result, Block_Suffix); end if; end Quoted_Printable_Encode; ----------------------------- -- Quoted_Printable_Decode -- ----------------------------- procedure Quoted_Printable_Decode (Str : String; Result : out Unbounded_String; Where : Region := Text) is Start : Integer := -1; S : Integer; function Is_Hex (Char : Character) return Boolean; -- Return true if Char is an hexa character ------------ -- Is_Hex -- ------------ function Is_Hex (Char : Character) return Boolean is begin return Qp_Convert (Char) >= 0; end Is_Hex; -- Start of processing for Quoted_Printable_Decode begin S := Str'First; Result := Null_Unbounded_String; while S <= Str'Last loop if Str (S) = '_' and then Where in Any_Header then -- Encoded SPACE if Start /= -1 then Append (Result, Str (Start .. S - 1)); Start := -1; end if; Append (Result, ' '); elsif Str (S) /= '=' then -- Regular character if Start = -1 then Start := S; end if; elsif Str (S) = '=' and then S + 1 <= Str'Last and then Str (S + 1) = ASCII.LF then -- Soft line break if Start /= -1 then Append (Result, Str (Start .. S - 1)); Start := -1; end if; S := S + 1; elsif S + 2 <= Str'Last and then Is_Hex (Str (S + 1)) and then Is_Hex (Str (S + 2)) then -- Valid quote sequence if Start /= -1 then Append (Result, Str (Start .. S - 1)); Start := -1; end if; Append (Result, Character'Val (Qp_Convert (Str (S + 1)) * 16 + Qp_Convert (Str (S + 2)))); S := S + 2; else -- Invalid quote sequence. Leave it as is if Start /= -1 then Append (Result, Str (Start .. S - 1)); Start := -1; end if; end if; S := S + 1; end loop; if Start /= -1 then Append (Result, Str (Start .. Str'Last)); end if; end Quoted_Printable_Decode; ------------------- -- Base64_Encode -- ------------------- procedure Base64_Encode (Str : String; Charset : String; Max_Block_Len : Integer := Integer'Last; Where : Region := Text; Result : out Unbounded_String) is Block_Prefix : constant String := (if Where in Any_Header then "=?" & Charset & "?b?" else ""); Block_Suffix : constant String := (if Where in Any_Header then "?=" else ""); Block_Separator : constant String := (if Where in Any_Header then " " else (1 => ASCII.LF)); -- In Text, use a soft line break as line separator Max : constant Natural := 4 * Integer'Max (1, (Integer'Min (Max_Block_Len, (if Where in Any_Header then 75 else 76)) - Block_Prefix'Length - Block_Suffix'Length) / 4); -- Maximum length of encoded data within an encoded block (must be -- a non-null multiple of 4). Note: block separator does not contain -- any printable character, so does not count against the limit. Encoded_Len : constant Integer := (Str'Length + 2) / 3 * 4; -- Each group of 3 input bytes yields 4 output bytes, including a -- trailing incomplete group. Blocks : constant Integer := (Encoded_Len + Max - 1) / Max; Encoded_Block_Len : constant Integer := Block_Prefix'Length + Max + Block_Suffix'Length + Block_Separator'Length; -- Allocation size for each block Len : constant Integer := Blocks * Encoded_Block_Len; -- Pre-allocation length. This is sufficient to accomodate the entire -- encoded data, split into blocks, except if some blocks need to be -- flushed early (while incomplete) in order to avoid incorrect -- splitting of multi-byte sequences. Output : Ada.Strings.Unbounded.String_Access := new String (1 .. Len); Index : Integer := Output'First; Left : Unsigned_16 := 0; Leftbits : Natural := 0; Ch : Mod64; Current : Integer := 0; procedure Append (Ch : Character); -- Append a new character to the output, splitting lines as necessary ------------ -- Append -- ------------ procedure Append (Ch : Character) is New_Output : Ada.Strings.Unbounded.String_Access; begin if Current = 0 then -- Make sure that the string has sufficient space for the -- full new encoded block if Output'Last - Index + 1 < Encoded_Block_Len then New_Output := new String (1 .. Output'Length + Encoded_Block_Len); New_Output (1 .. Index - 1) := Output (1 .. Index - 1); Free (Output); Output := New_Output; end if; Output (Index .. Index + Block_Prefix'Length - 1) := Block_Prefix; Index := Index + Block_Prefix'Length; end if; Output (Index) := Ch; Index := Index + 1; Current := Current + 1; if Current = Max then -- Append suffix and separator Output (Index .. Index + Block_Suffix'Length + Block_Separator'Length - 1) := Block_Suffix & Block_Separator; Index := Index + Block_Suffix'Length + Block_Separator'Length; Current := 0; end if; end Append; procedure Encode_Append (Str : String); -- Encode Str and append result to output, splitting if necessary. -- If Where is Any_Header, then never split Str across two different -- blocks. procedure Flush; -- Flush pending bits, outputting padding characters if necessary procedure Encode_Append (Str : String) is Out_Chars : constant Integer := (Leftbits + Str'Length * 8 + 5) / 6; begin -- Force flushing now if in header mode and encoded sequence would -- exceed maximum length. if Where in Any_Header and then Current + Out_Chars > Max then Flush; end if; for J in Str'Range loop Left := Shift_Left (Left, 8) or Character'Pos (Str (J)); Leftbits := Leftbits + 8; while Leftbits >= 6 loop Ch := Mod64 ((Shift_Right (Left, Leftbits - 6)) and 16#3f#); Leftbits := Leftbits - 6; Append (To_Base64 (Ch)); end loop; end loop; end Encode_Append; ----------- -- Flush -- ----------- procedure Flush is begin case Leftbits is when 0 => null; when 2 => Ch := Mod64 (Shift_Left (Left and 3, 4)); Append (To_Base64 (Ch)); Append ('='); Append ('='); when 4 => Ch := Mod64 (Shift_Left (Left and 16#F#, 2)); Append (To_Base64 (Ch)); Append ('='); when others => raise Program_Error with "invalid Base64 encoder state"; end case; Left := 0; Leftbits := 0; end Flush; Start, Next : Integer; -- Start of current encoded sequence, -- start of next encoded sequence, -- last element of previous encoded sequence. Next_Char : constant Next_Char_Acc := (if Where in Any_Header then Next_Char_For_Charset (Charset) else Single_Byte_Next_Char'Access); -- In message bodies, multi-byte encodings can be -- split across multiple lines; in headers, they can't -- be split across multiple encoded words. -- Start of processing for Base64_Encode begin Next := Str'First; loop Start := Next; exit when Start > Str'Last; -- Find end of possibly multibyte sequence starting at Start Next := Start; Next_Char_Ignore_Invalid (Next_Char, Str, Next); Encode_Append (Str (Start .. Next - 1)); end loop; Flush; if Current = 0 then -- Remove last separator Index := Index - Block_Separator'Length; elsif Current > 0 then Output (Index .. Index + Block_Suffix'Length - 1) := Block_Suffix; Index := Index + Block_Suffix'Length; end if; if Output'Last /= Index - 1 then Set_Unbounded_String (Result, Output (1 .. Index - 1)); else Set_Unbounded_String (Result, Output.all); end if; Free (Output); end Base64_Encode; ------------------- -- Base64_Decode -- ------------------- procedure Base64_Decode (Str : String; Result : out Unbounded_String) is type Phase_Type is mod 4; -- We must use the heap rather than the stack here. In some -- cases, we'll be able to avoid a copy of the string anyway, -- and in case where this code is run in a multi-threaded -- application, the stack size is generally too small anyway Output : Ada.Strings.Unbounded.String_Access := new String (1 .. Str'Length * 6 / 8); Index : Integer := Output'First; Phase : Phase_Type := 0; D, Dlast : Byte := 0; begin for S in Str'First .. Str'Last loop if Str (S) = ASCII.LF or else Str (S) = ASCII.CR then Phase := 0; Dlast := 0; else D := Base64_Convert (Str (S)); if D /= -1 then case Phase is when 0 => Phase := Phase + 1; when 1 => Output (Index) := Character'Val (Dlast * 4 or ((D and 16#30#) / 16)); Index := Index + 1; Phase := Phase + 1; when 2 => Output (Index) := Character'Val (((Dlast and 16#F#) * 16) or ((D and 16#3C#) / 4)); Index := Index + 1; Phase := Phase + 1; when 3 => Output (Index) := Character'Val (((Dlast and 16#3#) * 64) or D); Index := Index + 1; Phase := 0; end case; Dlast := D; end if; end if; end loop; if Index - 1 = Output'Last then Set_Unbounded_String (Result, Output.all); else Set_Unbounded_String (Result, Output (Output'First .. Index - 1)); end if; Free (Output); end Base64_Decode; ------------ -- Encode -- ------------ procedure Encode (Str : String; Charset : String := Charset_US_ASCII; Where : Region := Text; Result : out Unbounded_String) is Encoding : Encoding_Type; Set : constant String := To_Lower (Charset); begin -- Preferred encoding are the same as in Python if Set = Charset_US_ASCII then Encoding := Encoding_7bit; elsif Set = Charset_ISO_8859_1 or else Set = "latin_1" or else Set = "latin-1" or else Set = Charset_ISO_8859_2 or else Set = "latin_2" or else Set = "latin-2" or else Set = Charset_ISO_8859_3 or else Set = "latin_3" or else Set = "latin-3" or else Set = Charset_ISO_8859_4 or else Set = "latin_4" or else Set = "latin-4" or else Set = Charset_ISO_8859_9 or else Set = "latin_5" or else Set = "latin-5" or else Set = Charset_ISO_8859_10 or else Set = "latin_6" or else Set = "latin-6" or else Set = Charset_ISO_8859_13 or else Set = "latin_7" or else Set = "latin-7" or else Set = Charset_ISO_8859_14 or else Set = "latin_8" or else Set = "latin-8" or else Set = Charset_ISO_8859_15 or else Set = "latin_9" or else Set = "latin-9" or else Set = Charset_Windows_1252 or else Set = "viscii" or else Set = Charset_UTF_8 or else Set = "utf8" then Encoding := Encoding_QP; else Encoding := Encoding_Base64; end if; case Encoding is when Encoding_Base64 => Base64_Encode (Str, Charset => Set, Where => Where, Result => Result); when Encoding_QP => Quoted_Printable_Encode (Str, Charset => Set, Where => Where, Result => Result); when others => Result := To_Unbounded_String (Str); end case; end Encode; ------------------- -- Decode_Header -- ------------------- procedure Decode_Header (Str : String; Default_Charset : String := Charset_US_ASCII; Result : out Charset_String_List.List; Where : Any_Header := Other_Header) is use Charset_String_List; Start : Integer; Index : Integer; Index2 : Integer; Section : Charset_String; Encoding : Encoding_Type; S : Integer; procedure Append (Section : Charset_String); -- Add Section to the result, merging with previous section if needed. -- If Section.Charset is empty, use Default_Charset, or Charset_US_ASCII -- if possible. ------------ -- Append -- ------------ procedure Append (Section : Charset_String) is NSection : Charset_String := Section; begin if NSection.Charset = Null_Unbounded_String then declare Raw_Str : Ada.Strings.Unbounded.Aux.Big_String_Access; Raw_Last : Integer; begin Ada.Strings.Unbounded.Aux.Get_String (NSection.Contents, Raw_Str, Raw_Last); for J in Raw_Str'First .. Raw_Last loop if Character'Pos (Raw_Str (J)) not in 32 .. 126 then NSection.Charset := To_Unbounded_String (Default_Charset); exit; end if; end loop; if NSection.Charset = Null_Unbounded_String then NSection.Charset := U_Charset_US_ASCII; end if; end; end if; -- Now append the new section to the sequence if Is_Empty (Result) then Append (Result, NSection); else -- An empty section between two encoded ones must be ignored if NSection.Charset /= Default_Charset and then Element (Last (Result)).Charset = Default_Charset then declare Previous : constant Unbounded_String := Element (Last (Result)).Contents; begin if Index_Non_Blank (Previous) < 1 then Delete_Last (Result); end if; end; end if; -- Try to merge Section with previous one, if possible if not Is_Empty (Result) and then NSection.Charset = Element (Last (Result)).Charset then Replace_Element (Result, Last (Result), (Contents => Element (Last (Result)).Contents & NSection.Contents, Charset => NSection.Charset)); else Append (Result, NSection); end if; end if; end Append; -- Start of processing for Decode_Header begin Result := Charset_String_List.Empty_List; S := Str'First; Start := Str'First; while S < Str'Last loop if Str (S) = '=' and then S < Str'Last and then Str (S + 1) = '?' then Index := Next_Occurrence (Str (S + 2 .. Str'Last), '?'); if Index < Str'Last then Section.Charset := To_Unbounded_String (To_Lower (Str (S + 2 .. Index - 1))); case To_Lower (Str (Index + 1)) is when 'q' => Encoding := Encoding_QP; when 'b' => Encoding := Encoding_Base64; when others => Encoding := Encoding_7bit; end case; if Encoding /= Encoding_7bit and then Index + 2 < Str'Last then if Str (Index + 2) = '?' then -- So far we have the prefix =??? Index2 := Index + 3; Index := Next_Occurrence (Str (Index2 .. Str'Last), '?'); if Index < Str'Last and then Str (Index + 1) = '=' then case Encoding is when Encoding_QP => Quoted_Printable_Decode (Str (Index2 .. Index - 1), Where => Where, Result => Section.Contents); when Encoding_Base64 => Base64_Decode (Str (Index2 .. Index - 1), Result => Section.Contents); when others => null; end case; -- Deal with non-encoded-word part: charset is -- set to Default_Charset, unless the string has -- no character which need to be encoded, in which -- case use US-ASCII instead. if Start <= S - 1 then declare Raw_Section : String renames Str (Start .. S - 1); -- Part of Str that is not an encoded-word begin Append ((Contents => To_Unbounded_String (Raw_Section), Charset => Null_Unbounded_String)); end; end if; Append (Section); S := Index + 2; Start := S; else S := Index2; end if; else S := Index + 1; end if; else S := Index + 1; end if; end if; end if; S := S + 1; end loop; if Start <= Str'Last then Append ((Contents => To_Unbounded_String (Str (Start .. Str'Last)), Charset => Null_Unbounded_String)); end if; end Decode_Header; ------------------- -- Get_Main_Type -- ------------------- function Get_Main_Type (MIME_Type : String) return String is begin for M in MIME_Type'Range loop if MIME_Type (M) = '/' then return MIME_Type (MIME_Type'First .. M - 1); end if; end loop; return MIME_Type; end Get_Main_Type; ------------------ -- Get_Sub_Type -- ------------------ function Get_Sub_Type (MIME_Type : String) return String is begin for M in MIME_Type'Range loop if MIME_Type (M) = '/' then if M + 1 <= MIME_Type'Last then return MIME_Type (M + 1 .. MIME_Type'Last); else return ""; end if; end if; end loop; return MIME_Type; end Get_Sub_Type; end GNATCOLL.Email.Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-email-utils.ads000066400000000000000000000273001425465243200236260ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package contains various utility routines related to handling of -- email messages with Ada.Calendar; with Ada.Containers.Hashed_Sets; package GNATCOLL.Email.Utils is type Region is (Addr_Header, Other_Header, Text); subtype Any_Header is Region range Addr_Header .. Other_Header; -- Used to indicate where a given character occurs: -- Addr_Header: From/To/Cc header -- Header: any other header -- Text: message body ----------- -- Dates -- ----------- type Time_Format is (Time_RFC2822, Time_Envelope); -- The time formats supported by this package. -- Time_RFC2822 is the one used in the Date: header. -- Time_Enveloppe is the one used in the From_ header function To_Time (Date : String; Format : Time_Format := Time_RFC2822) return Ada.Calendar.Time; -- Interprets the Date as a date/time, and returns it. The time is UTC. -- If Date doesn't match Format, No_Time is returned. function Format_Date (Date : Ada.Calendar.Time; Use_GMT : Boolean := False; From_Line : Boolean := False; No_TZ : Boolean := False; Show_Time : Boolean := True; Show_Seconds : Boolean := True; Show_Day : Boolean := True) return String; -- Format the date as a RFC 2822 string, eg: -- Fri, 09 Nov 2001 01:08:47 -0000 -- If Use_GMT is true, the time stamp is rendered in UTC, and the time zone -- is shown as "GMT". This is needed for some protocols. -- If From_Line is True, use the format of standard UNIX mailbox From_ -- lines: -- Tue Jan 24 14:48:49 2006 +0100 -- If No_TZ is true, then the date is rendered in UTC, and no time zone -- name is shown. -- If Show_Seconds is false, then seconds will not be displayed (this can -- be used to save space, but the output format is not compatible with -- RFC 2822). -- If Show_Day is false, the day of week is not displayed. The output is -- also not compatible with RFC 2822. function Format_Time (Date : Ada.Calendar.Time) return String; -- Format the time part of Date, interpreted in UTC, as a RFC2822 string: -- 01:08:47 --------------- -- Addresses -- --------------- function Hash (Addr : Email_Address) return Ada.Containers.Hash_Type; package Address_Set is new Ada.Containers.Hashed_Sets (Email_Address, Hash, "="); function Quote (Str : String) return String; -- Return a string which is a quoted version of Str: backslashes have been -- replaced by \\, and double-quotes by \". function Unquote (Str : String) return String; -- Return an unquoted version of Str. Extra Backslashes are removed function Parse_Address (Email : String) return Email_Address; -- Split an email address as read from a message header into its -- constituents function To_Address (Address : String; Real_Name : String := "") return Email_Address; -- Create an Email_Address from the given parts function Get_Addresses (Str : String) return Address_Set.Set; function Get_Addresses (Str : Charset_String_List.List) return Address_Set.Set; -- Return the list of addresses in Str. -- The second version properly preserves real names from extended charsets. function To_String (Addresses : Address_Set.Set; Separator : String := ", "; Address_Only : Boolean := False; Charset : String := Charset_US_ASCII) return String; -- Return the list of addresses as a string compatible with RFC 2822. -- Parsing this field with Get_Addresses would return the same set of -- addresses of Separator has its default value. -- If Address_Only is true, then the real names are never shown in the -- string. -- Charset is passed to Format_Address to format indivudual addresses. function Get_Recipients (Msg : Message'Class; Include_From : Boolean := False) return Address_Set.Set; function Get_Recipients (H : Header'Class) return Address_Set.Set; -- Return the list of all recipients of the message. This takes into -- account all occurrences of all relevant headers. -- In the first case, Include_From indicates whether the sender of the -- message should also be returned. For Null_Message, return an empty set. -- ??? The 2nd function should be renamed to Get_Addresses since it applies -- to all headers containing addresses, not only those designating -- message recipients. function Legacy_Format_Address (Real : String; Address : String) return String; -- Format the given email address and real name, using quotes and -- backslash escaping to protect any special characters occurring in Real. -- Note: Real should be a US ASCII string. function Format_Address (Email : Email_Address; Charset : String := Charset_US_ASCII) return Charset_String_List.List; -- Format an email address into a proper format for RFC2822 -- Charset specifies the character set for the real name. function Format_Address (Email : Email_Address; Charset : String := Charset_US_ASCII) return Unbounded_String; -- Same as above, and return result as an RFC 2047 encoded string function Domain_From_Address (Email : String) return String; function Domain_From_Address (Email : Email_Address) return String; -- Return the domain name for the given Email address. In the first case, -- Email must only contain the address, not the real name. -- If no domain is specified, the empty string is returned. Look at -- GNAT.Socket.Host_Name to fall back on the current host. function Login_From_Address (Email : String) return String; function Login_From_Address (Email : Email_Address) return String; -- Return the login name from the given email address, ie the part before -- the '@'. In the first case, Email must only contain the address, not the -- real name. ---------- -- Mime -- ---------- function Get_Main_Type (MIME_Type : String) return String; -- Return the main type component of the MIME_Type, for instance "text" -- when the type is "text/plain"; function Get_Sub_Type (MIME_Type : String) return String; -- Return the sub type component of the MIME_Type, for instance "plain" -- when the type is "text/plain"; --------------- -- Encodings -- --------------- procedure Quoted_Printable_Encode (Str : String; Charset : String; Max_Block_Len : Integer := Integer'Last; Where : Region := Text; Result : out Unbounded_String); -- Encode Str in quoted-printable format, as per RFC 2045/2047. -- This should be used for ascii-like charsets, like all iso-8859-* -- charsets, ie when most of the characters are already in the ASCII -- charset (0 through 127). procedure Quoted_Printable_Decode (Str : String; Result : out Unbounded_String; Where : Region := Text); -- Decode Str as a quoted-printable encoded string as per RFC 2045. -- The returned value may contain non - ASCII characters, their -- interpretation is left to the called (ie the charset is unknown). -- If the optional argument header is present and true, underscore will be -- decoded as space. This is used to decode "Q" encoded headers as -- described in RFC 2047: "MIME (Multipurpose Internet Mail Extensions) -- Part Three: Message Header Extensions for Non-ASCII Text". procedure Base64_Encode (Str : String; Charset : String; Max_Block_Len : Integer := Integer'Last; Where : Region := Text; Result : out Unbounded_String); -- Encode Str in base64 format, as defined by RFC 2045. -- This should be used for charsets that have little similarity with -- ASCII, for instance asian charsets. procedure Base64_Decode (Str : String; Result : out Unbounded_String); -- Decode Str from a base64 encoding, as defined by RFC 2045 procedure Encode (Str : String; Charset : String := Charset_US_ASCII; Where : Region := Text; Result : out Unbounded_String); -- Encode Str in the best encoding to use for Charset. The encoding depends -- on how close charset is to ASCII. -- If Header is true, then several encoded blocks will be created as -- required by RFC 2045 (separated by spaces). In addition, the charset is -- included as part of the encoded field, as suitable for mail headers. procedure Decode_Header (Str : String; Default_Charset : String := Charset_US_ASCII; Result : out Charset_String_List.List; Where : Any_Header := Other_Header); -- Decode Str. It might contain several mime-encoded sections, with -- different charsets. Each section is returned separately. For each -- section, Contents must be interpreted in the context of that charset. -- When several adjacent sections have the same encoding, they are merged -- for ease of use. -- When no charset is specified for a section, the default charset is -- assumed. -- This function can also be used for headers, when each section starts -- with =?charset?q?....?=. -------------- -- Charsets -- -------------- procedure Flatten (List : Charset_String_List.List; Result : out Unbounded_String); -- Return a flatten version of List, where all sections are concatenated. -- It will not be possible to go back to List afterward, since the sections -- are not MIME-encoded, only their contents is taken into account. -- This should never be used for display to the user, only for internal -- manipulation when the exact charset of each section is irrelevant. procedure To_String (List : Charset_String_List.List; Result : out Unbounded_String; Where : Any_Header := Other_Header); -- Return a single string representing list, where all sections is -- properly encoded and surrounded by =?charset? markers. end GNATCOLL.Email.Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-email.adb000066400000000000000000002071501425465243200224520ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ pragma Ada_2012; with Ada.Calendar; use Ada.Calendar; with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Containers; use Ada.Containers; with Ada.Strings.Fixed; use Ada.Strings.Fixed; with Ada.Text_IO; use Ada.Text_IO; with Ada.Unchecked_Deallocation; with GNATCOLL.Email.Utils; use GNATCOLL.Email.Utils; with GNATCOLL.Utils; use GNATCOLL.Utils; with GNATCOLL.VFS; use GNATCOLL.VFS; with GNAT.Strings; use GNAT.Strings; package body GNATCOLL.Email is use Header_List, Charset_String_List, Message_List; function Identify_Header (Name : String) return Any_Header; -- Determine whether Name is the name of an Addr_Header or Other_Header procedure To_String (Payload : Message_Payload; Header_Max_Line_Len : Positive; Content_Filter : Payload_Filter := null; Msg : Message'Class; Append_To : in out Unbounded_String); -- Encode the payload in a form suitable to send the message. -- If necessary, this creates the "boundary" for the message. procedure To_String (Headers : Header_List.List; Header_Max_Line_Len : Positive; Subject_Max_Line_Len : Positive; Filter : Header_Filter := null; Append_To : in out Unbounded_String); -- Encode the headers in a form suitable to send the message procedure Get_Param_Index (H : Header'Class; Param_Name : String; C : out Charset_String_List.Cursor; Semicolon : out Integer; Name_Start : out Integer; Name_End : out Integer; Value_End : out Integer); -- Find the occurrence of a parameter in the value of H procedure Replace_Header_Internal (Msg : Message'Class; H : Header'Class; Append : Boolean); -- Same as Replace_Header, but Append can be used to specify whether the -- header should be appended or prepended to the list if it didn't exist -- yet. function Check_Boundary (Msg : Message'Class; Boundary : String) return Boolean; -- Whether Boundary can be used for this message function Has_Line_Starting_With (Text : Unbounded_String; Starts_With : String) return Boolean; -- Whether Text has a line that starts with Starts_With function Clone_Header (Ref : Header) return Header; -- Return a deep copy of the given Header. function Clone_Headers (Ref : Header_List.List) return Header_List.List; -- Return a deep copy of the given list of headers. type Constant_String_Access is access constant String; Encoding_Names : constant array (Encoding_Type) of Constant_String_Access := (Encoding_7bit => new String'("7bit"), Encoding_8bit => new String'("8bit"), Encoding_Binary => new String'("binary"), Encoding_QP => new String'("quoted-printable"), Encoding_Base64 => new String'("base64")); --------- -- "=" -- --------- function "=" (Addr1, Addr2 : Email_Address) return Boolean is begin return To_Lower (To_String (Addr1.Address)) = To_Lower (To_String (Addr2.Address)); end "="; --------------------- -- Next_Occurrence -- --------------------- function Next_Occurrence (S : String; Char : Character; Skip_Quotes : Boolean := False) return Integer is In_Quotes : Boolean := False; begin for Index in S'Range loop if Skip_Quotes and then S (Index) = '"' then In_Quotes := not In_Quotes; elsif S (Index) = Char and then not In_Quotes then return Index; end if; end loop; return S'Last + 1; end Next_Occurrence; --------------------- -- Identify_Header -- --------------------- function Identify_Header (Name : String) return Any_Header is L_Name : constant String := To_Lower (Name); begin if L_Name = "from" or else L_Name = "sender" or else L_Name = "to" or else L_Name = "cc" or else L_Name = "bcc" then return Addr_Header; else return Other_Header; end if; end Identify_Header; ------------------- -- Is_Whitespace -- ------------------- function Is_Whitespace (Char : Character) return Boolean is begin return Char = ' ' or Char = ASCII.HT; end Is_Whitespace; ---------------------- -- Skip_Whitespaces -- ---------------------- procedure Skip_Whitespaces (S : String; Index : in out Integer) is begin while Index <= S'Last and then (Is_Whitespace (S (Index)) or else S (Index) = ASCII.LF) loop Index := Index + 1; end loop; end Skip_Whitespaces; ----------------- -- New_Message -- ----------------- function New_Message (MIME_Type : String := Text_Plain; Charset : String := Charset_US_ASCII) return Message is Pay : Message_Payload; Msg : Message; begin if Get_Main_Type (MIME_Type) = "multipart" then Pay := Null_Multipart_Payload; else Pay := Null_Payload; end if; Msg := (Ada.Finalization.Controlled with Contents => new Message_Record' (Ref_Count => 1, Envelope_From => Null_Unbounded_String, Headers => Header_List.Empty_List, Is_Nested => False, Payload => Pay)); if MIME_Type /= "" then Replace_Header (Msg, Create ("Content-Type", MIME_Type & "; charset=""" & Charset & '"')); end if; return Msg; end New_Message; ------------------ -- Clone_Header -- ------------------ function Clone_Header (Ref : Header) return Header is Copy : constant Header := (Ada.Finalization.Controlled with Contents => new Header_Record); begin Copy.Contents.all := (Name => Ref.Contents.Name, Value => Ref.Contents.Value, Ref_Count => 1); return Copy; end Clone_Header; ------------------- -- Clone_Headers -- ------------------- function Clone_Headers (Ref : Header_List.List) return Header_List.List is Copy : Header_List.List; Cursor : Header_List.Cursor := First (Ref); begin while Cursor /= Header_List.No_Element loop Append (Copy, Clone_Header (Element (Cursor))); Next (Cursor); end loop; return Copy; end Clone_Headers; ------------------- -- Clone_Message -- ------------------- function Clone_Message (Msg : Message) return Message is New_Msg : Message; begin New_Msg := (Ada.Finalization.Controlled with Contents => new Message_Record); New_Msg.Contents.all := (Ref_Count => 1, Envelope_From => Msg.Contents.Envelope_From, Headers => Clone_Headers (Msg.Contents.Headers), Payload => Msg.Contents.Payload, Is_Nested => Msg.Contents.Is_Nested); return New_Msg; end Clone_Message; -------------- -- Reply_To -- -------------- function Reply_To (Msg : Message'Class; From_Email : String; From_Real_Name : String := ""; Quote : Boolean := True; Reply_All : Boolean := True; Reply_Filter : access function (Recipient : Email_Address) return Boolean := null; Local_Date : Ada.Calendar.Time := Ada.Calendar.Clock; Charset : String := Charset_US_ASCII) return Message is Reply : Message := New_Message; H, H2, H3 : Header; Is_First : Boolean; To_Quote : Unbounded_String; Part_Iter : Payload_Iterator; Payload : Message; Who_Quoted : Unbounded_String; begin Set_Envelope_From (Reply, From_Email, Local_Date); H := Get_Header (Msg, "Subject"); if H /= Null_Header then H2 := Create ("Subject", "Re: "); Append (H2, Get_Value (H)); Replace_Header_Internal (Reply, H2, Append => False); end if; Replace_Header_Internal (Reply, Create ("Date", Format_Date (Local_Date)), Append => False); Set_From_Header (Reply, From_Email, From_Real_Name, Charset); H := Get_Header (Msg, "From"); H2 := Create ("To", ""); if H /= Null_Header then Append (H2, Get_Value (H)); Flatten (H.Contents.Value, Result => Who_Quoted); Who_Quoted := Parse_Address (To_String (Who_Quoted)).Address; end if; Add_Header (Reply, H2); if Reply_All then H2 := Create ("Cc", ""); Is_First := True; for Recipient of Get_Recipients (Msg) loop if Reply_Filter = null or else Reply_Filter (Recipient) then if Is_First then Is_First := False; else Append (H2, ", "); end if; Append (H2, Format_Address (Recipient)); end if; end loop; if not Is_First then Add_Header (Reply, H2); end if; end if; H := Get_Header (Msg, "Message-Id"); if H /= Null_Header then H2 := Create ("In-Reply-To", ""); Append (H2, Get_Value (H)); Add_Header (Reply, H2); H2 := Create ("References", ""); H3 := Get_Header (Msg, "References"); if H3 /= Null_Header then Append (H2, Get_Value (H3)); else H3 := Get_Header (Msg, "In-Reply-To"); if H3 /= Null_Header then Append (H2, Get_Value (H3)); end if; end if; Append (H2, Get_Value (H)); Add_Header (Reply, H2); end if; if Quote then if Is_Multipart (Msg) then To_Quote := Null_Unbounded_String; Part_Iter := Get_Payload (Msg); loop Next (Part_Iter, Item => Payload); exit when Payload = Null_Message; if Get_Main_Type (Get_Content_Type (Payload)) = "text" then Get_Single_Part_Payload (Payload, To_Quote, Decode => True); exit; end if; end loop; elsif Get_Main_Type (Get_Content_Type (Msg)) = "text" then Get_Single_Part_Payload (Msg, To_Quote, Decode => True); else To_Quote := Null_Unbounded_String; end if; if To_Quote /= Null_Unbounded_String then if Who_Quoted /= Null_Unbounded_String then Append (Who_Quoted, " wrote:" & ASCII.LF); end if; declare StrA : constant String := To_String (To_Quote); Start, Eol : Integer; begin Start := StrA'First; while Start <= StrA'Last loop Eol := Integer'Min (StrA'Last, Next_Occurrence (StrA (Start .. StrA'Last), ASCII.LF)); Append (Who_Quoted, "> " & StrA (Start .. Eol)); Start := Eol + 1; end loop; Set_Text_Payload (Reply, Who_Quoted); end; end if; end if; return Reply; end Reply_To; ------------------------- -- Set_Default_Headers -- ------------------------- procedure Set_Default_Headers (Msg : in out Message'Class; From_Email : String; Subject : String := "No Subject"; From_Real_Name : String := ""; Local_Date : Ada.Calendar.Time := Ada.Calendar.Clock; Charset : String := Charset_US_ASCII) is begin Set_Envelope_From (Msg, From_Email, Local_Date); Replace_Header_Internal (Msg, Create ("Subject", Subject, Charset), Append => False); Replace_Header_Internal (Msg, Create ("Date", Format_Date (Local_Date)), Append => False); Set_From_Header (Msg, From_Email, From_Real_Name, Charset); end Set_Default_Headers; --------------------- -- Set_From_Header -- --------------------- procedure Set_From_Header (Msg : in out Message'Class; From_Email : String; From_Real_Name : String; Charset : String) is From_H : Header; begin From_H := Create ("From", Charset_String_List.List'(Format_Address (Email => (Real_Name => To_Unbounded_String (From_Real_Name), Address => To_Unbounded_String (From_Email)), Charset => Charset))); Replace_Header_Internal (Msg, From_H, Append => False); end Set_From_Header; ------------ -- Adjust -- ------------ procedure Adjust (Msg : in out Message) is begin if Msg.Contents /= null then Msg.Contents.Ref_Count := Msg.Contents.Ref_Count + 1; end if; end Adjust; -------------- -- Finalize -- -------------- procedure Finalize (Msg : in out Message) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Message_Record, Message_Access); Contents : Message_Access := Msg.Contents; begin Msg.Contents := null; -- Make Finalize idempotent if Contents /= null then Contents.Ref_Count := Contents.Ref_Count - 1; if Contents.Ref_Count = 0 then Unchecked_Free (Contents); end if; end if; end Finalize; ----------------------- -- Set_Envelope_From -- ----------------------- procedure Set_Envelope_From (Msg : in out Message'Class; From : String) is begin Msg.Contents.Envelope_From := To_Unbounded_String (From); end Set_Envelope_From; ----------------------- -- Set_Envelope_From -- ----------------------- procedure Set_Envelope_From (Msg : in out Message'Class; Email : String; Local_Date : Ada.Calendar.Time) is begin Msg.Contents.Envelope_From := To_Unbounded_String ("From " & Email & " " & Format_Date (Local_Date, From_Line => True)); end Set_Envelope_From; ----------------------- -- Get_Envelope_From -- ----------------------- function Get_Envelope_From (Msg : Message'Class) return String is begin return To_String (Msg.Contents.Envelope_From); end Get_Envelope_From; ------------------------ -- Date_From_Envelope -- ------------------------ function Date_From_Envelope (Msg : Message'Class) return Ada.Calendar.Time is Str : constant String := To_String (Msg.Contents.Envelope_From); Index : Natural := Str'First; begin if Str = "" then return No_Time; end if; Index := Index + 5; -- Skips "From " Skip_Whitespaces (Str, Index); while Index <= Str'Last and then not Is_Whitespace (Str (Index)) loop Index := Index + 1; end loop; return To_Time (Str (Index .. Str'Last), Format => Time_Envelope); end Date_From_Envelope; -------------------------- -- Sender_From_Envelope -- -------------------------- function Sender_From_Envelope (Msg : Message'Class) return String is Str : constant String := To_String (Msg.Contents.Envelope_From); Index : Natural := Str'First + 5; -- Skips "From" Stop : Natural; begin Skip_Whitespaces (Str, Index); Stop := Index; while Stop <= Str'Last and then not Is_Whitespace (Str (Stop)) loop Stop := Stop + 1; end loop; return Str (Index .. Stop - 1); end Sender_From_Envelope; ------------ -- Create -- ------------ function Create (Name : String; Value : String; Charset : String := Charset_US_ASCII) return Header is V : Charset_String_List.List; begin Decode_Header (Value, Default_Charset => Charset, Result => V, Where => Identify_Header (Name)); return Create (Name, V); end Create; function Create (Name : String; Value : Charset_String_List.List) return Header is begin return (Ada.Finalization.Controlled with Contents => new Header_Record' (Name => To_Unbounded_String (To_Lower (Name)), Value => Value, others => <>)); end Create; ------------ -- Append -- ------------ procedure Append (H : in out Header'Class; Value : String; Charset : String := Charset_US_ASCII) is L : Charset_String_List.List; begin Decode_Header (Value, Default_Charset => Charset, Result => L, Where => Identify_Header (To_String (H.Contents.Name))); Splice (H.Contents.Value, Charset_String_List.No_Element, L); end Append; ------------ -- Append -- ------------ procedure Append (H : in out Header'Class; Value : Charset_String_List.List) is C : Charset_String_List.Cursor := First (Value); begin while Has_Element (C) loop Append (H.Contents.Value, Element (C)); Next (C); end loop; end Append; --------------- -- To_String -- --------------- procedure To_String (H : Header'Class; Max_Line_Len : Positive := Default_Max_Header_Line_Length; Show_Header_Name : Boolean := True; Result : out Unbounded_String) is begin if H.Contents = null then Result := Null_Unbounded_String; return; end if; declare Max : Positive := Max_Line_Len - 2 - Length (H.Contents.Name); N : String := To_String (H.Contents.Name); Value : constant Charset_String_List.List := Get_Value (H); Encoded : Unbounded_String; Uppercase_Next : Boolean; Next : Natural; begin To_String (Value, Encoded, Identify_Header (N)); if Show_Header_Name then -- Fix up casing of header name if N = "message-id" then N := Message_ID; elsif N = "cc" then N := CC; else if N'Length >= 5 and then N (N'First .. N'First + 4) = "mime-" then N (N'First .. N'First + 3) := "MIME"; Next := N'First + 5; else Next := N'First; end if; Uppercase_Next := True; while Next <= N'Last loop if Uppercase_Next then N (Next) := To_Upper (N (Next)); Uppercase_Next := False; end if; if N (Next) = '-' then Uppercase_Next := True; end if; Next := Next + 1; end loop; end if; end if; -- Fold continuation lines declare Str : String := To_String (Encoded); Last : Natural; Index, Index2 : Integer; Offset : Integer := 0; -- Count of LF characters skipped so far begin -- Flatten the header on a single line, eliminating newline -- characters. for J in Str'Range loop if Str (J) = ASCII.LF then Offset := Offset + 1; elsif Offset > 0 then Str (J - Offset) := Str (J); end if; end loop; Last := Str'Last - Offset; if Show_Header_Name and then Last <= Max then if Last = 0 then -- Empty header Result := To_Unbounded_String (N & ": "); elsif Element (Encoded, 1) = ' ' then Result := To_Unbounded_String (N & ':' & Str (1 .. Last)); else Result := To_Unbounded_String (N & ": " & Str (1 .. Last)); end if; return; elsif not Show_Header_Name and then Last <= Max_Line_Len then if Offset = 0 then Result := Encoded; -- Save a string copy else Result := To_Unbounded_String (Str (1 .. Last)); end if; return; end if; Result := Null_Unbounded_String; Index := Str'First; while Index <= Last loop -- Only split on spaces. To keep Content-Type headers as much -- as possible on a single line, we split on the first blank -- space after the theoretical split point. Index2 := Integer'Min (Index + Max - 1, Last); loop Index2 := Index2 + 1; exit when Index2 > Last or else Str (Index2) = ' '; end loop; -- Index2 points right after last non-blank character Append (Result, Str (Index .. Index2 - 1)); -- Do not print a last line containing only white spaces, this -- might confuse mailers. if Index2 < Last then Append (Result, ASCII.LF & ' '); end if; Index := Index2 + 1; Max := Max_Line_Len; end loop; if Show_Header_Name then if Length (Result) = 0 or else Element (Result, 1) = ' ' then Result := N & ':' & Result; else Result := N & ": " & Result; end if; end if; end; end; end To_String; function To_String (H : Header'Class; Max_Line_Len : Positive := Default_Max_Header_Line_Length; Show_Header_Name : Boolean := True) return String is Result : Unbounded_String; begin To_String (H, Max_Line_Len, Show_Header_Name, Result); return To_String (Result); end To_String; --------------- -- To_String -- --------------- procedure To_String (Payload : Message_Payload; Header_Max_Line_Len : Positive; Content_Filter : Payload_Filter := null; Msg : Message'Class; Append_To : in out Unbounded_String) is C : Message_List.Cursor; Attachment : Message; begin case Payload.Multipart is when True => declare Parts : array (1 .. Length (Payload.Parts)) of Boolean := (others => True); Payload_Count : Natural := Parts'Length; begin -- First check how many payloads needs to be output if Content_Filter /= null then C := First (Payload.Parts); Payload_Count := 0; for P in Parts'Range loop Parts (P) := Content_Filter (Element (C)); if Parts (P) then Payload_Count := Payload_Count + 1; end if; Next (C); end loop; end if; -- At least one payload : create a boundary if necessary if Payload_Count > 0 then Set_Boundary (Msg); end if; declare Boundary : constant String := Get_Boundary (Msg); begin if Payload.Preamble /= Null_Unbounded_String then Append (Append_To, Payload.Preamble); end if; C := First (Payload.Parts); for P in Parts'Range loop if Parts (P) then Append (Append_To, ASCII.LF & "--" & Boundary & ASCII.LF); Attachment := Element (C); To_String (Attachment.Contents.Headers, Header_Max_Line_Len, Header_Max_Line_Len, Append_To => Append_To); To_String (Attachment.Contents.Payload, Header_Max_Line_Len, Msg => Attachment, Append_To => Append_To); end if; Next (C); end loop; Append (Append_To, ASCII.LF & "--" & Boundary & "--" & ASCII.LF); if Payload.Epilogue /= Null_Unbounded_String then Append (Append_To, ASCII.LF & Payload.Epilogue); end if; end; end; when False => Append (Append_To, Payload.Text); end case; end To_String; --------------- -- To_String -- --------------- procedure To_String (Headers : Header_List.List; Header_Max_Line_Len : Positive; Subject_Max_Line_Len : Positive; Filter : Header_Filter := null; Append_To : in out Unbounded_String) is H : Header_List.Cursor := First (Headers); Tmp : Unbounded_String; begin while Has_Element (H) loop if Filter = null or else Filter (Element (H)) then if Get_Name (Element (H)) = "subject" then To_String (Element (H), Subject_Max_Line_Len, Result => Tmp); else To_String (Element (H), Header_Max_Line_Len, Result => Tmp); end if; if Tmp /= Null_Unbounded_String then Append (Append_To, Tmp); Append (Append_To, ASCII.LF); end if; end if; Next (H); end loop; Append (Append_To, ASCII.LF); end To_String; ---------- -- Size -- ---------- function Size (Msg : Message; Include_Attachments : Boolean) return Long_Integer is Total : Long_Integer := 0; C : Message_List.Cursor; begin if Is_Multipart (Msg) then Total := Total + Long_Integer (Length (Msg.Contents.Payload.Preamble)) + Long_Integer (Length (Msg.Contents.Payload.Epilogue)); C := First (Msg.Contents.Payload.Parts); while Has_Element (C) loop if Include_Attachments then Total := Total + Size (Element (C), True); elsif Get_Content_Type (Element (C)) = Text_Plain then Total := Total + Size (Element (C), True); exit; end if; Next (C); end loop; else Total := Total + Long_Integer (Length (Msg.Contents.Payload.Text)); end if; return Total; end Size; --------------- -- To_String -- --------------- procedure To_String (Msg : Message'Class; Envelope : Boolean := False; Header_Max_Line_Len : Positive := Default_Max_Header_Line_Length; Subject_Max_Line_Len : Positive := Default_Max_Header_Line_Length; Content_Filter : Payload_Filter := null; Filter : Header_Filter := null; Decode : Boolean := False; Quote_From : Boolean := False; Result : out Unbounded_String) is Encoded_Payload : Unbounded_String; Payload : Unbounded_String; Encoding : Encoding_Type; Encoding_Str : Unbounded_String; function Retain_Header (H : Header'Class) return Boolean; -- Filter for header list: if Decode is True, strip the MIME -- Content-Transfer-Encoding; else just apply Filter. ------------------- -- Retain_Header -- ------------------- function Retain_Header (H : Header'Class) return Boolean is begin if Decode and then Get_Name (H) = To_Lower (Content_Transfer_Encoding) then return False; elsif Filter /= null then return Filter (H); else return True; end if; end Retain_Header; -- Start of processing for To_String begin Result := Null_Unbounded_String; if Envelope then Append (Result, Msg.Contents.Envelope_From); Append (Result, ASCII.LF); end if; -- First convert the payload. This way we know how many payloads are -- output, and whether a boundary is necessary or not. To_String (Msg.Contents.Payload, Header_Max_Line_Len, Msg => Msg, Content_Filter => Content_Filter, Append_To => Encoded_Payload); if Decode then Encoding := Get_Encoding_Type (Msg); case Encoding is when Encoding_Base64 => Base64_Decode (To_String (Encoded_Payload), Payload); Encoding := Encoding_8bit; when Encoding_QP => Quoted_Printable_Decode (To_String (Encoded_Payload), Payload); Encoding := Encoding_8bit; when others => Payload := Encoded_Payload; end case; else Payload := Encoded_Payload; end if; To_String (Msg.Contents.Headers, Header_Max_Line_Len, Subject_Max_Line_Len, Retain_Header'Unrestricted_Access, Append_To => Result); if Decode and then Encoding /= Encoding_7bit then To_String (Create (Content_Transfer_Encoding, Encoding_Names (Encoding).all), Result => Encoding_Str); -- Splice new CTE header before empty line at end of headers declare L : constant Natural := Length (Result); begin Replace_Slice (Result, L, L - 1, To_String (Encoding_Str) & ASCII.LF); end; end if; if Quote_From then declare Payload_Str : constant String := To_String (Payload); J : Integer := Payload_Str'First; Copy_From : Natural := Payload_Str'First; begin while J < Payload_Str'Last loop -- Skip until the beginning of a new line while J < Payload_Str'Last and then Payload_Str (J) = ASCII.LF loop J := J + 1; end loop; -- If the new line starts with From_ if J + 4 <= Payload_Str'Length and then Payload_Str (J .. J + 4) = "From " then Append (Result, Payload_Str (Copy_From .. J - 1)); Append (Result, ">"); Copy_From := J; J := J + 5; end if; -- Skip till end of line while J < Payload_Str'Last and then Payload_Str (J) /= ASCII.LF loop J := J + 1; end loop; end loop; Append (Result, Payload_Str (Copy_From .. Payload_Str'Last)); end; else Append (Result, Payload); end if; end To_String; ------------- -- To_Time -- ------------- function To_Time (H : Header'Class) return Ada.Calendar.Time is Tmp : Unbounded_String; begin -- For portability, we could use To_String (H.Value), but that is -- slower. if H.Contents = null then return No_Time; else Flatten (H.Contents.Value, Result => Tmp); return To_Time (To_String (Tmp)); end if; end To_Time; ---------------- -- Add_Header -- ---------------- procedure Add_Header (Msg : in out Message'Class; H : Header'Class) is begin Append (Msg.Contents.Headers, Header (H)); end Add_Header; ---------------- -- Get_Header -- ---------------- function Get_Header (Msg : Message'Class; Name : String) return Header is Iter : Header_List.Cursor; N : constant String := To_Lower (Name); begin if Msg.Contents /= null then Iter := First (Msg.Contents.Headers); while Has_Element (Iter) loop if Element (Iter).Contents.Name = N then return Element (Iter); end if; Next (Iter); end loop; end if; return Null_Header; end Get_Header; -------------------- -- Delete_Headers -- -------------------- procedure Delete_Headers (Msg : Message'Class; Name : String) is Iter : Header_List.Cursor := First (Msg.Contents.Headers); Iter2 : Header_List.Cursor; N : constant String := To_Lower (Name); begin while Has_Element (Iter) loop Iter2 := Next (Iter); if Name = "" or else Element (Iter).Contents.Name = N then Delete (Msg.Contents.Headers, Iter); end if; Iter := Iter2; end loop; end Delete_Headers; ------------------- -- Delete_Header -- ------------------- procedure Delete_Header (Msg : Message'Class; H : Header'Class) is Iter : Header_List.Cursor := First (Msg.Contents.Headers); begin while Has_Element (Iter) loop if Element (Iter).Contents = H.Contents then Delete (Msg.Contents.Headers, Iter); return; end if; Next (Iter); end loop; end Delete_Header; -------------------- -- Replace_Header -- -------------------- procedure Replace_Header (Msg : Message'Class; H : Header'Class) is begin Replace_Header_Internal (Msg, H, Append => True); end Replace_Header; ----------------------------- -- Replace_Header_Internal -- ----------------------------- procedure Replace_Header_Internal (Msg : Message'Class; H : Header'Class; Append : Boolean) is Iter : Header_List.Cursor := First (Msg.Contents.Headers); Iter2 : Header_List.Cursor; Is_First : Boolean := True; begin while Has_Element (Iter) loop Iter2 := Next (Iter); if Element (Iter).Contents.Name = H.Contents.Name then if Is_First then Replace_Element (Msg.Contents.Headers, Iter, Header (H)); Is_First := False; else Delete (Msg.Contents.Headers, Iter); end if; end if; Iter := Iter2; end loop; if Is_First then if Append then Header_List.Append (Msg.Contents.Headers, Header (H)); else Prepend (Msg.Contents.Headers, Header (H)); end if; end if; end Replace_Header_Internal; ----------------- -- Get_Headers -- ----------------- function Get_Headers (Msg : Message'Class; Name : String := "") return Header_Iterator is C : Header_List.Cursor; N : constant Unbounded_String := To_Unbounded_String (To_Lower (Name)); begin if Msg.Contents = null then return (Header_List.No_Element, N); end if; C := First (Msg.Contents.Headers); if Name /= "" then while Has_Element (C) and then Element (C).Contents.Name /= N loop Next (C); end loop; end if; return (C, N); end Get_Headers; ---------- -- Next -- ---------- function Next (Iter : in out Header_Iterator; H : out Header) return Boolean is begin if Has_Element (Iter.Cursor) then H := Element (Iter.Cursor); Next (Iter.Cursor); if Length (Iter.Name) /= 0 then while Has_Element (Iter.Cursor) and then Element (Iter.Cursor).Contents.Name /= Iter.Name loop Next (Iter.Cursor); end loop; end if; return True; end if; return False; end Next; ---------- -- Next -- ---------- procedure Next (Iter : in out Header_Iterator; H : out Header) is begin if not Next (Iter, H) then H := Null_Header; end if; end Next; ---------------------- -- Set_Text_Payload -- ---------------------- procedure Set_Text_Payload (Msg : Message'Class; Payload : Unbounded_String; MIME_Type : String := Text_Plain; Disposition : String := ""; Charset : String := Charset_US_ASCII; Prepend : Boolean := False) is Msg2 : Message; H_CT : Header := Create (Content_Type, MIME_Type); H_CTE : Header := Null_Header; begin if Charset /= "" then Set_Param (H_CT, "charset", Charset); H_CTE := Create (Content_Transfer_Encoding, (if Charset = Charset_US_ASCII then "7bit" else "8bit")); end if; if Msg.Contents.Payload.Multipart then Msg2 := New_Message (MIME_Type => ""); Replace_Header (Msg2, H_CT); if H_CTE /= Null_Header then Replace_Header (Msg2, H_CTE); end if; if Disposition /= "" then Add_Header (Msg2, Create (Content_Disposition, Disposition)); end if; Msg2.Contents.Payload.Text := Payload; if Prepend then Message_List.Prepend (Msg.Contents.Payload.Parts, Msg2); else Message_List.Append (Msg.Contents.Payload.Parts, Msg2); end if; else if MIME_Type /= "" and not Prepend then Replace_Header (Msg, H_CT); if H_CTE = Null_Header then Delete_Headers (Msg, Content_Transfer_Encoding); else Replace_Header (Msg, H_CTE); end if; Delete_Headers (Msg, Content_Disposition); end if; if Prepend then Msg.Contents.Payload.Text := Payload & Msg.Contents.Payload.Text; -- Incorrect if Charset does not match the charset of the existing -- payload??? else Msg.Contents.Payload.Text := Payload; end if; end if; end Set_Text_Payload; procedure Set_Text_Payload (Msg : Message'Class; Payload : String; MIME_Type : String := Text_Plain; Disposition : String := ""; Charset : String := Charset_US_ASCII; Prepend : Boolean := False) is begin Set_Text_Payload (Msg => Msg, Payload => To_Unbounded_String (Payload), MIME_Type => MIME_Type, Disposition => Disposition, Charset => Charset, Prepend => Prepend); end Set_Text_Payload; ----------------------------- -- Get_Single_Part_Payload -- ----------------------------- procedure Get_Single_Part_Payload (Msg : Message'Class; Payload : out Unbounded_String; Decode : Boolean := False) is H : Header; Encoding : Encoding_Type; Encoding_Str : Unbounded_String; begin if Msg.Contents.Payload.Multipart then raise Multipart_Error; elsif Decode then H := Get_Header (Msg, Content_Transfer_Encoding); if H.Contents = null then Encoding := Encoding_7bit; else Flatten (H.Contents.Value, Result => Encoding_Str); declare Encode : constant String := To_Lower (Trim (To_String (Encoding_Str), Ada.Strings.Both)); begin if Encode = "base64" then Encoding := Encoding_Base64; elsif Encode = "quoted-printable" then Encoding := Encoding_QP; else Encoding := Encoding_7bit; end if; end; end if; case Encoding is when Encoding_Base64 => Base64_Decode (To_String (Msg.Contents.Payload.Text), Payload); when Encoding_QP => Quoted_Printable_Decode (To_String (Msg.Contents.Payload.Text), Payload); when others => Payload := Msg.Contents.Payload.Text; end case; else Payload := Msg.Contents.Payload.Text; end if; end Get_Single_Part_Payload; -------------- -- Get_Name -- -------------- function Get_Name (H : Header'Class) return String is begin return To_String (H.Contents.Name); end Get_Name; --------------- -- Get_Value -- --------------- function Get_Value (H : Header'Class) return Charset_String_List.List is begin if H.Contents = null then return Charset_String_List.Empty_List; else return H.Contents.Value; end if; end Get_Value; ------------------ -- Set_Epilogue -- ------------------ procedure Set_Epilogue (Msg : in out Message'Class; Epilogue : String) is begin Convert_To_Multipart (Msg); Msg.Contents.Payload.Epilogue := To_Unbounded_String (Epilogue); end Set_Epilogue; ------------------ -- Set_Preamble -- ------------------ procedure Set_Preamble (Msg : in out Message'Class; Preamble : String) is begin Convert_To_Multipart (Msg); Msg.Contents.Payload.Preamble := To_Unbounded_String (Preamble); end Set_Preamble; ------------------ -- Is_Multipart -- ------------------ function Is_Multipart (Msg : Message'Class) return Boolean is begin return Msg.Contents.Payload.Multipart; end Is_Multipart; ----------------- -- Get_Payload -- ----------------- function Get_Payload (Msg : Message'Class) return Payload_Iterator is begin if Msg.Contents.Payload.Multipart then return (Cursor => First (Msg.Contents.Payload.Parts), Msg => Null_Message); else return (Cursor => Message_List.No_Element, Msg => Message (Msg)); end if; end Get_Payload; ---------- -- Next -- ---------- procedure Next (Iter : in out Payload_Iterator; Item : out Message) is begin if Has_Element (Iter.Cursor) then Item := Element (Iter.Cursor); Next (Iter.Cursor); elsif Iter.Msg /= Null_Message then Item := Iter.Msg; Iter.Msg := Null_Message; else Item := Null_Message; end if; end Next; -------------------- -- Delete_Payload -- -------------------- procedure Delete_Payload (Msg : in out Message'Class; Iter : in out Payload_Iterator) is begin Delete (Msg.Contents.Payload.Parts, Iter.Cursor); end Delete_Payload; ---------------------- -- Get_Content_Type -- ---------------------- function Get_Content_Type (Msg : Message'Class) return String is T : constant String := Get_Type (Get_Header (Msg, Content_Type)); begin if T /= "" then return T; elsif Msg.Contents.Is_Nested then return Message_RFC822; else return Text_Plain; end if; end Get_Content_Type; -------------- -- Get_Type -- -------------- function Get_Type (H : Header) return String is use Ada.Strings; H_Ustr : Unbounded_String; begin if H = Null_Header then return ""; end if; Flatten (H.Contents.Value, Result => H_Ustr); declare H_Str : constant String := Trim (To_String (H_Ustr), Both); SC : Integer; begin SC := H_Str'First; while SC <= H_Str'Last and then not (Is_Whitespace (H_Str (SC)) or else H_Str (SC) = ';') loop SC := SC + 1; end loop; return To_Lower (H_Str (H_Str'First .. SC - 1)); end; end Get_Type; ---------------------------- -- Convert_To_Single_Part -- ---------------------------- procedure Convert_To_Single_Part (Msg : in out Message'Class; Purge : Boolean := False) is Attach : Message; begin if Msg.Contents.Payload.Multipart then if Length (Msg.Contents.Payload.Parts) = 0 or else Purge then Msg.Contents.Payload := (Multipart => False, Text => Null_Unbounded_String); Replace_Header (Msg, Create (Content_Type, Text_Plain)); elsif Length (Msg.Contents.Payload.Parts) = 1 then Attach := Element (First (Msg.Contents.Payload.Parts)); if Is_Multipart (Attach) then Msg.Contents.Payload := (Multipart => True, Parts => Attach.Contents.Payload.Parts, Preamble => Attach.Contents.Payload.Preamble, Epilogue => Attach.Contents.Payload.Epilogue); Replace_Header (Msg, Get_Header (Attach, Content_Type)); else Msg.Contents.Payload := (Multipart => False, Text => Attach.Contents.Payload.Text); Replace_Header (Msg, Get_Header (Attach, Content_Type)); if Get_Header (Attach, Content_Transfer_Encoding) /= Null_Header then Replace_Header (Msg, Get_Header (Attach, Content_Transfer_Encoding)); end if; end if; end if; end if; end Convert_To_Single_Part; -------------------------- -- Convert_To_Multipart -- -------------------------- procedure Convert_To_Multipart (Msg : Message'Class) is MIME_Type : constant String := Get_Content_Type (Msg); Is_Multipart_Type : constant Boolean := Get_Main_Type (MIME_Type) = "multipart"; begin if not Msg.Contents.Payload.Multipart then Convert_To_Multipart (Msg, (if Is_Multipart_Type then MIME_Type else Multipart_Mixed)); end if; end Convert_To_Multipart; procedure Convert_To_Multipart (Msg : Message'Class; MIME_Type : String; Force : Boolean := False) is Parts : Message_List.List; Create_Nested : constant Boolean := Get_Content_Type (Msg) /= MIME_Type or else Force; Part : Message; Preamble : Unbounded_String; procedure Move_Header (Header_Name : String); -- Move named header from Msg to Part ----------------- -- Move_Header -- ----------------- procedure Move_Header (Header_Name : String) is H : constant Header := Get_Header (Msg, Header_Name); begin if H /= Null_Header then Replace_Header (Part, H); Delete_Header (Msg, H); end if; end Move_Header; -- Start of processing for Convert_To_Multipart begin if not Msg.Contents.Payload.Multipart or else Create_Nested then if Get_Main_Type (Get_Content_Type (Msg)) = "multipart" and then not Create_Nested then -- Here we only convert the underlying payload storage -- to multipart, but we don't change the user-visible MIME -- structure: from the user's point of view, this is a no-op. -- Used while parsing a message: the payload is initially -- not Multipart, and then converted here lazily when parts -- are parsed. Assume that the original text payload is actually -- the multipart's preamble. Preamble := Msg.Contents.Payload.Text; else -- Here to convert a MIME message with a non-multipart type to a -- multipart, or to force creation of a nested multipart: make -- the original payload a part in the new multipart payload (but -- don't create an empty part). if Msg.Contents.Payload.Multipart or else Length (Msg.Contents.Payload.Text) > 0 then Part := Clone_Message (Message (Msg)); Part.Contents.Headers := Header_List.Empty_List; Move_Header (Content_Type); Move_Header (Content_Transfer_Encoding); Parts.Append (Part); else Delete_Headers (Msg, Content_Transfer_Encoding); end if; Replace_Header (Msg, Create (Content_Type, MIME_Type)); Replace_Header (Msg, Create (MIME_Version, "1.0")); end if; Msg.Contents.Payload := (Multipart => True, Parts => Parts, Preamble => Preamble, Epilogue => Null_Unbounded_String); end if; end Convert_To_Multipart; ----------------- -- Add_Payload -- ----------------- procedure Add_Payload (Msg : in out Message'Class; Payload : Message; First : Boolean := False) is begin Convert_To_Multipart (Msg); Payload.Contents.Is_Nested := True; if First then Prepend (Msg.Contents.Payload.Parts, Payload); else Append (Msg.Contents.Payload.Parts, Payload); end if; end Add_Payload; ---------------- -- Attach_Msg -- ---------------- procedure Attach_Msg (Msg : in out Message'Class; Attach : Message'Class; Description : String := "") is Attachment : constant Message := New_Message (MIME_Type => Message_RFC822); Tmp : Unbounded_String; begin if Description /= "" then Replace_Header (Attachment, Create (Content_Description, Description)); end if; To_String (Attach, Result => Tmp); Set_Text_Payload (Attachment, Tmp, Charset => "", MIME_Type => Message_RFC822); Replace_Header (Attachment, Create (Content_Disposition, "inline")); Add_Payload (Msg, Attachment); end Attach_Msg; ------------ -- Attach -- ------------ procedure Attach (Msg : in out Message'Class; Path : Virtual_File; MIME_Type : String := Application_Octet_Stream; Recommended_Filename : Virtual_File := No_File; Description : String := ""; Charset : String := Charset_US_ASCII; Disposition : Disposition_Type := Disposition_Attachment; Encoding : Encoding_Type := Encoding_Base64) is Attachment : Message := New_Message (MIME_Type => ""); Str : GNAT.Strings.String_Access; begin declare F : Unbounded_String; begin Convert_To_Multipart (Msg); if Get_Main_Type (MIME_Type) = "text" then Replace_Header (Attachment, Create (Content_Type, MIME_Type & "; charset=""" & Charset & '"')); else Replace_Header (Attachment, Create (Content_Type, MIME_Type)); end if; if Description /= "" then Replace_Header (Attachment, Create (Content_Description, Description)); end if; case Disposition is when Disposition_Attachment => if Recommended_Filename = No_File then Replace_Header (Attachment, Create (Content_Disposition, "attachment; filename=""" & (+Base_Name (Path)) & '"')); else Replace_Header (Attachment, Create (Content_Disposition, "attachment; filename=""" & (+Base_Name (Recommended_Filename)) & '"')); end if; when Disposition_Inline => if Recommended_Filename = No_File then Replace_Header (Attachment, Create (Content_Disposition, "inline; filename=""" & (+Base_Name (Path)) & '"')); else Replace_Header (Attachment, Create (Content_Disposition, "inline; filename=""" & (+Base_Name (Recommended_Filename)) & '"')); end if; end case; Str := Read_File (Path); case Encoding is when Encoding_Base64 => Base64_Encode (Str.all, Charset => Charset, Where => Text, Result => F); Add_Header (Attachment, Create (Content_Transfer_Encoding, "base64")); Set_Unbounded_String (Attachment.Contents.Payload.Text, To_String (F)); when Encoding_QP => Quoted_Printable_Encode (Str.all, Charset => Charset, Where => Text, Result => F); Add_Header (Attachment, Create (Content_Transfer_Encoding, "quoted-printable")); Set_Unbounded_String (Attachment.Contents.Payload.Text, To_String (F)); when Encoding_7bit => Add_Header (Attachment, Create (Content_Transfer_Encoding, "7bit")); Set_Unbounded_String (Attachment.Contents.Payload.Text, Str.all); when Encoding_8bit => Add_Header (Attachment, Create (Content_Transfer_Encoding, "8bit")); Set_Unbounded_String (Attachment.Contents.Payload.Text, Str.all); when Encoding_Binary => Add_Header (Attachment, Create (Content_Transfer_Encoding, "binary")); Set_Unbounded_String (Attachment.Contents.Payload.Text, Str.all); end case; end; Free (Str); Append (Msg.Contents.Payload.Parts, Attachment); end Attach; --------------------- -- Get_Param_Index -- --------------------- procedure Get_Param_Index (H : Header'Class; Param_Name : String; C : out Charset_String_List.Cursor; Semicolon : out Integer; Name_Start : out Integer; Name_End : out Integer; Value_End : out Integer) is begin C := First (H.Contents.Value); Semicolon := 0; -- Initialize variables to avoid GNAT warnings Name_Start := 0; Name_End := 0; Value_End := 0; while Has_Element (C) loop declare Str : constant String := To_String (Element (C).Contents); Index : Natural := Str'First; Stop : Natural; Val_Stop : Natural; begin while Index <= Str'Last loop -- Look for next occurrence of ';', but not within a quoted -- string, for instance a filename in Content-Disposition. Index := Next_Occurrence (Str (Index .. Str'Last), ';', Skip_Quotes => True); if Index <= Str'Last then Semicolon := Index; Index := Index + 1; Skip_Whitespaces (Str, Index); Stop := Next_Occurrence (Str (Index + 1 .. Str'Last), '=', Skip_Quotes => True); if Stop < Str'Last then Val_Stop := Next_Occurrence (Str (Stop + 1 .. Str'Last), ';', Skip_Quotes => True); if To_Lower (Str (Index .. Stop - 1)) = To_Lower (Param_Name) then Name_Start := Index; Name_End := Stop - 1; Value_End := Val_Stop - 1; return; end if; Index := Val_Stop; else Index := Stop; end if; end if; end loop; end; Next (C); end loop; end Get_Param_Index; --------------- -- Set_Param -- --------------- procedure Set_Param (H : in out Header'Class; Param_Name : String; Param_Value : String) is C : Charset_String_List.Cursor := First (H.Contents.Value); Semicolon, Name_Start, Name_End, Val_End : Integer; Str : constant String := "; " & Param_Name & "=""" & Param_Value & '"'; begin Get_Param_Index (H, Param_Name, C, Semicolon, Name_Start, Name_End, Val_End); if Has_Element (C) then Replace_Element (H.Contents.Value, C, (Contents => Unbounded_Slice (Element (C).Contents, 1, Semicolon - 1) & Str & Unbounded_Slice (Element (C).Contents, Val_End + 1, Length (Element (C).Contents)), Charset => Element (C).Charset)); else Append (H.Contents.Value, (Contents => To_Unbounded_String (Str), Charset => To_Unbounded_String (Charset_US_ASCII))); end if; end Set_Param; --------------- -- Get_Param -- --------------- function Get_Param (H : Header'Class; Param_Name : String) return String is C : Charset_String_List.Cursor; Semicolon, Name_Start, Name_End, Val_End : Integer; function Get_Val return String; -- Return the value, omitting surrounding quotes if any function Get_Val return String is Str : constant String := Slice (Element (C).Contents, Name_End + 2, Val_End); begin if Str (Str'First) = '"' then return Str (Str'First + 1 .. Str'Last - 1); else return Str; end if; end Get_Val; begin if H.Contents /= null then C := First (H.Contents.Value); Get_Param_Index (H, Param_Name, C, Semicolon, Name_Start, Name_End, Val_End); if Has_Element (C) then return Get_Val; else -- Support for continuation headers -- http://greenbytes.de/tech/webdav/rfc2231.html#rfc.section.3 -- where a header can be split onto several lines declare Current : Natural := 0; Val : Unbounded_String; begin loop Get_Param_Index (H, Param_Name & "*" & Image (Current, Min_Width => 1), C, Semicolon, Name_Start, Name_End, Val_End); exit when not Has_Element (C); Append (Val, Get_Val); Current := Current + 1; end loop; return To_String (Val); end; end if; end if; return ""; end Get_Param; ------------------ -- Delete_Param -- ------------------ procedure Delete_Param (H : in out Header'Class; Param_Name : String) is C : Charset_String_List.Cursor := First (H.Contents.Value); Semicolon, Name_Start, Name_End, Val_End : Integer; begin Get_Param_Index (H, Param_Name, C, Semicolon, Name_Start, Name_End, Val_End); if Has_Element (C) then Replace_Element (H.Contents.Value, C, (Contents => Unbounded_Slice (Element (C).Contents, 1, Semicolon - 1) & Unbounded_Slice (Element (C).Contents, Val_End + 1, Length (Element (C).Contents)), Charset => Element (C).Charset)); end if; end Delete_Param; ------------------ -- Get_Boundary -- ------------------ function Get_Boundary (Msg : Message'Class) return String is Content_T : constant Header := Get_Header (Msg, Content_Type); begin if Content_T = Null_Header then return ""; end if; return Get_Param (Content_T, "boundary"); end Get_Boundary; ----------------------- -- Get_Encoding_Type -- ----------------------- function Get_Encoding_Type (Msg : Message'Class) return Encoding_Type is H : constant Header := Get_Header (Msg, Content_Transfer_Encoding); HU : Unbounded_String; begin if H /= Null_Header then Flatten (H.Contents.Value, Result => HU); declare use Ada.Strings; HS : constant String := To_Lower (Trim (To_String (HU), Both)); begin for J in Encoding_Names'Range loop if HS = Encoding_Names (J).all then return J; end if; end loop; end; end if; return Encoding_7bit; end Get_Encoding_Type; ---------------------------- -- Has_Line_Starting_With -- ---------------------------- function Has_Line_Starting_With (Text : Unbounded_String; Starts_With : String) return Boolean is StrA : constant String := To_String (Text); Index : Natural; Eol : Natural; begin Index := StrA'First; while Index <= StrA'Last loop Eol := Next_Occurrence (StrA (Index .. StrA'Last), ASCII.LF); if Index + Starts_With'Length - 1 <= StrA'Last and then StrA (Index .. Index + Starts_With'Length - 1) = Starts_With then return True; end if; Index := Eol + 1; end loop; return False; end Has_Line_Starting_With; -------------------- -- Check_Boundary -- -------------------- function Check_Boundary (Msg : Message'Class; Boundary : String) return Boolean is Iter : Payload_Iterator; Msg2 : Message; Bound : constant String := "--" & Boundary; begin if Is_Multipart (Msg) then if Has_Line_Starting_With (Msg.Contents.Payload.Preamble, Bound) or else Has_Line_Starting_With (Msg.Contents.Payload.Epilogue, Bound) then return False; end if; Iter := Get_Payload (Msg); loop Next (Iter, Item => Msg2); exit when Msg2 = Null_Message; case Get_Encoding_Type (Msg2) is when Encoding_QP | Encoding_Base64 => -- No check needs to be done, since the boundary always -- includes the =_ sequence which cannot occur in such -- contexts null; when others => if not Check_Boundary (Msg2, Boundary) then return False; end if; end case; end loop; else if Has_Line_Starting_With (Msg.Contents.Payload.Text, Bound) then return False; end if; end if; return True; end Check_Boundary; ------------------ -- Set_Boundary -- ------------------ procedure Set_Boundary (Msg : Message'Class; Boundary : String := "") is Candidate : Unbounded_String; Valid : Boolean := False; Content_T : Header; begin Convert_To_Multipart (Msg); Content_T := Get_Header (Msg, Content_Type); if Boundary = "" then -- Try to reuse the current boundary, if any Candidate := To_Unbounded_String (Get_Boundary (Msg)); if Candidate = "" then -- Else default on an unlikely one -- Should generate a unique string??? Candidate := To_Unbounded_String ("=_=_=____=_=_"); end if; else -- Try and use the user's proposal Candidate := To_Unbounded_String (Boundary); if Index (Candidate, "=_") = 0 then -- Add this string so that we never have to check quoted-printable -- or base64 content Append (Candidate, "=_"); end if; end if; while not Valid loop Valid := Check_Boundary (Msg, To_String (Candidate)); if not Valid then Append (Candidate, "=_"); end if; end loop; if Content_T = Null_Header then Content_T := Create (Content_Type, Multipart_Mixed); end if; Set_Param (Content_T, "boundary", To_String (Candidate)); Replace_Header (Msg, Content_T); end Set_Boundary; ------------ -- Adjust -- ------------ procedure Adjust (H : in out Header) is begin if H.Contents /= null then H.Contents.Ref_Count := H.Contents.Ref_Count + 1; end if; end Adjust; -------------- -- Finalize -- -------------- procedure Finalize (H : in out Header) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Header_Record, Header_Access); begin if H.Contents /= null then H.Contents.Ref_Count := H.Contents.Ref_Count - 1; if H.Contents.Ref_Count = 0 then Unchecked_Free (H.Contents); end if; end if; end Finalize; -------------------- -- Get_Message_Id -- -------------------- function Get_Message_Id (Msg : Message) return String is use Ada.Strings; H : constant Header := Get_Header (Msg, "Message-ID"); MsgId_Str : constant String := (if H = Null_Header then "" else Trim (To_String (H, Show_Header_Name => False), Both)); Index : Integer; begin -- Note that we remove leading and trailing spaces, so that a Message-Id -- that consists only of spaces will be treated as missing. -- Lotus Notes is known to generate such bogus message IDs. Index := Next_Occurrence (MsgId_Str, '<'); if Index > MsgId_Str'Last then return MsgId_Str; else return MsgId_Str (Index + 1 .. Next_Occurrence (MsgId_Str (Index .. MsgId_Str'Last), '>') - 1); end if; end Get_Message_Id; -------------- -- Get_Date -- -------------- function Get_Date (Msg : Message) return Ada.Calendar.Time is H : constant Header := Get_Header (Msg, "Date"); begin if H /= Null_Header then return To_Time (H); else return Date_From_Envelope (Msg); end if; end Get_Date; procedure Debug_Message (Msg : Message); pragma Export (Ada, Debug_Message); -- Display Msg on standard output (for debugging purposes) ------------------- -- Debug_Message -- ------------------- procedure Debug_Message (Msg : Message) is Res : Unbounded_String; begin To_String (Msg, True, Default_Max_Header_Line_Length, Default_Max_Header_Line_Length, null, null, False, True, Res); Put_Line (To_String (Res)); end Debug_Message; end GNATCOLL.Email; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-email.ads000066400000000000000000000774561425465243200225110ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package and its children provide routines to manipulate mailboxes and -- email messages with Ada.Calendar; with Ada.Containers.Doubly_Linked_Lists; with Ada.Finalization; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with GNATCOLL.VFS; package GNATCOLL.Email is ---------------------- -- Charset sections -- ---------------------- type Charset_String is record Contents : Unbounded_String; Charset : Unbounded_String; end record; Null_Charset_String : constant Charset_String; -- This type represents a string and its charset. Contents must be -- interpreted relatively to Charset, ie characters above 127 must be -- read from that charset. For instance character 161 is an inverted -- exclamation mark in iso-8859-1, but a latin letter A with ogonek in -- iso-8859-2. package Charset_String_List is new Ada.Containers.Doubly_Linked_Lists (Charset_String); -- Single-byte charsets Charset_US_ASCII : constant String := "us-ascii"; Charset_ISO_8859_1 : constant String := "iso-8859-1"; Charset_ISO_8859_2 : constant String := "iso-8859-2"; Charset_ISO_8859_3 : constant String := "iso-8859-3"; Charset_ISO_8859_4 : constant String := "iso-8859-4"; Charset_ISO_8859_9 : constant String := "iso-8859-9"; Charset_ISO_8859_10 : constant String := "iso-8859-10"; Charset_ISO_8859_13 : constant String := "iso-8859-13"; Charset_ISO_8859_14 : constant String := "iso-8859-14"; Charset_ISO_8859_15 : constant String := "iso-8859-15"; Charset_Windows_1252 : constant String := "windows-1252"; -- Multi-byte charsets Charset_UTF_8 : constant String := "utf-8"; Charset_Shift_JIS : constant String := "shift-jis"; Charset_EUC : constant String := "x-euc"; --------------- -- Addresses -- --------------- type Email_Address is record Real_Name : Unbounded_String; Address : Unbounded_String; end record; Null_Address : constant Email_Address; function "=" (Addr1, Addr2 : Email_Address) return Boolean; -- Whether Addr1 and Addr2 have the same address, even if real name differs ------------- -- Headers -- ------------- type Header is tagged private; Null_Header : constant Header; Default_Max_Header_Line_Length : constant := 76; -- Default maximal length that headers should use Content_Description : constant String := "Content-Description"; Content_Disposition : constant String := "Content-Disposition"; Content_Transfer_Encoding : constant String := "Content-Transfer-Encoding"; Content_Type : constant String := "Content-Type"; MIME_Version : constant String := "MIME-Version"; Message_ID : constant String := "Message-ID"; CC : constant String := "CC"; -- The standard MIME headers for mail messages. -- For Content_Disposition, see RFC 2183 at -- http://www.faqs.org/rfcs/rfc2183.html Text_Plain : constant String := "text/plain"; Text_Html : constant String := "text/html"; Application_Octet_Stream : constant String := "application/octet-stream"; Application_Json : constant String := "application/json"; Message_RFC822 : constant String := "message/rfc822"; Multipart_Mixed : constant String := "multipart/mixed"; Multipart_Alternative : constant String := "multipart/alternative"; Multipart_Signed : constant String := "multipart/signed"; Multipart_Digest : constant String := "multipart/digest"; Image_Jpeg : constant String := "image/jpeg"; Image_Gif : constant String := "image/gif"; Text_Xvcard : constant String := "text/x-vcard"; -- Some of the standard MIME types function Create (Name : String; Value : String; Charset : String := Charset_US_ASCII) return Header; function Create (Name : String; Value : Charset_String_List.List) return Header; -- Create a new header, with an unparsed string Value. The interpretation -- of Value depends on the specific header (it could be a date, some -- content type,...). -- Charset indicates the charset used for Value. If Value already contains -- a Mime-encoded string (such as '=?iso-8859-1?q?p=F4stal?='), the -- charset should be left to us-ascii. If Value contains extended -- characters from another charset, the latter must be specified. For -- instance, you could replace the previous mime-encoded string with: -- Value='pôstal' Charset='iso-8859-1' -- The charset influences how the header is encoded when it is displayed in -- a message. -- The Value, if it was split into several lines, must have been normalized -- and the newline characters removed. procedure Append (H : in out Header'Class; Value : String; Charset : String := Charset_US_ASCII); procedure Append (H : in out Header'Class; Value : Charset_String_List.List); -- Appends some content to the header's value procedure Set_Param (H : in out Header'Class; Param_Name : String; Param_Value : String); -- Set the value for one of H's parameters. Such parameters are typically -- used for the Content-Type header, to store the file name, or the -- boundary for instance. They appear as: -- Content-Type: text/plain; charset="iso-8859-1" -- If such a parameter is already set, it is replaced in-place, ie the -- order of parameters is preserved. function Get_Param (H : Header'Class; Param_Name : String) return String; -- Get the value for one of H's parameters, or "" if there is no such -- param. -- This automatically handles continuation headers, ie cases where the -- value of the parameter was split onto several lines, as in: -- filename*0="value1"; -- filename*1="value2" procedure Delete_Param (H : in out Header'Class; Param_Name : String); -- Remove in place one of H's parameters. -- No error is the parameter doesn't exist function Get_Name (H : Header'Class) return String; -- Return the name of the header, lower cased function Get_Value (H : Header'Class) return Charset_String_List.List; -- Return the value of the header procedure To_String (H : Header'Class; Max_Line_Len : Positive := Default_Max_Header_Line_Length; Show_Header_Name : Boolean := True; Result : out Unbounded_String); function To_String (H : Header'Class; Max_Line_Len : Positive := Default_Max_Header_Line_Length; Show_Header_Name : Boolean := True) return String; -- Return the header's value as string. Optionally, the header's name can -- be prepended. -- Lines will be split as needed to match Max_Line_Len. The first line will -- be shorted to take into account the header's name. -- The header is MIME encoded if necessary so that it only contains ASCII -- characters suitable for sending in an email message. function To_Time (H : Header'Class) return Ada.Calendar.Time; -- Interprets the header's value as a time, and returns it. This mostly -- applies to the 'Date:' header. The returned time is UTC. -- The format of the header must match the date format described in -- RFC 2822. When the format is incorrect, No_Time is returned. -------------- -- Messages -- -------------- type Message is tagged private; Null_Message : constant Message; function New_Message (MIME_Type : String := Text_Plain; Charset : String := Charset_US_ASCII) return Message; -- Return a new empty message. The memory will be freed automatically when -- the message is no longer used. -- The MIME type is the initial type, but it can be changed at any time by -- changing the header. The mail will be created as multi-part if -- MIME_Type is one of the standard multipart/* types. Otherwise, a single -- part message is created, but that will change automatically depending on -- the payload you set for the message. If MIME_Type is the empty string, -- no Content-Type header is set. function Clone_Message (Msg : Message) return Message; -- Return a copy of the given message. -- ??? In the case of a multipart message, the contents of each -- part of the message is not duplicated. In other words, modifying -- the contents of any part of the payload will affect both the -- copy and the original. function Reply_To (Msg : Message'Class; From_Email : String; From_Real_Name : String := ""; Quote : Boolean := True; Reply_All : Boolean := True; Reply_Filter : access function (Recipient : Email_Address) return Boolean := null; Local_Date : Ada.Calendar.Time := Ada.Calendar.Clock; Charset : String := Charset_US_ASCII) return Message; -- Create a new message as a reply to Msg. This impacts subjects, -- recipients,... If Quote is True, then Msg is quoted in the payload of -- the new message. -- Headers are set so that the reply will appear in the same thread as Msg -- in mailers that support threads. Charset, is supplied, is used for -- encoding of From_Real_Name. If Reply_All is True, all recipients of -- the original message are added to the Cc: header of the reply. If -- in addition Reply_Filter is not null, then only recipients for which -- Reply_Filter returns True are added. procedure Set_Default_Headers (Msg : in out Message'Class; From_Email : String; Subject : String := "No Subject"; From_Real_Name : String := ""; Local_Date : Ada.Calendar.Time := Ada.Calendar.Clock; Charset : String := Charset_US_ASCII); -- Set the standard headers for the message. This is just a convenient -- subprogram, since the same can be done by manipulating directly the -- headers. Charset is used for MIME encoding of the From: and Subject: -- headers only. procedure Set_From_Header (Msg : in out Message'Class; From_Email : String; From_Real_Name : String; Charset : String); -- Create and set a From: header for Msg using the given email address and -- real name. The real name has the indicated Charset. type Header_Filter is access function (H : Header'Class) return Boolean; -- A filter for headers. It is returned True, the header will be displayed, -- otherwise it is skipped. type Payload_Filter is access function (Attachment : Message'Class) return Boolean; -- Whether a given payload part should be displayed when a message is -- converted to a string. If it returns True, that part is displayed. -- When the filter is unspecified to To_String, all payloads are output. -- This filter only applies in the case of multipart messages, and only to -- the toplevel attachments (ie if an attachment is itself a message with -- other attachments, the filter will not be applied for these). procedure To_String (Msg : Message'Class; Envelope : Boolean := False; Header_Max_Line_Len : Positive := Default_Max_Header_Line_Length; Subject_Max_Line_Len : Positive := Default_Max_Header_Line_Length; Content_Filter : Payload_Filter := null; Filter : Header_Filter := null; Decode : Boolean := False; Quote_From : Boolean := False; Result : out Unbounded_String); -- Return the message as string. This string is suitable for passing to any -- program like sendmail to forward the mail to its recipients. -- If Envelope is True, the envelope line, if known, is included. -- If Content_Filter is specified, it can be used to filter out which part -- of multipart message should be displayed. -- If Filter is specified, it can be used to filter out which headers -- should be displayed. -- If Decode is True and this message is MIME-encoded, it is automatically -- decoded. -- If Quote_From is true, then each line of Msg's payload preceded by a -- blank line and starting with "From " will be prepended with ">" in order -- to avoid further tools to be confused with the From_ message delimiter. -- -- The message might be modified if for instance a boundary needs to be -- created or adjusted for a multipart message. procedure Set_Envelope_From (Msg : in out Message'Class; From : String); procedure Set_Envelope_From (Msg : in out Message'Class; Email : String; Local_Date : Ada.Calendar.Time); function Get_Envelope_From (Msg : Message'Class) return String; -- Set the "From " line used for the envelope of the message function Date_From_Envelope (Msg : Message'Class) return Ada.Calendar.Time; -- Return the date read in the envelope of the message. It is recommanded -- that you get the date from the 'Date:' header when available instead. function Sender_From_Envelope (Msg : Message'Class) return String; -- Return the sender part of the envelope. It is recommended that you use -- the From: header instead when available procedure Add_Header (Msg : in out Message'Class; H : Header'Class); -- Set the unparsed block of headers for the message. -- If there is already a header with the same name, it isn't overridden. -- Instead, two headers with the same name will exist for the message. procedure Delete_Headers (Msg : Message'Class; Name : String); procedure Delete_Header (Msg : Message'Class; H : Header'Class); -- Delete either all headers with the given name (all if Name is the empty -- string), or a specific header. procedure Replace_Header (Msg : Message'Class; H : Header'Class); -- Replace the first header with the same name by H, and delete all other -- headers with the same name. This is different from doing a -- Delete_Headers (Msg, Name); -- Add_Header (Create (Name, ...)); -- since Replace_Header will preserve the order of headers. -- If no header with the same name is found, H is simply added to the list. function Get_Header (Msg : Message'Class; Name : String) return Header; -- Return the first header of Msg with the given name. If this header -- occurs multiple times, only the first occurrence is returned. -- Name is case-insensitive function Get_Type (H : Header) return String; -- For a header H that is a Content-Type or Content-Disposition, return -- the content type or the disposition type (i.e. the initial part of the -- header, before the semicolon). The returned value is always converted -- to lower case. For a null header, an empty string is returned. function Get_Content_Type (Msg : Message'Class) return String; -- Return the MIME content type for the message. -- As per RFC 2045, there is always such a content type, even if it wasn't -- specified explicitly by the headers. It defaults to text/plain when the -- message is not part of the payload of a multipart/report message, to -- message/rfc822 otherwise. The returned value is always converted to -- lower case. function Get_Message_Id (Msg : Message) return String; -- Return the Message_Id for this message. This returns the empty string if -- no such Id is defined. Otherwise, this extracts the Id from that header, -- properly keeping only the Id itself, and not the surrounding <..> if -- they exist. function Get_Date (Msg : Message) return Ada.Calendar.Time; -- Return the date the message was sent. This information is taken from the -- Date: header if it exists, and if not from the envelope of the message. function Size (Msg : Message; Include_Attachments : Boolean) return Long_Integer; -- Return the size of the message and all its MIME parts. This size is not -- extremely precise (and doesn't reflect the size it would take to convert -- it to a string for instance), and for instance doesn't include the size -- of the headers. -- If Include_Attachments is False, then all but the first text/plain part -- will be ignored type Encoding_Type is (Encoding_7bit, Encoding_8bit, Encoding_Binary, Encoding_QP, Encoding_Base64); function Get_Encoding_Type (Msg : Message'Class) return Encoding_Type; -- Return the encoding used for this message. -- As per RFC 2045, there is always such an encoding, and if no header is -- specified then Encoding_7bit is assumed. type Header_Iterator is private; function Get_Headers (Msg : Message'Class; Name : String := "") return Header_Iterator; -- Iterate over all headers with the given name. If Name is unspecified, -- iterates over all headers of the message. For Null_Message, return an -- empty iterator. Looping over all headers is done as follows: -- Iter := Get_Headers (Msg); -- loop -- Next (Iter, H); -- exit when H = Null_Header; -- Header_Processing (H); -- end loop; procedure Next (Iter : in out Header_Iterator; H : out Header); -- Returns current header if exists or Null_Header otherwise. -- Move to the next header with the expected name. function Next (Iter : in out Header_Iterator; H : out Header) return Boolean; -- Returns True if the header exists and returns it in H parameter. -- Move cursor position to the next header. The loop over headers could be -- like this: -- -- Iter := Get_Headers (Msg); -- while Next (Iter, H) loop -- Do_Something_With (H); -- end loop; ------------- -- Payload -- ------------- -- A message can either be a single part message, ie it just contains text, -- possibly in various charsets or a multi part message, in which case it -- can have attached files, contain nested messages, etc. -- The content of the message, whether single or multi part, is called the -- payload. -- Since each part of a multi-part message can itself have its own headers -- and be a nested message, the actual payload of a message is represented -- as a list of messages. function Is_Multipart (Msg : Message'Class) return Boolean; -- Whether the message contains several parts, and must be encoded as a -- multipart email message. If False, the payload is a simple string. Multipart_Error : exception; -------------------------- -- Single part messages -- -------------------------- procedure Set_Text_Payload (Msg : Message'Class; Payload : Unbounded_String; MIME_Type : String := Text_Plain; Disposition : String := ""; Charset : String := Charset_US_ASCII; Prepend : Boolean := False); -- Set the payload of the message, as text. No parsing is done. -- If the message is a single part message, this is the text of the -- message. If the message is a multi-part message, this is set as one of -- the parts, with the given MIME type. As a result, it can be called -- several times in such a case, each time will create a new part. -- If MIME_Type is set to the empty string, it is not updated in the -- message. This is mostly useful when Msg was parsed through one of the -- functions in Email.Parser. -- If Disposition is specified, it is used as the value of the -- Content-Disposition header of the text part. -- When Msg is a multi-part message, the new part is either appended after -- the existing parts, or prepend before, depending on the Prepend -- parameter. If Msg is a single part message, then Payload will replace -- the current payload if Prepend is False, otherwise the old payload is -- preserved and set after the new one. procedure Set_Text_Payload (Msg : Message'Class; Payload : String; MIME_Type : String := Text_Plain; Disposition : String := ""; Charset : String := Charset_US_ASCII; Prepend : Boolean := False); -- The same like above but Payload is just a String procedure Get_Single_Part_Payload (Msg : Message'Class; Payload : out Unbounded_String; Decode : Boolean := False); -- Return the content of a message when it doesn't contain multiparts. -- If this is a multipart message, Multipart_Error is raised. -- If Decode is true and this message is MIME-encoded, it is automatically -- decoded. You can also decode it later through the subprograms in -- email-utils.ads ------------------------- -- Multi part messages -- ------------------------- type Payload_Iterator is private; function Get_Payload (Msg : Message'Class) return Payload_Iterator; -- Return an iterator over the whole content of the message. -- If the message is not a multipart message, a single element will ever -- be returned, which is Msg itself. This allows for traversing both -- single parts and multiparts messages in a single piece of code. -- The following code will find all textual contents of Msg: -- Iter := Get_Payload (Msg); -- loop -- Next (Iter, Item => Attachment); -- exit when Attachment = Null_Message; -- if Get_Main_Type (Get_Content_Type (Attachment)) = "text" then -- Get_Single_Part_Payload (Attachment, ....); -- end if; -- end loop; procedure Next (Iter : in out Payload_Iterator; Item : out Message); -- Get the next part in the payload of a message. Null_Message is -- returned when there are no more parts in the message. procedure Delete_Payload (Msg : in out Message'Class; Iter : in out Payload_Iterator); -- Remove the corresponding payload from the message procedure Convert_To_Multipart (Msg : Message'Class); -- If Msg is a single part message, convert it to a multipart/mixed whose -- first part is the original payload, else do not change the MIME -- structure of Msg (but make sure that the underlying data structure is -- suitable for storage of a multipart message). procedure Convert_To_Multipart (Msg : Message'Class; MIME_Type : String; Force : Boolean := False); -- If Msg is a single part message, convert it to a multipart with the -- indicated MIME_Type, whose first part is the original payload. Also -- do so if Msg is a multipart message if it has a different MIME subtype, -- or if Force is True. Else do not change the MIME structure of Msg -- (but make sure that the underlying data structure is suitable -- for storage of a multipart message). procedure Convert_To_Single_Part (Msg : in out Message'Class; Purge : Boolean := False); -- Try to convert Msg to a single part message. This is only doable if -- there is a single textual part, or the message is already single part. -- If Msg contains a single part which is in turn a multipart Msg, it gets -- processed as well. -- All other cases will do nothing, unless Purge is set True, in which -- case all contents are lost, and the (single part) payload is reset -- to an empty text/plain part. procedure Set_Preamble (Msg : in out Message'Class; Preamble : String); -- Set the preamble of the MIME message. -- This text will be inserted before the first boundary, ie the first -- attached file. -- Normally, in MIME aware mailers, this preamble will not be visible. It -- will only be visible by viewing the full text of the message. -- If the message was single-part message, it is automatically converted to -- a multi-part message. procedure Set_Epilogue (Msg : in out Message'Class; Epilogue : String); -- This is similar to the preamble, but appears after the end of the -- last document. -- If the message was single-part message, it is automatically converted to -- a multi-part message procedure Add_Payload (Msg : in out Message'Class; Payload : Message; First : Boolean := False); -- Add a new part to a multipart message. Msg is first converted to -- multipart if necessary. Payload itself is stored in Msg, ie modifying -- Payload later on will impact Msg. This procedure cannot be used when -- attaching a real mail message, see Attach_Msg instead. -- If First is True, then add the new part at the begining. Otherwise, -- add it at the end. procedure Attach_Msg (Msg : in out Message'Class; Attach : Message'Class; Description : String := ""); -- Attach an existing mail message to another one (for instance when -- forwarding as attachment). type Disposition_Type is (Disposition_Attachment, Disposition_Inline); procedure Attach (Msg : in out Message'Class; Path : GNATCOLL.VFS.Virtual_File; MIME_Type : String := Application_Octet_Stream; Recommended_Filename : GNATCOLL.VFS.Virtual_File := GNATCOLL.VFS.No_File; Description : String := ""; Charset : String := Charset_US_ASCII; Disposition : Disposition_Type := Disposition_Attachment; Encoding : Encoding_Type := Encoding_Base64); -- Attach a file to the payload. The file is immediately read from the -- disk, and encoded as necessary, so this might be an expensive operation -- to perform. -- Name_Error is raised if the file is not found. function Get_Boundary (Msg : Message'Class) return String; -- Return the boundary used for Msg to separate its various parts. -- The empty string is returned if this isn't a multipart message. procedure Set_Boundary (Msg : Message'Class; Boundary : String := ""); -- Set the boundary to use between parts of the message. If the empty -- string is passed, a boundary will be added if none already exists, or -- if the current one can not be used because some part of the message -- already includes it. -- The message is automatically converted to a multipart message if you -- call this message, since boundaries can not be used with single part -- messages. -- As per RFC 1521, the boundary can only use the following characters: -- 0-9 a-z A-Z '()+_,-./:=? -- In this implementation, it must include the sequence =_. This is a -- sequence that is guaranteed to never appear in quoted-printable or -- base64 encoded parts, and this implementation takes advantage of this -- to speed up the check that the boundary can be used. -- The string =_ will be appended as many times as necessary to Boundary to -- make it valid. -- In general, you do not need to call this procedure, which is called -- automatically when needed. private type Header_Record is record Name : Unbounded_String; Value : Charset_String_List.List; Ref_Count : Natural := 1; end record; type Header_Access is access Header_Record; type Header is new Ada.Finalization.Controlled with record Contents : Header_Access; end record; procedure Adjust (H : in out Header); procedure Finalize (H : in out Header); -- Headers are stored in a list, since order might be relevant sometimes, -- especially for the 'Received:' headers. package Header_List is new Ada.Containers.Doubly_Linked_Lists (Header); type Header_Iterator is record Cursor : Header_List.Cursor; Name : Unbounded_String; end record; type Message_Record; type Message_Access is access Message_Record; type Message is new Ada.Finalization.Controlled with record Contents : Message_Access; end record; -- Smart pointer to message. This provides automatic freeing of the memory, -- but allows us to have a list of messages without having access to the -- full view of a Message, which itself contains an instance of the list. procedure Adjust (Msg : in out Message); procedure Finalize (Msg : in out Message); package Message_List is new Ada.Containers.Doubly_Linked_Lists (Message); type Payload_Iterator is record Cursor : Message_List.Cursor; Msg : Message; end record; type Message_Payload (Multipart : Boolean := False) is record case Multipart is when True => Parts : Message_List.List; Preamble : Unbounded_String; Epilogue : Unbounded_String; when False => Text : Unbounded_String; end case; end record; Null_Payload : constant Message_Payload := (False, Null_Unbounded_String); Null_Multipart_Payload : constant Message_Payload := (True, Message_List.Empty_List, Null_Unbounded_String, Null_Unbounded_String); type Message_Record is record Ref_Count : Natural := 1; Envelope_From : Unbounded_String; Headers : Header_List.List; Payload : Message_Payload; Is_Nested : Boolean := False; end record; Null_Message : constant Message := (Ada.Finalization.Controlled with Contents => null); function Next_Occurrence (S : String; Char : Character; Skip_Quotes : Boolean := False) return Integer; -- Return the index of the next occurrence of Char, or a number greater -- than S'Last if we are on the last line. -- If Skip_Quotes is true, characters between a "..." will be ignored. function Is_Whitespace (Char : Character) return Boolean; pragma Inline (Is_Whitespace); -- Whether Char is a whitespace (tab or space) procedure Skip_Whitespaces (S : String; Index : in out Integer); pragma Inline (Skip_Whitespaces); -- Skip any whitespace character, including newlines, starting at Index. -- Leaves Index on the first non-whitespace character Null_Header : constant Header := (Ada.Finalization.Controlled with null); Null_Charset_String : constant Charset_String := (Null_Unbounded_String, Null_Unbounded_String); Null_Address : constant Email_Address := (Null_Unbounded_String, Null_Unbounded_String); end GNATCOLL.Email; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-format_columns_vertical.ads000066400000000000000000000040771425465243200263300ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Procedure to format ordered words by columns vertically. -- Number of columns limited by width and have to be calculated to minimize -- number of rows in each column. with GNATCOLL.Strings; with GNATCOLL.Formatters; procedure GNATCOLL.Format_Columns_Vertical is new Formatters.Columns_Vertical (Strings); -- See comment for GNATCOLL.Formatters.Columns_Vertical alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-formatters.adb000066400000000000000000000126601425465243200235510ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Formatters is ---------------------- -- Columns_Vertical -- ---------------------- procedure Columns_Vertical (Words : Strings.XString_Array; Width : Positive; Put_Line : not null access procedure (Line : Strings.XString); Pad : Strings.Char_Type := Strings.Space; Delimiter : Strings.Char_String := (1 => Strings.Space)) is use Strings; Rows : Natural; Cols : Natural; Max : Natural := 0; Idx : Natural; Len : Natural; begin -- Prepare initial rough proposal for number of rows for W of Words loop if W.Length > Max then Max := W.Length; end if; end loop; Cols := Width / (Max + Delimiter'Length); Rows := Words'Length / Cols; if Words'Length rem Cols /= 0 then Rows := Rows + 1; end if; -- Trying to reduce number of rows using max length in each column Reduce_Rows : while Rows > 1 loop Rows := Rows - 1; Cols := Words'Length / Rows; if Words'Length rem Rows > 0 then Cols := Cols + 1; end if; Idx := Words'First; Len := 0; for Col in 1 .. Cols loop Max := 0; for Row in 1 .. Rows loop if Max < Words (Idx).Length then Max := Words (Idx).Length; end if; Idx := Idx + 1; exit when Idx > Words'Last; end loop; Len := Len + Max + Delimiter'Length; if Len > Width then Rows := Rows + 1; exit Reduce_Rows; end if; exit when Idx > Words'Last; end loop; end loop Reduce_Rows; Cols := Words'Length / Rows; if Words'Length rem Rows > 0 then Cols := Cols + 1; end if; declare Cmax : array (1 .. Cols) of Positive := (others => 1); Line : XString; Align : Natural; begin for J in Words'Range loop Idx := (J - Words'First) / Rows + 1; if Cmax (Idx) < Words (J).Length then Cmax (Idx) := Words (J).Length; end if; end loop; for Row in 1 .. Rows loop Line.Clear; Align := 0; for Col in 1 .. Cols loop Idx := (Col - 1) * Rows + Row - 1 + Words'First; exit when Idx > Words'Last; if not Line.Is_Empty then Line.Append (Align * Pad); Line.Append (Delimiter); end if; Line.Append (Words (Idx)); Align := Cmax (Col) - Words (Idx).Length; end loop; Put_Line (Line); end loop; end; end Columns_Vertical; ------------------------------- -- Columns_Vertical_XStrings -- ------------------------------- function Columns_Vertical_XString (Words : Strings.XString_Array; Width : Positive; Pad : Strings.Char_Type := Strings.Space; Delimiter : Strings.Char_String := (1 => Strings.Space)) return Strings.XString is Result : Strings.XString; procedure Append_Line (Line : Strings.XString); -- Append line to result --------------- -- Each_Line -- --------------- procedure Append_Line (Line : Strings.XString) is begin Result.Append (Line); Result.Append (End_Of_Line); end Append_Line; procedure Format_Columns is new Columns_Vertical (Strings); begin Format_Columns (Words, Width, Append_Line'Access, Pad, Delimiter); return Result; end Columns_Vertical_XString; end GNATCOLL.Formatters; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-formatters.ads000066400000000000000000000077121425465243200235740ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides routines to format the text representation of complex -- data structures. with GNATCOLL.Strings_Impl; package GNATCOLL.Formatters is generic with package Strings is new GNATCOLL.Strings_Impl.Strings (<>); procedure Columns_Vertical (Words : Strings.XString_Array; Width : Positive; Put_Line : not null access procedure (Line : Strings.XString); Pad : Strings.Char_Type := Strings.Space; Delimiter : Strings.Char_String := (1 => Strings.Space)); -- Procedure to format ordered phrases by columns vertically and output it -- to callback line by line. -- Number of columns limited by width and have to be calculated to minimize -- number of rows in each column. Output example: -- -- A_2.0161E-01 L_8.34E-02 W_3.4E-02 -- B_4.112135470E-01 M_9.83147859573364258000E-01 X_1.232E-01 -- C_1.8368E-01 N_4.7302106023E-01 Y_7.27181677268E-01 -- D_2.25542E-01 O_8.702573776245117190E-01 Z_1.415E-01 -- E_5.836335420609E-01 P_9.2786121368408203100E-01 -- F_7.226370573043823E-01 Q_9.2725968360900878900E-01 -- G_5.0E-03 R_7.7519929409027100E-01 -- H_6.59124374389648E-01 S_2.48095E-01 -- I_3.4402838E-01 T_9.0058088302612304700E-01 -- J_1.7E-02 U_6.0053098201752E-01 -- K_7.217630147933960E-01 V_8.02301645278930664E-01 -- -- Words is the array of strings to be formatted in the output. -- Width is the width limit of the output. -- Put_Line is the callback routine to take output line by line. -- Pad is the character filling the space after words to have same size in -- column for next column to be alligned. -- Delimiter is string delimiting the columns. generic with package Strings is new GNATCOLL.Strings_Impl.Strings (<>); End_Of_Line : Strings.Char_Type; function Columns_Vertical_XString (Words : Strings.XString_Array; Width : Positive; Pad : Strings.Char_Type := Strings.Space; Delimiter : Strings.Char_String := (1 => Strings.Space)) return Strings.XString; -- The same as above but returns formatted text at once end GNATCOLL.Formatters; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-geometry.adb000066400000000000000000000462031425465243200232160ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Algorithms in this package are adapted from the following books and -- articles: -- -- [GGII] Graphic Gems II -- http://www1.acm.org/pubs/tog/GraphicsGems/gemsii -- [GGIV] Graphic Gems IV -- http://www1.acm.org/pubs/tog/GraphicsGems/gemsiv -- [CGA] comp.lang.graphics -- [TRI] http://www.acm.org/jgt/papers/GuigueDevillers03/ -- triangle_triangle_intersection.html -- [PTTRI] http://www.blackpawn.com/texts/pointinpoly/default.html -- [SEGSEG] http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/ -- [GEO] http://geometryalgorithms.com/Archive/algorithm_0.04 -- -- See also the FAQ of comp.graphics.algorithms package body GNATCOLL.Geometry is use Coordinate_Elementary_Functions; function Orient (P, Q, R : Point) return Coordinate; -- From [TRI] pragma Inline (Orient); function Tri_Intersection (P1, Q1, R1, P2, Q2, R2 : Point) return Boolean; -- From [TRI] function Intersection_Test_Edge (P1, Q1, R1, P2, Q2, R2 : Point) return Boolean; -- From [TRI] pragma Inline (Intersection_Test_Edge); function Intersection_Test_Vertex (P1, Q1, R1, P2, Q2, R2 : Point) return Boolean; -- From [TRI] pragma Inline (Intersection_Test_Vertex); -- Return whether the 2.0 triangles intersect. Points need to be sorted ------------- -- To_Line -- ------------- function To_Line (P1, P2 : Point) return Line is A : constant Coordinate := P2.Y - P1.Y; B : constant Coordinate := P1.X - P2.X; begin return (A => A, B => B, C => A * P1.X + B * P1.Y); end To_Line; ------------- -- To_Line -- ------------- function To_Line (Seg : Segment) return Line is begin return To_Line (Seg (1), Seg (2)); end To_Line; -------------- -- Bisector -- -------------- function Bisector (S : Segment) return Line is L : constant Line := To_Line (S); X_Mid : constant Coordinate := (S (1).X + S (2).X) / 2.0; Y_Mid : constant Coordinate := (S (1).Y + S (2).Y) / 2.0; begin return (A => -L.B, B => L.A, C => -L.B * X_Mid + L.A * Y_Mid); end Bisector; ------------------ -- Intersection -- ------------------ function Intersection (L1, L2 : Line) return Point is Det : constant Coordinate := L1.A * L2.B - L2.A * L1.B; begin if Det = 0.0 then if L1.C = L2.C then return Infinity_Points; else return No_Point; end if; else return (X => (L2.B * L1.C - L1.B * L2.C) / Det, Y => (L1.A * L2.C - L2.A * L1.C) / Det); end if; end Intersection; ------------ -- Inside -- ------------ function Inside (P : Point; L : Line) return Boolean is begin return L.A * P.X + L.B * P.Y = L.C; end Inside; ------------ -- Inside -- ------------ function Inside (P : Point; S : Segment) return Boolean is begin return Inside (P, To_Line (S)) and then P.X >= Coordinate'Min (S (1).X, S (2).X) and then P.X <= Coordinate'Max (S (1).X, S (2).X) and then P.Y >= Coordinate'Min (S (1).Y, S (2).Y) and then P.Y <= Coordinate'Max (S (1).Y, S (2).Y); end Inside; ------------------ -- Intersection -- ------------------ -- Algorithm adapted from [GGII - xlines.c] function Intersection (S1, S2 : Segment) return Point is L1 : constant Line := To_Line (S1); R3 : constant Coordinate := L1.A * S2 (1).X + L1.B * S2 (1).Y - L1.C; R4 : constant Coordinate := L1.A * S2 (2).X + L1.B * S2 (2).Y - L1.C; L2 : constant Line := To_Line (S2); R1 : constant Coordinate := L2.A * S1 (1).X + L2.B * S1 (1).Y - L2.C; R2 : constant Coordinate := L2.A * S1 (2).X + L2.B * S1 (2).Y - L2.C; Denom : Coordinate; begin -- Check signs of R3 and R4. If both points 3 and 4 lie on same side -- of line 1, the line segments do not intersect if (R3 > 0.0 and then R4 > 0.0) or else (R3 < 0.0 and then R4 < 0.0) then return No_Point; end if; -- Check signs of r1 and r2. If both points lie on same side of -- second line segment, the line segments do not intersect if (R1 > 0.0 and then R2 > 0.0) or else (R1 < 0.0 and then R2 < 0.0) then return No_Point; end if; -- Line segments intersect, compute intersection point Denom := L1.A * L2.B - L2.A * L1.B; if Denom = 0.0 then -- colinears if Inside (S1 (1), S2) or else Inside (S1 (2), S2) then return Infinity_Points; else return No_Point; end if; end if; return (X => (L2.B * L1.C - L1.B * L2.C) / Denom, Y => (L1.A * L2.C - L2.A * L1.C) / Denom); end Intersection; --------------- -- To_Vector -- --------------- function To_Vector (S : Segment) return Vector is begin return (X => S (2).X - S (1).X, Y => S (2).Y - S (1).Y); end To_Vector; --------- -- "-" -- --------- function "-" (P2, P1 : Point) return Vector is begin return (X => P2.X - P1.X, Y => P2.Y - P1.Y); end "-"; --------- -- Dot -- --------- function Dot (Vector1, Vector2 : Vector) return Coordinate is begin return Vector1.X * Vector2.X + Vector1.Y * Vector2.Y; end Dot; ----------- -- Cross -- ----------- function Cross (Vector1, Vector2 : Vector) return Coordinate is begin return Vector1.X * Vector2.Y - Vector1.Y * Vector2.X; end Cross; ------------ -- Length -- ------------ function Length (Vect : Vector) return Distance_Type is begin return Sqrt (Coordinate (Vect.X * Vect.X + Vect.Y * Vect.Y)); end Length; -------------- -- Distance -- -------------- function Distance (From : Point; To : Line) return Distance_Type is S : constant Coordinate'Base := To.A * To.A + To.B * To.B; begin return abs (To.A * From.X + To.B * From.Y - To.C) / Sqrt (S); end Distance; -------------- -- Distance -- -------------- function Distance (From : Point; To : Point) return Distance_Type is X : constant Coordinate'Base := To.X - From.X; Y : constant Coordinate'Base := To.Y - From.Y; begin return Sqrt (X * X + Y * Y); end Distance; -------------- -- Distance -- -------------- function Distance (From : Point; To : Segment) return Distance_Type is begin if To (1) = To (2) then raise Program_Error with "Empty Segment"; end if; if Dot (From - To (2), To (2) - To (1)) > 0.0 then -- Closest point is Segment (2) return Distance (From, To (2)); elsif Dot (From - To (1), To (1) - To (2)) > 0.0 then -- Closest point is Segment (1) return Distance (From, To (1)); else return Distance (From, To_Line (To)); end if; end Distance; -------------- -- Distance -- -------------- function Distance (From : Point; To : Polygon) return Distance_Type is Min : Distance_Type := Distance_Type'Last; begin for P in To'First .. To'Last - 1 loop Min := Distance_Type'Min (Min, Distance (From, Segment'(To (P), To (P + 1)))); end loop; return Distance_Type'Min (Min, Distance (From, Segment'(To (To'First), To (To'Last)))); end Distance; --------------- -- Intersect -- --------------- function Intersect (C1, C2 : Circle) return Boolean is begin return Distance (C1.Center, C2.Center) <= C1.Radius + C2.Radius; end Intersect; --------------- -- Intersect -- --------------- function Intersect (L : Line; C : Circle) return Boolean is begin return Distance (C.Center, L) <= C.Radius; end Intersect; ---------- -- Area -- ---------- function Area (Self : Polygon) return Distance_Type is D : Coordinate'Base := 0.0; begin for P in Self'First + 1 .. Self'Last - 1 loop D := D + Cross (Self (P) - Self (Self'First), Self (P + 1) - Self (Self'First)); end loop; return abs (D / 2.0); end Area; ---------- -- Area -- ---------- function Area (Self : Triangle) return Distance_Type is begin return abs ((Self (2).X - Self (1).X) * (Self (3).Y - Self (1).Y) - (Self (3).X - Self (1).X) * (Self (2).Y - Self (1).Y)) / 2.0; end Area; --------------- -- To_Circle -- --------------- function To_Circle (P1, P2, P3 : Point) return Circle is -- Find the intersection of the 2.0 perpendicular bisectors of two of -- the segments. Bis1 : constant Line := Bisector (Segment'(1 => P1, 2 => P2)); Bis2 : constant Line := Bisector (Segment'(1 => P2, 2 => P3)); Center : constant Point := Intersection (Bis1, Bis2); begin if Center = No_Point or else Center = Infinity_Points then return No_Circle; else return (Center => Center, Radius => Distance (Center, P1)); end if; end To_Circle; ------------ -- Inside -- ------------ function Inside (P : Point; Poly : Polygon) return Boolean is J : Natural := Poly'Last; C : Boolean := False; Deltay : Coordinate; begin -- See http://www.ecse.rpi.edu/Homepages/wrf/Research -- /Short_Notes/pnpoly.html for S in Poly'Range loop Deltay := P.Y - Poly (S).Y; -- The divide below is mandatory: if you transform it into a -- multiplication on the other side, the sign of the denominator will -- flip the inequality, and thus make the code harder. if ((0.0 <= Deltay and then P.Y < Poly (J).Y) or else (Poly (J).Y <= P.Y and then Deltay < 0.0)) and then (P.X - Poly (S).X < (Poly (J).X - Poly (S).X) * Deltay / (Poly (J).Y - Poly (S).Y)) then C := not C; end if; J := S; end loop; return C; end Inside; -------------- -- Centroid -- -------------- function Centroid (Self : Polygon) return Point is X, Y : Coordinate'Base := 0.0; Weight : Coordinate'Base := 0.0; Local : Coordinate'Base; begin for P in Self'First + 1 .. Self'Last - 1 loop Local := Area (Triangle'(Self (Self'First), Self (P), Self (P + 1))); Weight := Weight + Local; X := X + (Self (Self'First).X + Self (P).X + Self (P + 1).X) / 3.0 * Local; Y := Y + (Self (Self'First).Y + Self (P).Y + Self (P + 1).Y) / 3.0 * Local; end loop; return (X => X / Weight, Y => Y / Weight); end Centroid; --------------- -- Same_Side -- --------------- function Same_Side (P1, P2 : Point; As : Segment) return Boolean is -- Direction of cross-product for (L2 - L1) x (P1 - L1) Cross1_Z : constant Coordinate'Base := (As (2).X - As (1).X) * (P1.Y - As (1).Y) - (As (2).Y - As (1).Y) * (P1.X - As (1).X); -- Direction of cross-product for (L2 - L1) x (P2 - L1) Cross2_Z : constant Coordinate'Base := (As (2).X - As (1).X) * (P2.Y - As (1).Y) - (As (2).Y - As (1).Y) * (P2.X - As (1).X); begin if Cross1_Z <= 0.0 then return Cross2_Z <= 0.0; else return Cross2_Z > 0.0; end if; end Same_Side; --------------- -- Same_Side -- --------------- function Same_Side (P1, P2 : Point; As : Line) return Boolean is S : Segment; begin if As.B = 0.0 then -- Horizontal line S (1).X := As.C / As.A; S (1).Y := Coordinate'First; S (2).X := S (1).X; S (2).Y := Coordinate'Last; else S (1).X := Coordinate'First; S (1).Y := As.C / As.B; S (2).X := Coordinate'Last; S (2).Y := (As.C - As.A * S (2).X) / As.B; end if; return Same_Side (P1, P2, S); end Same_Side; ------------ -- Inside -- ------------ -- Algorithm from [PTTRI] function Inside (P : Point; T : Triangle) return Boolean is begin -- On boundary ? if Distance (P, T (1)) = 0.0 or else Distance (P, T (2)) = 0.0 or else Distance (P, T (3)) = 0.0 then return True; end if; return Same_Side (P, T (3), Segment'(T (1), T (2))) and then Same_Side (P, T (1), Segment'(T (2), T (3))) and then Same_Side (P, T (2), Segment'(T (1), T (3))); end Inside; --------------- -- Orient -- --------------- function Orient (P, Q, R : Point) return Coordinate is begin return (P.X - R.X) * (Q.Y - R.Y) - (P.Y - R.Y) * (Q.X - R.X); end Orient; ------------------------------ -- Intersection_Test_Vertex -- ------------------------------ function Intersection_Test_Vertex (P1, Q1, R1, P2, Q2, R2 : Point) return Boolean is begin if Orient (R2, P2, Q1) >= 0.0 then if Orient (R2, Q2, Q1) <= 0.0 then if Orient (P1, P2, Q1) > 0.0 then return Orient (P1, Q2, Q1) <= 0.0; else if Orient (P1, P2, R1) >= 0.0 then return Orient (Q1, R1, P2) >= 0.0; else return False; end if; end if; else if Orient (P1, Q2, Q1) <= 0.0 then if Orient (R2, Q2, R1) <= 0.0 then return Orient (Q1, R1, Q2) >= 0.0; else return False; end if; else return False; end if; end if; else if Orient (R2, P2, R1) >= 0.0 then if Orient (Q1, R1, R2) >= 0.0 then return Orient (P1, P2, R1) >= 0.0; else if Orient (Q1, R1, Q2) >= 0.0 then return Orient (R2, R1, Q2) >= 0.0; else return False; end if; end if; else return False; end if; end if; end Intersection_Test_Vertex; ---------------------------- -- Intersection_Test_Edge -- ---------------------------- function Intersection_Test_Edge (P1, Q1, R1, P2, Q2, R2 : Point) return Boolean is pragma Unreferenced (Q2); begin if Orient (R2, P2, Q1) >= 0.0 then if Orient (P1, P2, Q1) >= 0.0 then return Orient (P1, Q1, R2) >= 0.0; else return Orient (Q1, R1, P2) >= 0.0 and then Orient (R1, P1, P2) >= 0.0; end if; else if Orient (R2, P2, R1) >= 0.0 then if Orient (P1, P2, R1) >= 0.0 then return Orient (P1, R1, R2) >= 0.0 or else Orient (Q1, R1, R2) >= 0.0; else return False; end if; else return False; end if; end if; end Intersection_Test_Edge; ------------------------- -- Tri_Intersection -- ------------------------- function Tri_Intersection (P1, Q1, R1, P2, Q2, R2 : Point) return Boolean is begin pragma Warnings (Off, "*actuals for this call may be in wrong order"); if Orient (P2, Q2, P1) >= 0.0 then if Orient (Q2, R2, P1) >= 0.0 then if Orient (R2, P2, P1) >= 0.0 then return True; else return Intersection_Test_Edge (P1, Q1, R1, P2, Q2, R2); end if; else if Orient (R2, P2, P1) >= 0.0 then return Intersection_Test_Edge (P1, Q1, R1, R2, P2, Q2); else return Intersection_Test_Vertex (P1, Q1, R1, P2, Q2, R2); end if; end if; else if Orient (Q2, R2, P1) >= 0.0 then if Orient (R2, P2, P1) >= 0.0 then return Intersection_Test_Edge (P1, Q1, R1, Q2, R2, P2); else return Intersection_Test_Vertex (P1, Q1, R1, Q2, R2, P2); end if; else return Intersection_Test_Vertex (P1, Q1, R1, R2, P2, Q2); end if; end if; pragma Warnings (On, "*actuals for this call may be in wrong order"); end Tri_Intersection; --------------- -- Intersect -- --------------- -- From [TRI] function Intersect (T1, T2 : Triangle) return Boolean is begin if Orient (T1 (1), T1 (2), T1 (3)) < 0.0 then if Orient (T2 (1), T2 (2), T2 (3)) < 0.0 then return Tri_Intersection (T1 (1), T1 (3), T1 (2), T2 (1), T2 (3), T2 (2)); else return Tri_Intersection (T1 (1), T1 (3), T1 (2), T2 (1), T2 (2), T2 (3)); end if; else if Orient (T2 (1), T2 (2), T2 (3)) < 0.0 then return Tri_Intersection (T1 (1), T1 (2), T1 (3), T2 (1), T2 (3), T2 (2)); else return Tri_Intersection (T1 (1), T1 (2), T1 (3), T2 (1), T2 (2), T2 (3)); end if; end if; end Intersect; --------------- -- Intersect -- --------------- function Intersect (R1, R2 : Rectangle) return Boolean is begin return not (R1 (1).X > R2 (2).X -- R1 on the right of R2 or else R2 (1).X > R1 (2).X -- R2 on the right of R1 or else R1 (1).Y > R2 (2).Y -- R1 below R2 or else R2 (1).Y > R1 (2).Y); -- R1 above R2 end Intersect; end GNATCOLL.Geometry; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-geometry.ads000066400000000000000000000170331425465243200232360ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- A set of planar geometric utilites (intersections of segments, etc). with Ada.Numerics.Generic_Elementary_Functions; generic type Coordinate is digits <>; -- The type used to represent coordinates and distances. -- Distances are returned as a subtype including only the positive (or -- null) range, so this type must include positive numbers. package GNATCOLL.Geometry is package Coordinate_Elementary_Functions is new Ada.Numerics.Generic_Elementary_Functions (Coordinate); subtype Distance_Type is Coordinate'Base range 0.0 .. Coordinate'Base'Last; type Point is record X, Y : Coordinate; end record; -- General representation for a point in 2D No_Point : constant Point; -- Constant used to indicate that the point doesn't exist (no intersection -- for instance) Infinity_Points : constant Point; -- Constant used to indicate that an infinity number of points would match, -- for instance in the case of the intersection of coincident lines type Polygon is array (Positive range <>) of Point; type Triangle is new Polygon (1 .. 3); type Segment is array (1 .. 2) of Point; type Vector is new Point; type Rectangle is new Polygon (1 .. 2); -- A rectangle has sides parallel to the two axis of the space coordinates. -- It is defined by its top-left and bottom-right corners. If you need a -- more general definition of a rectangle, use the generic algorithms on -- polygons. type Line is private; type Circle is record Center : Point; Radius : Coordinate; end record; No_Circle : constant Circle; function To_Vector (S : Segment) return Vector; -- Return the vector that indicates the direction and magnitude of the -- segment. function To_Line (P1, P2 : Point) return Line; function To_Line (Seg : Segment) return Line; -- Return the line going through the two points, or overlapping the -- segment. function To_Circle (P1, P2, P3 : Point) return Circle; -- Return the circle that passes through the 3 points. If the 3 points are -- colinear, No_Circle is returned. function "-" (P2, P1 : Point) return Vector; -- Return the vector to go from P1 to P2. function Dot (Vector1, Vector2 : Vector) return Coordinate; -- Return the dot product of Vector1 and Vector2. Mathematically, this is -- also the value of |Vector1| * |Vector2| * cos (alpha), where alpha is -- the angle between the two vectors. When Dot is 0, the two vectors are -- orthogonal or null. function Cross (Vector1, Vector2 : Vector) return Coordinate; -- Return the magnitude of the cross-product of the two vectors. -- Technically, this is also a vector, but since we are in 2D, this is -- represented as a scalar. -- -- In 2D, this is also the value of |Vector1| * |Vector2| * sin (alpha). -- This is positive if Vector1 is less than 180 degrees clockwise from B. -- -- Last, in 2D the cross product is also the area of the parallelogram with -- two of its side formed by Vector1 and Vector2. -- ----A--- -- \ \ -- B | -- \ \ -- --------- function Length (Vect : Vector) return Distance_Type; -- Return the magnitude of the vector function Bisector (S : Segment) return Line; pragma Inline (Bisector); -- Return the bisector to S, i.e. the line that is perpendicular to S and -- goes through its middle. function Intersection (S1, S2 : Segment) return Point; function Intersection (L1, L2 : Line) return Point; -- Return the intersection of the two parameters. The result is either a -- simple point, or No_Point when they don't intersect, or -- Infinity_Points when the two parameters intersect on an infinity of -- points. function Intersect (C1, C2 : Circle) return Boolean; function Intersect (T1, T2 : Triangle) return Boolean; function Intersect (L : Line; C : Circle) return Boolean; function Intersect (R1, R2 : Rectangle) return Boolean; -- Whether the two parameters intersect function Inside (P : Point; S : Segment) return Boolean; function Inside (P : Point; L : Line) return Boolean; function Inside (P : Point; T : Triangle) return Boolean; function Inside (P : Point; Poly : Polygon) return Boolean; -- True if P is on the segment or line function Distance (From : Point; To : Point) return Distance_Type; function Distance (From : Point; To : Segment) return Distance_Type; function Distance (From : Point; To : Line) return Distance_Type; function Distance (From : Point; To : Polygon) return Distance_Type; -- Return the distance between P and the second parameter. function Centroid (Self : Polygon) return Point; -- Return the centroid of the polygon (aka center of gravity). function Area (Self : Triangle) return Distance_Type; function Area (Self : Polygon) return Distance_Type; -- Return the area of the (possibly non-convex) polygon. For the triangle, -- the area will be negative if the vertices are oriented clockwise function Same_Side (P1, P2 : Point; As : Segment) return Boolean; function Same_Side (P1, P2 : Point; As : Line) return Boolean; -- Whether the two points lay on the same side of the line overlapping -- the segment. It is slightly faster to use the Segment version private type Line is record A, B, C : Coordinate; end record; -- Representation for a line, through its equation, that -- is: Ax + By = C. See functions To_Line below if you define a line -- by a set of points. No_Point : constant Point := (Coordinate'First, Coordinate'First); No_Circle : constant Circle := (No_Point, Coordinate'First); Infinity_Points : constant Point := (Coordinate'Last, Coordinate'Last); end GNATCOLL.Geometry; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-native-codec__unix.adb000066400000000000000000000047101425465243200255300ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Unix version: todo, would require interfacing with 'locale' with Ada.Characters.Handling; use Ada.Characters.Handling; separate (GNATCOLL.IO.Native) package body Codec is ------------- -- To_UTF8 -- ------------- function To_UTF8 (Path : Wide_String) return String is begin return To_String (Path); end To_UTF8; function To_UTF8 (Path : FS_String) return String is begin return String (Path); end To_UTF8; --------------- -- From_UTF8 -- --------------- function From_UTF8 (Path : String) return FS_String is begin return FS_String (Path); end From_UTF8; function From_UTF8 (Path : String) return Wide_String is begin return To_Wide_String (Path); end From_UTF8; end Codec; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-native-codec__win32.adb000066400000000000000000000066321425465243200255140ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Windows version: all paths are already utf-8 encoded by mingw when -- GNAT_CODE_PAGE is CP_UTF8. Otherwise we need to convert to/from UTF-8. with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Environment_Variables; use Ada.Environment_Variables; with GNAT.Decode_UTF8_String; use GNAT.Decode_UTF8_String; with GNAT.Encode_UTF8_String; use GNAT.Encode_UTF8_String; separate (GNATCOLL.IO.Native) package body Codec is Is_UTF8 : Boolean := True; procedure Initialize; -- Initialize current Windows code page ---------------- -- Initialize -- ---------------- procedure Initialize is begin if Exists ("GNAT_CODE_PAGE") and then Value ("GNAT_CODE_PAGE") = "CP_ACP" then Is_UTF8 := False; end if; end Initialize; ------------- -- To_UTF8 -- ------------- function To_UTF8 (Path : Wide_String) return String is begin if Is_UTF8 then return To_String (Path); else return Encode_Wide_String (Path); end if; end To_UTF8; function To_UTF8 (Path : FS_String) return String is begin if Is_UTF8 then return String (Path); else return Encode_Wide_String (To_Wide_String (String (Path))); end if; end To_UTF8; --------------- -- From_UTF8 -- --------------- function From_UTF8 (Path : String) return Wide_String is begin if Is_UTF8 then return Decode_Wide_String (Path); else return To_Wide_String (Path); end if; end From_UTF8; function From_UTF8 (Path : String) return FS_String is begin return FS_String (To_String (From_UTF8 (Path))); end From_UTF8; begin Initialize; end Codec; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-native.adb000066400000000000000000000554511425465243200232630ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with System; with Ada.Unchecked_Deallocation; with Ada.Directories; with Ada.Calendar.Formatting; use Ada.Calendar; with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones; with GNAT.Directory_Operations; use GNAT.Directory_Operations; with GNAT.OS_Lib; with GNAT.Strings; use GNAT.Strings; with Interfaces.C; use Interfaces.C; with Interfaces.C.Strings; use Interfaces.C.Strings; with GNATCOLL.Mmap; with GNATCOLL.Path; use GNATCOLL.Path; with GNATCOLL.Utils; use GNATCOLL.Utils; package body GNATCOLL.IO.Native is package body Codec is separate; -- Separate implementation for Windows and Unix ------------ -- Create -- ------------ function Create (Path : FS_String) return File_Access is begin return new Native_File_Record' (Ref_Count => 1, Full => new FS_String'(From_Unix (Local_FS, Path)), Normalized => null, Normalized_And_Resolved => null, Kind => Unknown); end Create; ------------------------ -- Dispatching_Create -- ------------------------ function Dispatching_Create (Ref : not null access Native_File_Record; Full_Path : FS_String) return File_Access is pragma Unreferenced (Ref); begin return Create (Full_Path); end Dispatching_Create; ------------- -- To_UTF8 -- ------------- function To_UTF8 (Ref : not null access Native_File_Record; Path : FS_String) return String is pragma Unreferenced (Ref); begin return Codec.To_UTF8 (Path); end To_UTF8; --------------- -- From_UTF8 -- --------------- function From_UTF8 (Ref : not null access Native_File_Record; Path : String) return FS_String is pragma Unreferenced (Ref); begin return Codec.From_UTF8 (Path); end From_UTF8; ----------------- -- Current_Dir -- ----------------- function Current_Dir return File_Access is D : constant GNAT.Directory_Operations.Dir_Name_Str := GNAT.Directory_Operations.Get_Current_Dir; Ret : File_Access; begin Ret := Create (FS_String (D)); return Ret; end Current_Dir; -------------- -- Home_Dir -- -------------- function Home_Dir return File_Access is HOME : GNAT.Strings.String_Access := GNAT.OS_Lib.Getenv ("HOME"); Tmp : GNAT.Strings.String_Access; begin if HOME.all = "" then Free (HOME); HOME := GNAT.OS_Lib.Getenv ("USERPROFILE"); if HOME.all = "" then Free (HOME); return Create (Get_Root (Local_FS, "")); end if; end if; if HOME'Length > 2 and then HOME (HOME'First) = '%' and then HOME (HOME'Last) = '%' then -- Some Windows systems set %HOME% to another env variable, e.g. -- %USERPROFILE% Tmp := HOME; HOME := GNAT.OS_Lib.Getenv (Tmp (Tmp'First + 1 .. Tmp'Last - 1)); Free (Tmp); end if; declare -- ??? Convert from display charset to filesystem charset ? Result : constant FS_String := From_Unix (Local_FS, FS_String (HOME.all)); begin Free (HOME); return Create (Result); end; end Home_Dir; ----------------------- -- Get_Tmp_Directory -- ----------------------- function Get_Tmp_Directory return File_Access is function Internal return chars_ptr; pragma Import (C, Internal, "__gnatcoll_get_tmp_dir"); procedure c_free (C : chars_ptr); pragma Import (C, c_free, "free"); C_Str : constant chars_ptr := Internal; Str : constant FS_String := FS_String (GNAT.Directory_Operations.Format_Pathname (To_Ada (Value (C_Str)))); begin -- Since the allocation was done in C (strdup), we use directly the -- C version of free. This is probably more reliable, and more -- importantly, this works correctly with our own version of -- s-memory.adb (when GPS_MEMORY_MONITOR=1) c_free (C_Str); return Create (Ensure_Directory (Local_FS, Str)); end Get_Tmp_Directory; ------------------------ -- Get_Logical_Drives -- ------------------------ function Get_Logical_Drives return File_Array is function Internal (Buffer : System.Address; Length : Integer) return Integer; pragma Import (C, Internal, "__gnatcoll_get_logical_drive_strings"); Len : Integer; Last : Natural; N : Natural; begin -- First get the size of the buffer needed to contain the drives Len := Internal (System.Null_Address, 0); if Len = 0 then return (1 .. 0 => <>); end if; declare -- Use the returned length for creating the buffer. Do not forget -- to add room for the trailing \n Buffer : aliased FS_String (1 .. Len + 1); begin Len := Internal (Buffer'Address, Len); N := 0; for J in 1 .. Len loop if Buffer (J) = ASCII.NUL then N := N + 1; end if; end loop; declare Ret : File_Array (1 .. N); begin N := 1; Last := Buffer'First; for J in 1 .. Len loop if Buffer (J) = ASCII.NUL then Ret (N) := Create (GNATCOLL.Path.Path (Local_FS, Buffer (Last .. Last), "", "")); N := N + 1; Last := J + 1; end if; end loop; return Ret; end; end; end Get_Logical_Drives; -------------- -- Is_Local -- -------------- function Is_Local (File : Native_File_Record) return Boolean is pragma Unreferenced (File); begin return True; end Is_Local; ------------ -- Get_FS -- ------------ function Get_FS (File : not null access Native_File_Record) return FS_Type is pragma Unreferenced (File); begin return Local_FS; end Get_FS; ---------------------- -- Resolve_Symlinks -- ---------------------- procedure Resolve_Symlinks (File : not null access Native_File_Record) is Is_Dir_Path : Boolean; begin if File.Normalized_And_Resolved = null then Is_Dir_Path := Path.Is_Dir_Name (File.Get_FS, File.Full.all); declare -- We have to pass "" for the directory, in case File.Full is a -- relative path name. That might be surprising to the application -- since the current directory might have changed since File was -- created. Norm : constant String := GNAT.OS_Lib.Normalize_Pathname (String (File.Full.all), Directory => "", Resolve_Links => True); begin -- Normalize_Pathname sometimes removes the trailing dir separator -- We need to take care of it then. if not Is_Dir_Path or else Norm (Norm'Last) = GNAT.OS_Lib.Directory_Separator then if File.Normalized /= null and then FS_String (Norm) = File.Normalized.all then File.Normalized_And_Resolved := File.Normalized; else File.Normalized_And_Resolved := new FS_String'(FS_String (Norm)); end if; else if File.Normalized /= null and then FS_String (Norm) & GNAT.OS_Lib.Directory_Separator = File.Normalized.all then File.Normalized_And_Resolved := File.Normalized; else File.Normalized_And_Resolved := new FS_String' (FS_String (Norm) & GNAT.OS_Lib.Directory_Separator); end if; end if; end; end if; end Resolve_Symlinks; --------------------- -- Is_Regular_File -- --------------------- function Is_Regular_File (File : not null access Native_File_Record) return Boolean is begin return GNAT.OS_Lib.Is_Regular_File (String (File.Full.all)); end Is_Regular_File; ---------- -- Size -- ---------- function Size (File : not null access Native_File_Record) return Long_Integer is Fd : constant GNAT.OS_Lib.File_Descriptor := GNAT.OS_Lib.Open_Read (String (File.Full.all), Fmode => GNAT.OS_Lib.Binary); pragma Warnings (Off); Result : constant Long_Integer := Long_Integer (GNAT.OS_Lib.File_Length (Fd)); pragma Warnings (On); begin GNAT.OS_Lib.Close (Fd); return Result; end Size; ------------------ -- Is_Directory -- ------------------ function Is_Directory (File : not null access Native_File_Record) return Boolean is begin if GNAT.OS_Lib.Directory_Separator = '\' and then File.Full (File.Full'First .. File.Full'First + 1) = "\\" then -- There is an issue with (at least) GNAT 6.2 when Is_Directory -- returns False for Windows network paths (e.g. \\host\shared\). -- In this case, we try to open the directory and see if it works. declare Dir : GNAT.Directory_Operations.Dir_Type; begin GNAT.Directory_Operations.Open (Dir, String (File.Full.all)); GNAT.Directory_Operations.Close (Dir); return True; exception when GNAT.Directory_Operations.Directory_Error => return False; end; else return GNAT.OS_Lib.Is_Directory (String (File.Full.all)); end if; end Is_Directory; ---------------------- -- Is_Symbolic_Link -- ---------------------- function Is_Symbolic_Link (File : not null access Native_File_Record) return Boolean is begin return GNAT.OS_Lib.Is_Symbolic_Link (String (File.Full.all)); end Is_Symbolic_Link; --------------------- -- File_Time_Stamp -- --------------------- TZ : constant Time_Offset := UTC_Time_Offset; -- Time zone cache, assuming that the OS will not change time zones while -- this partition is running. function File_Time_Stamp (File : not null access Native_File_Record) return Ada.Calendar.Time is T : constant GNAT.OS_Lib.OS_Time := GNAT.OS_Lib.File_Time_Stamp (String (File.Full.all)); Year : GNAT.OS_Lib.Year_Type; Month : GNAT.OS_Lib.Month_Type; Day : GNAT.OS_Lib.Day_Type; Hour : GNAT.OS_Lib.Hour_Type; Minute : GNAT.OS_Lib.Minute_Type; Second : GNAT.OS_Lib.Second_Type; use type GNAT.OS_Lib.OS_Time; begin if T = GNAT.OS_Lib.Invalid_Time then return GNATCOLL.Utils.No_Time; end if; GNAT.OS_Lib.GM_Split (T, Year, Month, Day, Hour, Minute, Second); return Ada.Calendar.Formatting.Time_Of (Year => Year_Number (Year), Month => Month_Number (Month), Day => Day_Number (Day), Hour => Formatting.Hour_Number (Hour), Minute => Formatting.Minute_Number (Minute), Second => Formatting.Second_Number (Second), Sub_Second => 0.0, Time_Zone => TZ); end File_Time_Stamp; ----------------- -- Is_Readable -- ----------------- function Is_Readable (File : not null access Native_File_Record) return Boolean is begin return GNAT.OS_Lib.Is_Readable_File (String (File.Full.all)); end Is_Readable; ----------------- -- Is_Writable -- ----------------- function Is_Writable (File : not null access Native_File_Record) return Boolean is begin return GNAT.OS_Lib.Is_Writable_File (String (File.Full.all)); end Is_Writable; ------------------ -- Set_Writable -- ------------------ procedure Set_Writable (File : not null access Native_File_Record; State : Boolean) is begin if State then GNAT.OS_Lib.Set_Writable (String (File.Full.all)); else GNAT.OS_Lib.Set_Non_Writable (String (File.Full.all)); end if; end Set_Writable; ------------------ -- Set_Readable -- ------------------ procedure Set_Readable (File : not null access Native_File_Record; State : Boolean) is begin if State then GNAT.OS_Lib.Set_Readable (String (File.Full.all)); else GNAT.OS_Lib.Set_Non_Readable (String (File.Full.all)); end if; end Set_Readable; ------------ -- Rename -- ------------ procedure Rename (From : not null access Native_File_Record; Dest : not null access Native_File_Record; Success : out Boolean) is begin GNAT.OS_Lib.Rename_File (String (From.Full.all), String (Dest.Full.all), Success); exception when others => Success := False; end Rename; ---------- -- Copy -- ---------- procedure Copy (From : not null access Native_File_Record; Dest : FS_String; Success : out Boolean) is begin GNAT.OS_Lib.Copy_File (String (From.Full.all), String (Dest), Success, Mode => GNAT.OS_Lib.Overwrite, Preserve => GNAT.OS_Lib.Full); exception when others => Success := False; end Copy; ------------ -- Delete -- ------------ procedure Delete (File : not null access Native_File_Record; Success : out Boolean) is begin GNAT.OS_Lib.Delete_File (String (File.Full.all), Success); end Delete; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (File : not null access Native_File_Record) return GNAT.Strings.String_Access is begin return GNATCOLL.Mmap.Read_Whole_File (String (File.Full.all)); exception when others => return null; end Read_Whole_File; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (File : not null access Native_File_Record) return GNATCOLL.Strings.XString is begin return GNATCOLL.Mmap.Read_Whole_File (String (File.Full.all)); exception when others => return GNATCOLL.Strings.Null_XString; end Read_Whole_File; ---------------- -- Open_Write -- ---------------- procedure Open_Write (File : not null access Native_File_Record; Append : Boolean := False; FD : out GNAT.OS_Lib.File_Descriptor) is begin if Append then FD := GNAT.OS_Lib.Open_Read_Write (String (File.Full.all), Fmode => GNAT.OS_Lib.Binary); GNAT.OS_Lib.Lseek (FD, 0, GNAT.OS_Lib.Seek_End); else FD := GNAT.OS_Lib.Create_File (String (File.Full.all), Fmode => GNAT.OS_Lib.Binary); end if; exception when others => FD := GNAT.OS_Lib.Invalid_FD; end Open_Write; ----------- -- Close -- ----------- procedure Close (File : not null access Native_File_Record; FD : GNAT.OS_Lib.File_Descriptor; Success : out Boolean) is pragma Unreferenced (File); use type GNAT.OS_Lib.File_Descriptor; begin if FD /= GNAT.OS_Lib.Invalid_FD then GNAT.OS_Lib.Close (FD); Success := True; else Success := False; end if; end Close; ---------------- -- Change_Dir -- ---------------- function Change_Dir (Dir : not null access Native_File_Record) return Boolean is begin GNAT.Directory_Operations.Change_Dir (String (Dir.Full.all)); return True; exception when others => return False; end Change_Dir; -------------- -- Read_Dir -- -------------- function Read_Dir (Dir : not null access Native_File_Record; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List is Name : constant String := String (Ensure_Directory (Local_FS, Dir.Full.all)); D : GNAT.Directory_Operations.Dir_Type; Item : String (1 .. 1024); Last : Natural; Ret : GNAT.Strings.String_List_Access; Tmp : GNAT.Strings.String_List_Access; N : Natural := 0; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (GNAT.Strings.String_List, GNAT.Strings.String_List_Access); begin GNAT.Directory_Operations.Open (D, String (Dir.Full.all)); loop GNAT.Directory_Operations.Read (D, Item, Last); exit when Last = 0; if Item (1 .. Last) /= "." and then Item (1 .. Last) /= ".." and then (not Dirs_Only or else GNAT.OS_Lib.Is_Directory (Name & Item (1 .. Last))) and then (not Files_Only or else GNAT.OS_Lib.Is_Regular_File (Name & Item (1 .. Last))) then if Ret = null then Ret := new GNAT.Strings.String_List (1 .. 10); elsif N = Ret'Last then Tmp := new GNAT.Strings.String_List (1 .. Ret'Length * 2); Tmp (Ret'Range) := Ret.all; Unchecked_Free (Ret); Ret := Tmp; end if; N := N + 1; Ret (N) := new String'(Item (1 .. Last)); end if; end loop; GNAT.Directory_Operations.Close (D); if N = 0 then return (1 .. 0 => <>); end if; declare List : constant GNAT.Strings.String_List := Ret (1 .. N); begin Unchecked_Free (Ret); return List; end; end Read_Dir; -------------- -- Make_Dir -- -------------- function Make_Dir (Dir : not null access Native_File_Record; Recursive : Boolean) return Boolean is begin if Recursive then Ada.Directories.Create_Path (String (Dir.Full.all)); else Ada.Directories.Create_Directory (String (Dir.Full.all)); end if; return True; exception when GNAT.Directory_Operations.Directory_Error => return False; end Make_Dir; ---------------- -- Remove_Dir -- ---------------- procedure Remove_Dir (Dir : not null access Native_File_Record; Recursive : Boolean; Success : out Boolean) is begin GNAT.Directory_Operations.Remove_Dir (String (Dir.Full.all), Recursive); Success := True; exception when GNAT.Directory_Operations.Directory_Error => Success := False; end Remove_Dir; -------------- -- Copy_Dir -- -------------- procedure Copy_Dir (From : not null access Native_File_Record; Dest : FS_String; Success : out Boolean) is begin if not Is_Directory (From) then Success := False; return; end if; if not GNAT.OS_Lib.Is_Directory (String (Dest)) then begin GNAT.Directory_Operations.Make_Dir (String (Dest)); exception when others => Success := False; return; end; end if; declare Files : GNAT.Strings.String_List := Read_Dir (From); begin Success := True; for F in Files'Range loop declare Tmp_From : File_Access := Create (GNATCOLL.Path.Path (Local_FS, "", From.Full.all, FS_String (Files (F).all))); To_Str : constant FS_String := GNATCOLL.Path.Path (Local_FS, "", Dest, FS_String (Files (F).all)); begin if Is_Directory (Tmp_From) then Copy_Dir (Tmp_From, To_Str, Success); Unref (Tmp_From); exit when not Success; else Copy (Tmp_From, To_Str, Success); Unref (Tmp_From); exit when not Success; end if; end; GNAT.Strings.Free (Files (F)); end loop; exception when others => for J in Files'Range loop GNAT.Strings.Free (Files (J)); end loop; Success := False; end; exception when others => Success := False; end Copy_Dir; --------------------------- -- Copy_File_Permissions -- --------------------------- overriding procedure Copy_File_Permissions (From, To : not null access Native_File_Record; Success : out Boolean) is begin GNAT.OS_Lib.Copy_File_Attributes (From => String (From.Full.all), To => String (To.Full.all), Success => Success, Copy_Timestamp => False, Copy_Permissions => True); end Copy_File_Permissions; end GNATCOLL.IO.Native; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-native.ads000066400000000000000000000147771425465243200233120ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ private with GNATCOLL.Path; package GNATCOLL.IO.Native is type Native_File_Record is new File_Record with private; function Create (Path : FS_String) return File_Access; ------------------------------ -- Utilities for native FS -- ------------------------------ function Current_Dir return File_Access; -- Return the current directory function Home_Dir return File_Access; -- Return the home directory function Get_Tmp_Directory return File_Access; -- Return the directory that can be used to store temporary -- files on the filesystem. function Get_Logical_Drives return File_Array; Local_Root_Dir : constant File_Access; ---------------------------- -- Overridden from parent -- ---------------------------- overriding function Dispatching_Create (Ref : not null access Native_File_Record; Full_Path : FS_String) return File_Access; overriding function To_UTF8 (Ref : not null access Native_File_Record; Path : FS_String) return String; overriding function From_UTF8 (Ref : not null access Native_File_Record; Path : String) return FS_String; overriding function Is_Local (File : Native_File_Record) return Boolean; overriding function Get_FS (File : not null access Native_File_Record) return FS_Type; overriding procedure Resolve_Symlinks (File : not null access Native_File_Record); overriding function Is_Regular_File (File : not null access Native_File_Record) return Boolean; function Size (File : not null access Native_File_Record) return Long_Integer; overriding function Is_Directory (File : not null access Native_File_Record) return Boolean; overriding function Is_Symbolic_Link (File : not null access Native_File_Record) return Boolean; overriding function File_Time_Stamp (File : not null access Native_File_Record) return Ada.Calendar.Time; overriding function Is_Writable (File : not null access Native_File_Record) return Boolean; overriding procedure Set_Writable (File : not null access Native_File_Record; State : Boolean); overriding function Is_Readable (File : not null access Native_File_Record) return Boolean; overriding procedure Set_Readable (File : not null access Native_File_Record; State : Boolean); overriding procedure Rename (From : not null access Native_File_Record; Dest : not null access Native_File_Record; Success : out Boolean); overriding procedure Copy (From : not null access Native_File_Record; Dest : FS_String; Success : out Boolean); overriding procedure Delete (File : not null access Native_File_Record; Success : out Boolean); overriding function Read_Whole_File (File : not null access Native_File_Record) return GNAT.Strings.String_Access; overriding function Read_Whole_File (File : not null access Native_File_Record) return GNATCOLL.Strings.XString; overriding procedure Open_Write (File : not null access Native_File_Record; Append : Boolean := False; FD : out GNAT.OS_Lib.File_Descriptor); overriding procedure Close (File : not null access Native_File_Record; FD : GNAT.OS_Lib.File_Descriptor; Success : out Boolean); overriding function Change_Dir (Dir : not null access Native_File_Record) return Boolean; overriding function Read_Dir (Dir : not null access Native_File_Record; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List; overriding function Make_Dir (Dir : not null access Native_File_Record; Recursive : Boolean) return Boolean; overriding procedure Remove_Dir (Dir : not null access Native_File_Record; Recursive : Boolean; Success : out Boolean); overriding procedure Copy_Dir (From : not null access Native_File_Record; Dest : FS_String; Success : out Boolean); overriding procedure Copy_File_Permissions (From, To : not null access Native_File_Record; Success : out Boolean); package Codec is function To_UTF8 (Path : FS_String) return String; function To_UTF8 (Path : Wide_String) return String; function From_UTF8 (Path : String) return FS_String; function From_UTF8 (Path : String) return Wide_String; end Codec; -- Codec to translate a path to/from utf-8 private type Native_File_Record is new File_Record with null record; Local_Root_Dir : constant File_Access := new Native_File_Record' (Ref_Count => 1, Full => new FS_String' (GNATCOLL.Path.Path (GNATCOLL.Path.Local_FS, "", "", "")), Normalized => null, Normalized_And_Resolved => null, Kind => Directory); end GNATCOLL.IO.Native; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-remote-unix.adb000066400000000000000000000523451425465243200242500ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.Expect; use GNAT.Expect; with GNAT.Regpat; use GNAT.Regpat; with GNATCOLL.Utils; package body GNATCOLL.IO.Remote.Unix is procedure Free (Args : in out GNAT.OS_Lib.Argument_List); -- Free all strings in Args. ---------- -- Free -- ---------- procedure Free (Args : in out GNAT.OS_Lib.Argument_List) is begin for J in Args'Range loop Free (Args (J)); end loop; end Free; ----------------- -- Current_Dir -- ----------------- function Current_Dir (Exec : access Server_Record'Class) return FS_String is Args : GNAT.OS_Lib.Argument_List := (1 => new String'("pwd")); Output : String_Access; Status : Boolean; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status then declare -- Don't try to translate the string into a directory, as this -- is all handled later at VFS level. Result : constant FS_String := FS_String (Output.all); begin Free (Output); return Result; end; else return "/"; end if; end Current_Dir; -------------- -- Home_Dir -- -------------- function Home_Dir (Exec : access Server_Record'Class) return FS_String is Args : GNAT.OS_Lib.Argument_List := (new String'("echo"), new String'("$HOME")); Output : String_Access; Status : Boolean; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status then declare -- Don't try to translate the string into a directory, as this -- is all handled later at VFS level. Result : constant FS_String := FS_String (Output.all); begin Free (Output); return Result; end; else return "/"; end if; end Home_Dir; ------------- -- Tmp_Dir -- ------------- function Tmp_Dir (Exec : access Server_Record'Class) return FS_String is Args : GNAT.OS_Lib.Argument_List := (new String'("echo"), new String'("$TMP")); Output : String_Access; Status : Boolean; begin Exec.Execute_Remotely (Args, Output, Status); if not Status then GNAT.OS_Lib.Free (Args (2)); Args (2) := new String'("$TMPDIR"); Exec.Execute_Remotely (Args, Output, Status); end if; Free (Args); if Status then declare -- Don't try to translate the string into a directory, as this -- is all handled later at VFS level. Result : constant FS_String := FS_String (Output.all); begin Free (Output); return Result; end; else return "/tmp/"; end if; end Tmp_Dir; ------------------------ -- Get_Logical_Drives -- ------------------------ function Get_Logical_Drives (Exec : access Server_Record'Class) return String_List_Access is -- No drives on unix pragma Unreferenced (Exec); begin return null; end Get_Logical_Drives; -------------------- -- Locate_On_Path -- -------------------- function Locate_On_Path (Exec : access Server_Record'Class; Base : FS_String) return FS_String is Args : GNAT.OS_Lib.Argument_List := (new String'("which"), new String'(String (Base))); Output : String_Access; Status : Boolean; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status then declare -- Don't try to translate the string into a directory, as this -- is all handled later at VFS level. Result : constant FS_String := FS_String (Output.all); begin Free (Output); return Result; end; else return ""; end if; end Locate_On_Path; --------------------- -- Is_Regular_File -- --------------------- function Is_Regular_File (Exec : access Server_Record'Class; File : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("test"), new String'("-r"), new String'("""" & String (File) & """")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Is_Regular_File; ---------- -- Size -- ---------- function Size (Exec : access Server_Record'Class; File : FS_String) return Long_Integer is Args : GNAT.OS_Lib.Argument_List := (new String'("stat"), new String'("-s"), new String'("""" & String (File) & """")); Status : Boolean; Regexp : constant Pattern_Matcher := Compile ("st_size=(\d+)"); Output : String_Access; Matched : Match_Array (0 .. 1); Size : Long_Integer := 0; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status and then Output /= null then Match (Regexp, Output.all, Matched); if Matched (1) /= No_Match then Size := Long_Integer'Value (Output (Matched (1).First .. Matched (1).Last)); end if; end if; Free (Output); return Size; end Size; ------------------ -- Is_Directory -- ------------------ function Is_Directory (Exec : access Server_Record'Class; File : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("test"), new String'("-d"), new String'("""" & String (File) & """")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Is_Directory; ---------------------- -- Is_Symbolic_Link -- ---------------------- function Is_Symbolic_Link (Exec : access Server_Record'Class; File : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("test"), new String'("-L"), new String'("""" & String (File) & """")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Is_Symbolic_Link; --------------------- -- File_Time_Stamp -- --------------------- function File_Time_Stamp (Exec : access Server_Record'Class; File : FS_String) return Ada.Calendar.Time is Args : GNAT.OS_Lib.Argument_List := (new String'("ls"), new String'("-l"), new String'("--time-style=full-iso"), new String'("""" & String (File) & """"), new String'("2>"), new String'("/dev/null")); Status : Boolean; Regexp : constant Pattern_Matcher := Compile ("(\d\d\d\d[-]\d\d[-]\d\d)\s+(\d\d:\d\d:\d\d[.]\d+)\s+"); Matched : Match_Array (0 .. 2); Output : String_Access; Year : Natural; Month : Natural; Day : Natural; Hour : Natural; Minute : Natural; Second : Ada.Calendar.Day_Duration; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status and then Output /= null then Match (Regexp, Output.all, Matched); if Matched (0) = No_Match then Free (Output); return GNATCOLL.Utils.No_Time; end if; Year := Natural'Value (Output (Matched (1).First .. Matched (1).First + 3)); Month := Natural'Value (Output (Matched (1).First + 5 .. Matched (1).First + 6)); Day := Natural'Value (Output (Matched (1).First + 8 .. Matched (1).First + 9)); Hour := Natural'Value (Output (Matched (2).First .. Matched (2).First + 1)); Minute := Natural'Value (Output (Matched (2).First + 3 .. Matched (2).First + 4)); Second := Ada.Calendar.Day_Duration'Value (Output (Matched (2).First + 6 .. Matched (2).Last)); Second := Second + (60.0 * Ada.Calendar.Day_Duration (Minute)) + (3600.0 * Ada.Calendar.Day_Duration (Hour)); Free (Output); return Ada.Calendar.Time_Of (Year, Month, Day, Second); end if; Free (Output); return GNATCOLL.Utils.No_Time; end File_Time_Stamp; ----------------- -- Is_Readable -- ----------------- function Is_Readable (Exec : access Server_Record'Class; File : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("test"), new String'("-r"), new String'("""" & String (File) & """")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Is_Readable; ----------------- -- Is_Writable -- ----------------- function Is_Writable (Exec : access Server_Record'Class; File : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("test"), new String'("-w"), new String'("""" & String (File) & """")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Is_Writable; ------------------ -- Set_Writable -- ------------------ procedure Set_Writable (Exec : access Server_Record'Class; File : FS_String; State : Boolean) is Args : GNAT.OS_Lib.Argument_List := (1 => new String'("chmod"), 2 => new String'("u+w"), 3 => new String'("""" & String (File) & """")); Unused_Status : Boolean; begin if not State then Args (2).all := "u-w"; end if; Exec.Execute_Remotely (Args, Unused_Status); Free (Args); end Set_Writable; ------------------ -- Set_Readable -- ------------------ procedure Set_Readable (Exec : access Server_Record'Class; File : FS_String; State : Boolean) is Args : GNAT.OS_Lib.Argument_List := (1 => new String'("chmod"), 2 => new String'("u+r"), 3 => new String'("""" & String (File) & """")); Unused_Status : Boolean; begin if not State then Args (2).all := "u-r"; end if; Exec.Execute_Remotely (Args, Unused_Status); Free (Args); end Set_Readable; ------------ -- Rename -- ------------ procedure Rename (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("mv"), new String'("""" & String (From) & """"), new String'("""" & String (Dest) & """")); begin Exec.Execute_Remotely (Args, Success); Free (Args); end Rename; ---------- -- Copy -- ---------- procedure Copy (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("cp"), new String'("-f"), new String'("""" & String (From) & """"), new String'("""" & String (Dest) & """")); begin Exec.Execute_Remotely (Args, Success); Free (Args); end Copy; ------------ -- Delete -- ------------ procedure Delete (Exec : access Server_Record'Class; File : FS_String; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("rm"), new String'("-f"), new String'("""" & String (File) & """")); begin Exec.Execute_Remotely (Args, Success); Free (Args); end Delete; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (Exec : access Server_Record'Class; File : FS_String) return GNAT.Strings.String_Access is Args : GNAT.OS_Lib.Argument_List := (new String'("cat"), new String'("""" & String (File) & """")); Status : Boolean; Output : String_Access; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); return Output; end Read_Whole_File; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (Exec : access Server_Record'Class; File : FS_String) return GNATCOLL.Strings.XString is Args : GNAT.OS_Lib.Argument_List := (new String'("cat"), new String'("""" & String (File) & """")); Status : Boolean; Output : String_Access; Result : XString; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); Result.Set (Output.all); -- needs a copy of the string Free (Output); return Result; end Read_Whole_File; ---------------- -- Write_File -- ---------------- function Write_File (Exec : access Server_Record'Class; File : FS_String; Content : String) return Boolean is Pd : Process_Descriptor_Access; Args : GNAT.OS_Lib.Argument_List := (1 => new String'("cat"), 2 => new String'(">"), 3 => new String'("""" & String (File) & """"), 4 => new String'("<<"), 5 => new String'("GPSEOF")); Regexp : constant Pattern_Matcher := Compile ("[>] ", Single_Line or Multiple_Lines); Res : Expect_Match; begin Exec.Spawn_Remotely (Descriptor => Pd, Args => Args); Send (Pd.all, Content); Send (Pd.all, "GPSEOF"); loop Expect (Pd.all, Res, Regexp, 5000); if Res = Expect_Timeout then Flush (Pd.all); Close (Pd.all); exit; end if; end loop; Free (Args); return True; exception when Process_Died => Close (Pd.all); Free (Args); return False; end Write_File; ---------------- -- Change_Dir -- ---------------- function Change_Dir (Exec : access Server_Record'Class; Dir : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("cd"), new String'("""" & String (Dir) & """")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Change_Dir; -------------- -- Read_Dir -- -------------- function Read_Dir (Exec : access Server_Record'Class; Dir : FS_String; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List is function Create_Args return GNAT.OS_Lib.Argument_List; -- Return dir arguments following the Dirs_Only and Files_Only arguments ----------------- -- Create_Args -- ----------------- function Create_Args return GNAT.OS_Lib.Argument_List is begin -- Launch with sh to be able to redirect stderr to /dev/null, even -- when using (t)csh if Dirs_Only then return (new String'("sh"), new String'("-c"), new String'("ls -AL1F '" & String (Dir) & "' 2> /dev/null | grep /$")); elsif Files_Only then return (new String'("sh"), new String'("-c"), new String'("ls -AL1F '" & String (Dir) & "' 2> /dev/null | grep -v /$ | " & "sed -e 's/[*=@\|]$//'")); else return (new String'("sh"), new String'("-c"), new String'("ls"), new String'("-A1"), new String'("'" & String (Dir) & "'")); end if; end Create_Args; Args : GNAT.OS_Lib.Argument_List := Create_Args; Status : Boolean; Output : String_Access; Regexp : constant Pattern_Matcher := Compile ("^(.+)$", Multiple_Lines); Matched : Match_Array (0 .. 1); Index : Integer; Nb_Files : Natural; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Output /= null then Index := Output'First; Nb_Files := 0; while Index <= Output'Last loop Match (Regexp, Output (Index .. Output'Last), Matched); exit when Matched (0) = No_Match; Index := Matched (1).Last + 1; if Output (Matched (1).First .. Matched (1).Last) /= "." and then Output (Matched (1).First .. Matched (1).Last) /= ".." then Nb_Files := Nb_Files + 1; end if; end loop; declare List : String_List (1 .. Nb_Files); File_Idx : Natural; begin Index := Output'First; File_Idx := List'First; while Index /= Output'Last loop Match (Regexp, Output.all, Matched, Index); exit when Matched (0) = No_Match; Index := Matched (1).Last + 1; if Output (Matched (1).First .. Matched (1).Last) /= "." and then Output (Matched (1).First .. Matched (1).Last) /= ".." then List (File_Idx) := new String' (Output (Matched (1).First .. Matched (1).Last)); File_Idx := File_Idx + 1; end if; end loop; return List; end; end if; Free (Output); return (1 .. 0 => null); end Read_Dir; -------------- -- Make_Dir -- -------------- function Make_Dir (Exec : access Server_Record'Class; Dir : FS_String; Recursive : Boolean) return Boolean is Status : Boolean; Args : GNAT.OS_Lib.Argument_List := (1 => new String'("mkdir"), 2 => new String'("-p"), 3 => new String'("'" & String (Dir) & "'")); begin if Recursive then Exec.Execute_Remotely (Args, Status); else Exec.Execute_Remotely ((1 => Args (1), 2 => Args (3)), Status); end if; Free (Args); return Status; end Make_Dir; -------------- -- Copy_Dir -- -------------- procedure Copy_Dir (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("cp"), new String'("-rf"), new String'("'" & String (From) & "'"), new String'("'" & String (Dest) & "'")); begin Exec.Execute_Remotely (Args, Success); Free (Args); end Copy_Dir; ---------------- -- Delete_Dir -- ---------------- procedure Delete_Dir (Exec : access Server_Record'Class; Dir : FS_String; Recursive : Boolean; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (1 => new String'("rm"), 2 => new String'("-r"), 3 => new String'("'" & String (Dir) & "'")); begin if Recursive then Free (Args (2)); Args (2) := new String'("-rf"); end if; Exec.Execute_Remotely (Args, Success); Free (Args); end Delete_Dir; end GNATCOLL.IO.Remote.Unix; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-remote-unix.ads000066400000000000000000000116551425465243200242700ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.Strings; use GNAT.Strings; with GNATCOLL.Remote; use GNATCOLL.Remote; package GNATCOLL.IO.Remote.Unix is -- The following methods are equivalent to their native counterparts. -- See GNATCOLL.IO for documentation. function Current_Dir (Exec : access Server_Record'Class) return FS_String; function Home_Dir (Exec : access Server_Record'Class) return FS_String; function Tmp_Dir (Exec : access Server_Record'Class) return FS_String; function Get_Logical_Drives (Exec : access Server_Record'Class) return String_List_Access; function Locate_On_Path (Exec : access Server_Record'Class; Base : FS_String) return FS_String; function Is_Regular_File (Exec : access Server_Record'Class; File : FS_String) return Boolean; function Size (Exec : access Server_Record'Class; File : FS_String) return Long_Integer; function Is_Directory (Exec : access Server_Record'Class; File : FS_String) return Boolean; function Is_Symbolic_Link (Exec : access Server_Record'Class; File : FS_String) return Boolean; function File_Time_Stamp (Exec : access Server_Record'Class; File : FS_String) return Ada.Calendar.Time; function Is_Writable (Exec : access Server_Record'Class; File : FS_String) return Boolean; procedure Set_Writable (Exec : access Server_Record'Class; File : FS_String; State : Boolean); function Is_Readable (Exec : access Server_Record'Class; File : FS_String) return Boolean; procedure Set_Readable (Exec : access Server_Record'Class; File : FS_String; State : Boolean); procedure Rename (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean); procedure Copy (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean); procedure Delete (Exec : access Server_Record'Class; File : FS_String; Success : out Boolean); function Read_Whole_File (Exec : access Server_Record'Class; File : FS_String) return GNAT.Strings.String_Access; function Read_Whole_File (Exec : access Server_Record'Class; File : FS_String) return GNATCOLL.Strings.XString; function Write_File (Exec : access Server_Record'Class; File : FS_String; Content : String) return Boolean; function Change_Dir (Exec : access Server_Record'Class; Dir : FS_String) return Boolean; function Read_Dir (Exec : access Server_Record'Class; Dir : FS_String; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List; function Make_Dir (Exec : access Server_Record'Class; Dir : FS_String; Recursive : Boolean) return Boolean; procedure Copy_Dir (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean); procedure Delete_Dir (Exec : access Server_Record'Class; Dir : FS_String; Recursive : Boolean; Success : out Boolean); end GNATCOLL.IO.Remote.Unix; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-remote-windows.adb000066400000000000000000000574411425465243200247610ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Utils; with GNAT.Regpat; use GNAT.Regpat; package body GNATCOLL.IO.Remote.Windows is procedure Free (Args : in out GNAT.OS_Lib.Argument_List); -- Free all strings in Args. ---------- -- Free -- ---------- procedure Free (Args : in out GNAT.OS_Lib.Argument_List) is begin for J in Args'Range loop Free (Args (J)); end loop; end Free; ----------------- -- Current_Dir -- ----------------- function Current_Dir (Exec : access Server_Record'Class) return FS_String is Args : GNAT.OS_Lib.Argument_List := (1 => new String'("echo"), 2 => new String'("%CD%")); Output : GNAT.OS_Lib.String_Access; Status : Boolean; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status then declare Result : constant FS_String := FS_String (Output.all); begin Free (Output); return Result; end; else return "C:\"; end if; end Current_Dir; -------------- -- Home_Dir -- -------------- function Home_Dir (Exec : access Server_Record'Class) return FS_String is Args : GNAT.OS_Lib.Argument_List := (1 => new String'("echo"), 2 => new String'("%HOME%")); Output : GNAT.OS_Lib.String_Access; Status : Boolean; begin Exec.Execute_Remotely (Args, Output, Status); if not Status then GNAT.OS_Lib.Free (Args (2)); Args (2) := new String'("%USERPROFILE%"); Exec.Execute_Remotely (Args, Output, Status); end if; Free (Args); if Status then declare Result : constant FS_String := FS_String (Output.all); begin Free (Output); return Result; end; else return "C:\"; end if; end Home_Dir; ------------- -- Tmp_Dir -- ------------- function Tmp_Dir (Exec : access Server_Record'Class) return FS_String is Args : GNAT.OS_Lib.Argument_List := (1 => new String'("echo"), 2 => new String'("%TMP%")); Output : GNAT.OS_Lib.String_Access; Status : Boolean; begin Exec.Execute_Remotely (Args, Output, Status); if not Status then GNAT.OS_Lib.Free (Args (2)); Args (2) := new String'("%TMPDIR%"); Exec.Execute_Remotely (Args, Output, Status); end if; Free (Args); if Status then declare Result : constant FS_String := FS_String (Output.all); begin Free (Output); return Result; end; else return "C:\tmp\"; end if; end Tmp_Dir; ------------------------ -- Get_Logical_Drives -- ------------------------ function Get_Logical_Drives (Exec : access Server_Record'Class) return String_List_Access is Status : Boolean; Args : GNAT.OS_Lib.Argument_List := (1 => new String'("vol"), 2 => null, 3 => new String'("2>&1")); Ret : String_List (1 .. 24); Idx : Natural := Ret'First; begin for Drive in Character'('C') .. Character'('Z') loop Args (2) := new String'(Drive & ":"); Exec.Execute_Remotely (Args, Status); Free (Args (2)); if Status then Ret (Idx) := new String'(Drive & ":"); Idx := Idx + 1; end if; end loop; Free (Args); return new String_List'(Ret (1 .. Idx - 1)); end Get_Logical_Drives; -------------------- -- Locate_On_Path -- -------------------- function Locate_On_Path (Exec : access Server_Record'Class; Base : FS_String) return FS_String is function Get_Base return String; function Get_Base return String is begin if Base'Length < 4 or else Base (Base'Last - 3 .. Base'Last) /= ".exe" then return String (Base) & ".exe"; else return String (Base); end if; end Get_Base; Args : GNAT.OS_Lib.Argument_List := (new String'("for"), new String'("/f"), new String'("""usebackq"""), new String'("%i"), new String'("in"), new String'("('" & Get_Base & "')"), new String'("do"), new String'("@echo"), new String'("%~dp$PATH:i%i")); Output : String_Access; Status : Boolean; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status then if Output.all /= Get_Base then declare -- Don't try to translate the string into a directory, as this -- is all handled later at VFS level. Result : constant FS_String := FS_String (Output.all); begin Free (Output); return Result; end; else Free (Output); return ""; end if; else return ""; end if; end Locate_On_Path; --------------------- -- Is_Regular_File -- --------------------- function Is_Regular_File (Exec : access Server_Record'Class; File : FS_String) return Boolean is -- Redirect stderr to stdout for synchronisation purpose -- (stderr is asynchronous on windows) Args : GNAT.OS_Lib.Argument_List := (new String'("dir"), new String'("/a-d"), new String'("""" & String (File) & """"), new String'("2>&1")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Is_Regular_File; ---------- -- Size -- ---------- function Size (Exec : access Server_Record'Class; File : FS_String) return Long_Integer is Args : GNAT.OS_Lib.Argument_List := (new String'("dir"), new String'("/-C"), new String'("""" & String (File) & """"), new String'("2>&1")); Status : Boolean; Size : Long_Integer := 0; Output : GNAT.Strings.String_Access; S : GNAT.Strings.String_List_Access; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status and Output /= null then S := GNATCOLL.Utils.Split (Output.all, ' '); begin Size := Long_Integer'Value (S (S'First + 2).all); exception when Constraint_Error => Size := 0; end; Free (S); end if; Free (Output); return Size; end Size; ------------------ -- Is_Directory -- ------------------ function Is_Directory (Exec : access Server_Record'Class; File : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("dir"), new String'("/ad"), new String'("""" & String (File) & """"), new String'("2>&1")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Is_Directory; ---------------------- -- Is_Symbolic_Link -- ---------------------- function Is_Symbolic_Link (Exec : access Server_Record'Class; File : FS_String) return Boolean is pragma Unreferenced (Exec, File); begin -- ??? There are now symbolic links on Windows (Vista, Server 2008). -- Should we handle them ? return False; end Is_Symbolic_Link; --------------------- -- File_Time_Stamp -- --------------------- function File_Time_Stamp (Exec : access Server_Record'Class; File : FS_String) return Ada.Calendar.Time is Query_Args : GNAT.OS_Lib.Argument_List := (new String'("reg"), new String'("query"), new String'("""HKCU\Control Panel\International"""), new String'("/v"), new String'("sShortDate")); Query_Regexp : constant Pattern_Matcher := Compile ("REG_SZ\s+([dMy]+)[^dMy]*([dMy]+)[^dMy]*([dMy]+)$"); Regexp : constant Pattern_Matcher := Compile ("(\d+)[^\d](\d+)[^\d](\d+)\s+(\d\d:\d\d)\s+"); Args : GNAT.OS_Lib.Argument_List := (new String'("dir"), new String'("/tw"), new String'("/4"), new String'("""" & String (File) & """"), new String'("2>"), new String'("/dev/null")); Status : Boolean; Matched : Match_Array (0 .. 4); Output : String_Access; Year : Natural; Month : Natural; Day : Natural; Hour : Natural; Minute : Natural; Y_Pos : Natural := 0; M_Pos : Natural := 0; D_Pos : Natural := 0; use Ada.Calendar; begin -- We need to first query the date format -- (dd/MM/ yyyy, yyyy-mm-dd, mm-dd-yyyy ?) Exec.Execute_Remotely (Query_Args, Output, Status); Free (Query_Args); if Status then Match (Query_Regexp, Output.all, Matched); if Matched (0) /= No_Match then for J in 1 .. 3 loop if Output (Matched (J).First) = 'd' then D_Pos := J; elsif Output (Matched (J).First) = 'M' then M_Pos := J; elsif Output (Matched (J).First) = 'y' then Y_Pos := J; end if; end loop; end if; end if; Free (Output); if D_Pos = 0 or else M_Pos = 0 or else Y_Pos = 0 then return GNATCOLL.Utils.No_Time; end if; Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status then Match (Regexp, Output.all, Matched); if Matched (0) = No_Match then return GNATCOLL.Utils.No_Time; end if; Year := Natural'Value (Output (Matched (Y_Pos).First .. Matched (Y_Pos).Last)); Month := Natural'Value (Output (Matched (M_Pos).First .. Matched (M_Pos).Last)); Day := Natural'Value (Output (Matched (D_Pos).First .. Matched (D_Pos).Last)); Hour := Natural'Value (Output (Matched (4).First .. Matched (4).First + 1)); Minute := Natural'Value (Output (Matched (4).First + 3 .. Matched (4).First + 4)); Free (Output); return Ada.Calendar.Time_Of (Year, Month, Day, Seconds => 60.0 * 60.0 * Day_Duration (Hour) + 60.0 * Day_Duration (Minute)); end if; Free (Output); return GNATCOLL.Utils.No_Time; exception when others => return GNATCOLL.Utils.No_Time; end File_Time_Stamp; ----------------- -- Is_Readable -- ----------------- function Is_Readable (Exec : access Server_Record'Class; File : FS_String) return Boolean is pragma Unreferenced (Exec, File); begin -- A file cannot be unreadable on Windows, unless you use ACL (which we -- don't here) return True; end Is_Readable; ----------------- -- Is_Writable -- ----------------- function Is_Writable (Exec : access Server_Record'Class; File : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("dir"), new String'("/a-r"), new String'("""" & String (File) & """")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Is_Writable; ------------------ -- Set_Writable -- ------------------ procedure Set_Writable (Exec : access Server_Record'Class; File : FS_String; State : Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("attrib"), new String'("-r"), new String'("""" & String (File) & """"), new String'("2>&1")); Unused_Status : Boolean; begin if not State then Args (2) (Args (2)'First) := '+'; end if; Exec.Execute_Remotely (Args, Unused_Status); Free (Args); end Set_Writable; ------------------ -- Set_Readable -- ------------------ procedure Set_Readable (Exec : access Server_Record'Class; File : FS_String; State : Boolean) is pragma Unreferenced (Exec, File, State); begin -- A file cannot be unreadable on Windows, unless you use ACL (which we -- don't here) return; end Set_Readable; ------------ -- Rename -- ------------ procedure Rename (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("ren"), new String'("""" & String (From) & """"), new String'("""" & String (Dest) & """"), new String'("2>&1")); begin Exec.Execute_Remotely (Args, Success); Free (Args); end Rename; ---------- -- Copy -- ---------- procedure Copy (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("copy"), new String'("""" & String (From) & """"), new String'("""" & String (Dest) & """"), new String'("2>&1")); begin Exec.Execute_Remotely (Args, Success); Free (Args); end Copy; ------------ -- Delete -- ------------ procedure Delete (Exec : access Server_Record'Class; File : FS_String; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("erase"), new String'("/f"), new String'("""" & String (File) & """"), new String'("2>&1")); begin Exec.Execute_Remotely (Args, Success); Free (Args); end Delete; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (Exec : access Server_Record'Class; File : FS_String) return GNAT.Strings.String_Access is Args : GNAT.OS_Lib.Argument_List := (new String'("type"), new String'("""" & String (File) & """")); Status : Boolean; Output : String_Access; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); return Output; end Read_Whole_File; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (Exec : access Server_Record'Class; File : FS_String) return GNATCOLL.Strings.XString is Args : GNAT.OS_Lib.Argument_List := (new String'("type"), new String'("""" & String (File) & """")); Status : Boolean; Output : String_Access; Result : XString; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); Result.Set (Output.all); -- Needs a copy of the string Free (Output); return Result; end Read_Whole_File; ---------------- -- Write_File -- ---------------- function Write_File (Exec : access Server_Record'Class; File : FS_String; Content : String) return Boolean is Success : Boolean := True; procedure Internal_Write (S : String; First_Line : Boolean); -- Write a single line procedure Internal_Write (S : String; First_Line : Boolean) is Args : GNAT.OS_Lib.Argument_List := (new String'("echo"), new String'(S), new String'(">>"), new String'("""" & String (File) & """")); begin if First_Line then Args (3).all := "> "; end if; Exec.Execute_Remotely (Args, Success); Free (Args); end Internal_Write; Last : Natural := Content'First; Idx : Natural := Content'First; begin while Idx <= Content'Last loop if Content (Idx) = ASCII.CR and then Content (Idx + 1) = ASCII.LF then Internal_Write (Content (Last .. Idx - 1), Last = Content'First); exit when not Success; Last := Idx + 2; Idx := Idx + 2; elsif Content (Idx) = ASCII.LF then Internal_Write (Content (Last .. Idx - 1), Last = Content'First); exit when not Success; Last := Idx + 1; Idx := Idx + 1; elsif Idx = Content'Last then Internal_Write (Content (Last .. Idx), Last = Content'First); exit when not Success; else Idx := Idx + 1; end if; end loop; return Success; end Write_File; ---------------- -- Change_Dir -- ---------------- function Change_Dir (Exec : access Server_Record'Class; Dir : FS_String) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("cd"), new String'("""" & String (Dir) & """")); Status : Boolean; begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Change_Dir; -------------- -- Read_Dir -- -------------- function Read_Dir (Exec : access Server_Record'Class; Dir : FS_String; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List is function Create_Args return GNAT.OS_Lib.Argument_List; -- Return dir arguments following the Dirs_Only and Files_Only arguments ----------------- -- Create_Args -- ----------------- function Create_Args return GNAT.OS_Lib.Argument_List is begin if Dirs_Only then return (new String'("dir"), new String'("/ad"), new String'("/b"), new String'(String (Dir)), new String'("2>&1")); elsif Files_Only then return (new String'("dir"), new String'("/a-d"), new String'("/b"), new String'(String (Dir)), new String'("2>&1")); else return (new String'("dir"), new String'("/b"), new String'(String (Dir)), new String'("2>&1")); end if; end Create_Args; Args : GNAT.OS_Lib.Argument_List := Create_Args; Status : Boolean; Output : String_Access; Regexp : constant Pattern_Matcher := Compile ("^(.+)$", Multiple_Lines); Matched : Match_Array (0 .. 1); Index : Natural; Nb_Files : Natural; begin Exec.Execute_Remotely (Args, Output, Status); Free (Args); if Status then Index := Output'First; Nb_Files := 0; while Index <= Output'Last loop Match (Regexp, Output.all, Matched, Index); exit when Matched (0) = No_Match; Index := Matched (1).Last + 1; if Output (Matched (1).First .. Matched (1).Last) /= "." and then Output (Matched (1).First .. Matched (1).Last) /= ".." then Nb_Files := Nb_Files + 1; end if; end loop; declare List : String_List (1 .. Nb_Files); File_Idx : Natural; begin Index := Output'First; File_Idx := List'First; while Index /= Output'Last loop Match (Regexp, Output.all, Matched, Index); exit when Matched (0) = No_Match; Index := Matched (1).Last + 1; if Output (Matched (1).First .. Matched (1).Last) /= "." and then Output (Matched (1).First .. Matched (1).Last) /= ".." then List (File_Idx) := new String' (Output (Matched (1).First .. Matched (1).Last)); File_Idx := File_Idx + 1; end if; end loop; return List; end; end if; return (1 .. 0 => null); end Read_Dir; -------------- -- Make_Dir -- -------------- function Make_Dir (Exec : access Server_Record'Class; Dir : FS_String; Recursive : Boolean) return Boolean is Args : GNAT.OS_Lib.Argument_List := (new String'("mkdir"), new String'("""" & String (Dir) & """"), new String'("2>&1")); Status : Boolean; pragma Unreferenced (Recursive); -- There is no non-recursive mkdir on Windows begin Exec.Execute_Remotely (Args, Status); Free (Args); return Status; end Make_Dir; -------------- -- Copy_Dir -- -------------- procedure Copy_Dir (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean) is begin -- Generated stub: replace with real body! raise Program_Error; end Copy_Dir; ---------------- -- Delete_Dir -- ---------------- procedure Delete_Dir (Exec : access Server_Record'Class; Dir : FS_String; Recursive : Boolean; Success : out Boolean) is Args : GNAT.OS_Lib.Argument_List := (1 => new String'("rmdir"), 2 => new String'("/q"), 3 => new String'("""" & String (Dir) & """"), 4 => new String'("2>&1")); begin if Recursive then Free (Args (2)); Args (2) := new String'("/q/s"); end if; Exec.Execute_Remotely (Args, Success); Free (Args); end Delete_Dir; end GNATCOLL.IO.Remote.Windows; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-remote-windows.ads000066400000000000000000000116371425465243200247770ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2006-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.Strings; use GNAT.Strings; with GNATCOLL.Remote; use GNATCOLL.Remote; package GNATCOLL.IO.Remote.Windows is -- The following methods are equivalent to their native counterparts. -- See GNATCOLL.IO for documentation. function Current_Dir (Exec : access Server_Record'Class) return FS_String; function Home_Dir (Exec : access Server_Record'Class) return FS_String; function Tmp_Dir (Exec : access Server_Record'Class) return FS_String; function Get_Logical_Drives (Exec : access Server_Record'Class) return String_List_Access; function Locate_On_Path (Exec : access Server_Record'Class; Base : FS_String) return FS_String; function Is_Regular_File (Exec : access Server_Record'Class; File : FS_String) return Boolean; function Size (Exec : access Server_Record'Class; File : FS_String) return Long_Integer; function Is_Directory (Exec : access Server_Record'Class; File : FS_String) return Boolean; function Is_Symbolic_Link (Exec : access Server_Record'Class; File : FS_String) return Boolean; function File_Time_Stamp (Exec : access Server_Record'Class; File : FS_String) return Ada.Calendar.Time; function Is_Writable (Exec : access Server_Record'Class; File : FS_String) return Boolean; procedure Set_Writable (Exec : access Server_Record'Class; File : FS_String; State : Boolean); function Is_Readable (Exec : access Server_Record'Class; File : FS_String) return Boolean; procedure Set_Readable (Exec : access Server_Record'Class; File : FS_String; State : Boolean); procedure Rename (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean); procedure Copy (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean); procedure Delete (Exec : access Server_Record'Class; File : FS_String; Success : out Boolean); function Read_Whole_File (Exec : access Server_Record'Class; File : FS_String) return GNAT.Strings.String_Access; function Read_Whole_File (Exec : access Server_Record'Class; File : FS_String) return GNATCOLL.Strings.XString; function Write_File (Exec : access Server_Record'Class; File : FS_String; Content : String) return Boolean; function Change_Dir (Exec : access Server_Record'Class; Dir : FS_String) return Boolean; function Read_Dir (Exec : access Server_Record'Class; Dir : FS_String; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List; function Make_Dir (Exec : access Server_Record'Class; Dir : FS_String; Recursive : Boolean) return Boolean; procedure Copy_Dir (Exec : access Server_Record'Class; From : FS_String; Dest : FS_String; Success : out Boolean); procedure Delete_Dir (Exec : access Server_Record'Class; Dir : FS_String; Recursive : Boolean; Success : out Boolean); end GNATCOLL.IO.Remote.Windows; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-remote.adb000066400000000000000000000731701425465243200232660ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.Directory_Operations; with GNAT.Strings; use GNAT.Strings; with GNATCOLL.IO.Native; with GNATCOLL.IO.Remote.Unix; with GNATCOLL.IO.Remote.Windows; with GNATCOLL.Mmap; with GNATCOLL.Path; use GNATCOLL.Path; with GNATCOLL.Remote; use GNATCOLL.Remote; with GNATCOLL.Remote.Db; use GNATCOLL.Remote.Db; package body GNATCOLL.IO.Remote is procedure Internal_Initialize (File : not null access Remote_File_Record'Class; Host : String; Path : FS_String); -- Initialize internal fields according to the file's host ------------------------- -- Internal_Initialize -- ------------------------- procedure Internal_Initialize (File : not null access Remote_File_Record'Class; Host : String; Path : FS_String) is Server : constant Server_Access := Get_Server (Host); Last : Natural := Path'Last; begin -- Regexps might return file strings with a trailing CR or LF. Let's -- remove those before creating the File record. while Path (Last) = ASCII.CR or Path (Last) = ASCII.LF loop Last := Last - 1; end loop; File.Server := Server; if File.Tmp_Norm then File.Full := new FS_String' (GNATCOLL.Path.Normalize (Server.Shell_FS, From_Unix (Server.Shell_FS, Path (Path'First .. Last)))); else File.Full := new FS_String' (From_Unix (Server.Shell_FS, Path (Path'First .. Last))); end if; File.Normalized_And_Resolved := null; end Internal_Initialize; ------------------------ -- Ensure_Initialized -- ------------------------ procedure Ensure_Initialized (File : not null access Remote_File_Record'Class) is begin if File.Server /= null then return; elsif not Is_Configured (File.Tmp_Host.all) then raise Remote_Config_Error with "File needs server " & File.Tmp_Host.all & " which is not configured"; end if; Internal_Initialize (File, File.Tmp_Host.all, File.Tmp_Path.all); Free (File.Tmp_Host); Free (File.Tmp_Path); end Ensure_Initialized; ------------ -- Create -- ------------ function Create (Host : String; Path : FS_String; Normalize : Boolean) return File_Access is Ret : Remote_File_Access; begin Ret := new Remote_File_Record' (Ref_Count => 1, Tmp_Host => null, Tmp_Path => null, Tmp_Norm => Normalize, Tmp_Name => (others => ' '), Server => null, Full => null, Normalized => null, Normalized_And_Resolved => null, Kind => Unknown); if not Is_Configured (Host) then -- Delayed initialization Ret.Tmp_Host := new String'(Host); Ret.Tmp_Path := new FS_String'(Path); else Internal_Initialize (Ret, Host, Path); end if; return File_Access (Ret); end Create; ----------------- -- Current_Dir -- ----------------- function Current_Dir (Host : String) return File_Access is Server : Server_Access; begin if not Is_Configured (Host) then raise Remote_Config_Error with "Invalid FS for host " & Host; else Server := Get_Server (Host); end if; case Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return Create (Host, GNATCOLL.IO.Remote.Unix.Current_Dir (Server), False); when FS_Windows => return Create (Host, GNATCOLL.IO.Remote.Windows.Current_Dir (Server), False); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Host; end case; end Current_Dir; -------------- -- Home_Dir -- -------------- function Home_Dir (Host : String) return File_Access is Server : Server_Access; begin if not Is_Configured (Host) then raise Remote_Config_Error with "Invalid FS for host " & Host; else Server := Get_Server (Host); end if; case Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return Create (Host, GNATCOLL.IO.Remote.Unix.Home_Dir (Server), False); when FS_Windows => return Create (Host, GNATCOLL.IO.Remote.Windows.Home_Dir (Server), False); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Host; end case; end Home_Dir; ----------------------- -- Get_Tmp_Directory -- ----------------------- function Get_Tmp_Directory (Host : String) return File_Access is Server : Server_Access; begin if not Is_Configured (Host) then raise Remote_Config_Error with "Invalid FS for host " & Host; else Server := Get_Server (Host); end if; case Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return Create (Host, GNATCOLL.IO.Remote.Unix.Tmp_Dir (Server), False); when FS_Windows => return Create (Host, GNATCOLL.IO.Remote.Windows.Tmp_Dir (Server), False); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Host; end case; end Get_Tmp_Directory; -------------------- -- Locate_On_Path -- -------------------- function Locate_On_Path (Host : String; Base : FS_String) return File_Access is Server : Server_Access; begin if not Is_Configured (Host) then raise Remote_Config_Error with "Invalid FS for host " & Host; else Server := Get_Server (Host); end if; if GNATCOLL.Path.Is_Absolute_Path (Server.Shell_FS, Base) then return Create (Host, Base, False); end if; case Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => declare Ret : constant FS_String := GNATCOLL.IO.Remote.Unix.Locate_On_Path (Server, Base); begin if Ret = "" then return null; else return Create (Host, Ret, False); end if; end; when FS_Windows => declare Ret : constant FS_String := GNATCOLL.IO.Remote.Windows.Locate_On_Path (Server, Base); begin if Ret = "" then return null; else return Create (Host, Ret, False); end if; end; when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Host; end case; end Locate_On_Path; ------------------------ -- Get_Logical_Drives -- ------------------------ function Get_Logical_Drives (Host : String) return File_Array is Server : Server_Access; List : GNAT.Strings.String_List_Access; begin if not Is_Configured (Host) then raise Remote_Config_Error with "Invalid FS for host " & Host; else Server := Get_Server (Host); end if; case Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => List := GNATCOLL.IO.Remote.Unix.Get_Logical_Drives (Server); when FS_Windows => List := GNATCOLL.IO.Remote.Windows.Get_Logical_Drives (Server); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Host; end case; if List = null then return (1 .. 0 => <>); end if; declare Ret : File_Array (1 .. List'Length); begin for J in Ret'Range loop Ret (J) := Create (Host, FS_String (List (List'First + J - Ret'First).all), False); end loop; GNAT.Strings.Free (List); return Ret; end; end Get_Logical_Drives; -------------- -- Get_Host -- -------------- function Get_Host (File : not null access Remote_File_Record) return String is begin if File.Server = null then if not Is_Configured (File.Tmp_Host.all) then return File.Tmp_Host.all; else Internal_Initialize (File, File.Tmp_Host.all, File.Tmp_Path.all); Free (File.Tmp_Host); Free (File.Tmp_Path); return File.Server.Nickname; end if; else return File.Server.Nickname; end if; end Get_Host; ------------------------ -- Dispatching_Create -- ------------------------ function Dispatching_Create (Ref : not null access Remote_File_Record; Full_Path : FS_String) return File_Access is begin return Create (Ref.Get_Host, Full_Path, False); end Dispatching_Create; ------------- -- To_UTF8 -- ------------- function To_UTF8 (Ref : not null access Remote_File_Record; Path : FS_String) return String is pragma Unreferenced (Ref); begin return Codec.To_UTF8 (Path); end To_UTF8; --------------- -- From_UTF8 -- --------------- function From_UTF8 (Ref : not null access Remote_File_Record; Path : String) return FS_String is pragma Unreferenced (Ref); begin return Codec.From_UTF8 (Path); end From_UTF8; -------------- -- Is_Local -- -------------- function Is_Local (File : Remote_File_Record) return Boolean is pragma Unreferenced (File); begin return False; end Is_Local; ------------ -- Get_FS -- ------------ function Get_FS (File : not null access Remote_File_Record) return FS_Type is begin Ensure_Initialized (File); return File.Server.Shell_FS; end Get_FS; ---------------------- -- Resolve_Symlinks -- ---------------------- procedure Resolve_Symlinks (File : not null access Remote_File_Record) is begin Ensure_Initialized (File); -- ??? Should we do something more here (e.g. try to actually resolve ?) if File.Normalized_And_Resolved = null then if File.Normalized = null then File.Normalized := new FS_String' (GNATCOLL.Path.Normalize (Get_FS (File), File.Full.all)); end if; File.Normalized_And_Resolved := File.Normalized; end if; end Resolve_Symlinks; --------------------- -- Is_Regular_File -- --------------------- function Is_Regular_File (File : not null access Remote_File_Record) return Boolean is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Is_Regular_File (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Is_Regular_File (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Is_Regular_File; ---------- -- Size -- ---------- overriding function Size (File : not null access Remote_File_Record) return Long_Integer is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Size (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Size (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Size; ------------------ -- Is_Directory -- ------------------ function Is_Directory (File : not null access Remote_File_Record) return Boolean is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Is_Directory (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Is_Directory (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Is_Directory; ---------------------- -- Is_Symbolic_Link -- ---------------------- function Is_Symbolic_Link (File : not null access Remote_File_Record) return Boolean is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Is_Symbolic_Link (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Is_Symbolic_Link (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Is_Symbolic_Link; --------------------- -- File_Time_Stamp -- --------------------- function File_Time_Stamp (File : not null access Remote_File_Record) return Ada.Calendar.Time is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.File_Time_Stamp (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.File_Time_Stamp (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end File_Time_Stamp; ----------------- -- Is_Readable -- ----------------- overriding function Is_Readable (File : not null access Remote_File_Record) return Boolean is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Is_Readable (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Is_Readable (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Is_Readable; ----------------- -- Is_Writable -- ----------------- function Is_Writable (File : not null access Remote_File_Record) return Boolean is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Is_Writable (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Is_Writable (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Is_Writable; ------------------ -- Set_Writable -- ------------------ procedure Set_Writable (File : not null access Remote_File_Record; State : Boolean) is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => GNATCOLL.IO.Remote.Unix.Set_Writable (File.Server, File.Full.all, State); when FS_Windows => GNATCOLL.IO.Remote.Windows.Set_Writable (File.Server, File.Full.all, State); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Set_Writable; ------------------ -- Set_Readable -- ------------------ procedure Set_Readable (File : not null access Remote_File_Record; State : Boolean) is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => GNATCOLL.IO.Remote.Unix.Set_Readable (File.Server, File.Full.all, State); when FS_Windows => GNATCOLL.IO.Remote.Windows.Set_Readable (File.Server, File.Full.all, State); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Set_Readable; ------------ -- Rename -- ------------ procedure Rename (From : not null access Remote_File_Record; Dest : not null access Remote_File_Record; Success : out Boolean) is begin Ensure_Initialized (From); Ensure_Initialized (Dest); if From.Get_Host /= Dest.Get_Host then raise Remote_Config_Error with "cannot rename a file to another host"; end if; case From.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => GNATCOLL.IO.Remote.Unix.Rename (From.Server, From.Full.all, Dest.Full.all, Success); when FS_Windows => GNATCOLL.IO.Remote.Windows.Rename (From.Server, From.Full.all, Dest.Full.all, Success); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & From.Get_Host; end case; end Rename; ---------- -- Copy -- ---------- procedure Copy (From : not null access Remote_File_Record; Dest : FS_String; Success : out Boolean) is begin Ensure_Initialized (From); case From.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => GNATCOLL.IO.Remote.Unix.Copy (From.Server, From.Full.all, Dest, Success); when FS_Windows => GNATCOLL.IO.Remote.Windows.Copy (From.Server, From.Full.all, Dest, Success); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & From.Get_Host; end case; end Copy; ------------ -- Delete -- ------------ procedure Delete (File : not null access Remote_File_Record; Success : out Boolean) is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => GNATCOLL.IO.Remote.Unix.Delete (File.Server, File.Full.all, Success); when FS_Windows => GNATCOLL.IO.Remote.Windows.Delete (File.Server, File.Full.all, Success); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Delete; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (File : not null access Remote_File_Record) return GNAT.Strings.String_Access is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Read_Whole_File (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Read_Whole_File (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Read_Whole_File; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (File : not null access Remote_File_Record) return GNATCOLL.Strings.XString is begin Ensure_Initialized (File); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Read_Whole_File (File.Server, File.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Read_Whole_File (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; end Read_Whole_File; ---------------- -- Open_Write -- ---------------- procedure Open_Write (File : not null access Remote_File_Record; Append : Boolean := False; FD : out GNAT.OS_Lib.File_Descriptor) is Tmp_Dir : File_Access := GNATCOLL.IO.Native.Get_Tmp_Directory; Cur_Dir : File_Access := GNATCOLL.IO.Native.Current_Dir; Tmp : constant FS_String := GNATCOLL.Path.Ensure_Directory (Tmp_Dir.Get_FS, Tmp_Dir.Full.all); Cur : constant FS_String := GNATCOLL.Path.Ensure_Directory (Cur_Dir.Get_FS, Cur_Dir.Full.all); Content : GNAT.Strings.String_Access; Dead : Boolean; Written : Integer; pragma Unreferenced (Dead, Written); begin Ensure_Initialized (File); Unref (Tmp_Dir); Unref (Cur_Dir); GNAT.Directory_Operations.Change_Dir (String (Tmp)); GNAT.OS_Lib.Create_Temp_File (FD, File.Tmp_Name); GNAT.Directory_Operations.Change_Dir (String (Cur)); if Append then case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => Content := GNATCOLL.IO.Remote.Unix.Read_Whole_File (File.Server, File.Full.all); when FS_Windows => Content := GNATCOLL.IO.Remote.Windows.Read_Whole_File (File.Server, File.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; Written := GNAT.OS_Lib.Write (FD, Content.all'Address, Content'Length); GNAT.Strings.Free (Content); end if; end Open_Write; ----------- -- Close -- ----------- procedure Close (File : not null access Remote_File_Record; FD : GNAT.OS_Lib.File_Descriptor; Success : out Boolean) is Content : GNAT.Strings.String_Access; Tmp_Dir : File_Access := GNATCOLL.IO.Native.Get_Tmp_Directory; Tmp : constant FS_String := GNATCOLL.Path.Ensure_Directory (Tmp_Dir.Get_FS, Tmp_Dir.Full.all); Unused : Boolean; begin Unref (Tmp_Dir); Ensure_Initialized (File); GNAT.OS_Lib.Close (FD); Content := GNATCOLL.Mmap.Read_Whole_File (String (Tmp) & File.Tmp_Name, Empty_If_Not_Found => True); case File.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => Success := GNATCOLL.IO.Remote.Unix.Write_File (File.Server, File.Full.all, Content.all); when FS_Windows => Success := GNATCOLL.IO.Remote.Windows.Write_File (File.Server, File.Full.all, Content.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & File.Get_Host; end case; GNAT.OS_Lib.Delete_File (String (Tmp) & File.Tmp_Name, Unused); end Close; ---------------- -- Change_Dir -- ---------------- function Change_Dir (Dir : not null access Remote_File_Record) return Boolean is begin Ensure_Initialized (Dir); case Dir.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Change_Dir (Dir.Server, Dir.Full.all); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Change_Dir (Dir.Server, Dir.Full.all); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Dir.Get_Host; end case; end Change_Dir; -------------- -- Read_Dir -- -------------- function Read_Dir (Dir : not null access Remote_File_Record; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List is begin Ensure_Initialized (Dir); case Dir.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Read_Dir (Dir.Server, Dir.Full.all, Dirs_Only, Files_Only); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Read_Dir (Dir.Server, Dir.Full.all, Dirs_Only, Files_Only); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Dir.Get_Host; end case; end Read_Dir; -------------- -- Make_Dir -- -------------- function Make_Dir (Dir : not null access Remote_File_Record; Recursive : Boolean) return Boolean is begin Ensure_Initialized (Dir); case Dir.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => return GNATCOLL.IO.Remote.Unix.Make_Dir (Dir.Server, Dir.Full.all, Recursive); when FS_Windows => return GNATCOLL.IO.Remote.Windows.Make_Dir (Dir.Server, Dir.Full.all, Recursive); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Dir.Get_Host; end case; end Make_Dir; ---------------- -- Remove_Dir -- ---------------- procedure Remove_Dir (Dir : not null access Remote_File_Record; Recursive : Boolean; Success : out Boolean) is begin Ensure_Initialized (Dir); case Dir.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => GNATCOLL.IO.Remote.Unix.Delete_Dir (Dir.Server, Dir.Full.all, Recursive, Success); when FS_Windows => GNATCOLL.IO.Remote.Windows.Delete_Dir (Dir.Server, Dir.Full.all, Recursive, Success); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & Dir.Get_Host; end case; end Remove_Dir; -------------- -- Copy_Dir -- -------------- procedure Copy_Dir (From : not null access Remote_File_Record; Dest : FS_String; Success : out Boolean) is begin Ensure_Initialized (From); case From.Server.Shell_FS is when FS_Unix | FS_Unix_Case_Insensitive => GNATCOLL.IO.Remote.Unix.Copy_Dir (From.Server, From.Full.all, Dest, Success); when FS_Windows => GNATCOLL.IO.Remote.Windows.Copy_Dir (From.Server, From.Full.all, Dest, Success); when FS_Unknown => raise Remote_Config_Error with "Invalid FS for host " & From.Get_Host; end case; end Copy_Dir; --------------------------- -- Copy_File_Permissions -- --------------------------- overriding procedure Copy_File_Permissions (From, To : not null access Remote_File_Record; Success : out Boolean) is pragma Unreferenced (From, To); begin Success := False; end Copy_File_Permissions; ----------- -- Codec -- ----------- package body Codec is ------------- -- To_UTF8 -- ------------- function To_UTF8 (Path : FS_String) return String is begin -- ??? What if the Transport uses a specific charset ? return String (Path); end To_UTF8; --------------- -- From_UTF8 -- --------------- function From_UTF8 (Path : String) return FS_String is begin -- ??? What if the Transport uses a specific charset ? return FS_String (Path); end From_UTF8; end Codec; end GNATCOLL.IO.Remote; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io-remote.ads000066400000000000000000000157661425465243200233160ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Remote; package GNATCOLL.IO.Remote is Remote_Config_Error : exception; type Remote_File_Record is new File_Record with private; type Remote_File_Access is access all Remote_File_Record'Class; function Create (Host : String; Path : FS_String; Normalize : Boolean) return File_Access; function Current_Dir (Host : String) return File_Access; function Home_Dir (Host : String) return File_Access; function Get_Tmp_Directory (Host : String) return File_Access; function Get_Logical_Drives (Host : String) return File_Array; function Locate_On_Path (Host : String; Base : FS_String) return File_Access; procedure Ensure_Initialized (File : not null access Remote_File_Record'Class); -- Same as above, raising an exception if the file cannot be initialized. function Get_Host (File : not null access Remote_File_Record) return String; ---------------------------- -- Overridden from parent -- ---------------------------- overriding function Dispatching_Create (Ref : not null access Remote_File_Record; Full_Path : FS_String) return File_Access; overriding function To_UTF8 (Ref : not null access Remote_File_Record; Path : FS_String) return String; overriding function From_UTF8 (Ref : not null access Remote_File_Record; Path : String) return FS_String; overriding function Is_Local (File : Remote_File_Record) return Boolean; overriding function Get_FS (File : not null access Remote_File_Record) return FS_Type; overriding procedure Resolve_Symlinks (File : not null access Remote_File_Record); overriding function Is_Regular_File (File : not null access Remote_File_Record) return Boolean; overriding function Size (File : not null access Remote_File_Record) return Long_Integer; overriding function Is_Directory (File : not null access Remote_File_Record) return Boolean; overriding function Is_Symbolic_Link (File : not null access Remote_File_Record) return Boolean; overriding function File_Time_Stamp (File : not null access Remote_File_Record) return Ada.Calendar.Time; overriding function Is_Writable (File : not null access Remote_File_Record) return Boolean; overriding procedure Set_Writable (File : not null access Remote_File_Record; State : Boolean); overriding function Is_Readable (File : not null access Remote_File_Record) return Boolean; overriding procedure Set_Readable (File : not null access Remote_File_Record; State : Boolean); overriding procedure Rename (From : not null access Remote_File_Record; Dest : not null access Remote_File_Record; Success : out Boolean); overriding procedure Copy (From : not null access Remote_File_Record; Dest : FS_String; Success : out Boolean); overriding procedure Delete (File : not null access Remote_File_Record; Success : out Boolean); overriding function Read_Whole_File (File : not null access Remote_File_Record) return GNAT.Strings.String_Access; overriding function Read_Whole_File (File : not null access Remote_File_Record) return GNATCOLL.Strings.XString; overriding procedure Open_Write (File : not null access Remote_File_Record; Append : Boolean := False; FD : out GNAT.OS_Lib.File_Descriptor); overriding procedure Close (File : not null access Remote_File_Record; FD : GNAT.OS_Lib.File_Descriptor; Success : out Boolean); overriding function Change_Dir (Dir : not null access Remote_File_Record) return Boolean; overriding function Read_Dir (Dir : not null access Remote_File_Record; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List; overriding function Make_Dir (Dir : not null access Remote_File_Record; Recursive : Boolean) return Boolean; overriding procedure Remove_Dir (Dir : not null access Remote_File_Record; Recursive : Boolean; Success : out Boolean); overriding procedure Copy_Dir (From : not null access Remote_File_Record; Dest : FS_String; Success : out Boolean); overriding procedure Copy_File_Permissions (From, To : not null access Remote_File_Record; Success : out Boolean); -- See parent for documentation package Codec is function To_UTF8 (Path : FS_String) return String; function From_UTF8 (Path : String) return FS_String; end Codec; -- Codec to translate a path to/from utf-8. private type Remote_File_Record is new File_Record with record Tmp_Host : GNAT.Strings.String_Access; -- Host. Saved in case the below server is not resolved immediately. Tmp_Path : FS_String_Access; -- Path used at creation, saved in case the below server is not resolved -- immediately. Tmp_Norm : Boolean; -- Value used at creation to determine if Tmp_Path should be normalized Server : GNATCOLL.Remote.Server_Access; -- The server on which the file commands are executed. Tmp_Name : GNAT.OS_Lib.Temp_File_Name; -- Saved name for the temporary file used during Write operations. end record; end GNATCOLL.IO.Remote; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io.adb000066400000000000000000000052271425465243200217730ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Unchecked_Deallocation; package body GNATCOLL.IO is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (File_Record'Class, File_Access); --------- -- Ref -- --------- procedure Ref (File : File_Access) is begin File.Ref_Count := File.Ref_Count + 1; end Ref; ----------- -- Unref -- ----------- procedure Unref (File : in out File_Access) is begin if File.Ref_Count > 0 then File.Ref_Count := File.Ref_Count - 1; if File.Ref_Count = 0 then Destroy (File.all); Unchecked_Free (File); end if; end if; end Unref; ------------- -- Destroy -- ------------- procedure Destroy (File : in out File_Record) is begin Free (File.Full); if File.Normalized_And_Resolved /= File.Normalized then Free (File.Normalized_And_Resolved); end if; Free (File.Normalized); end Destroy; end GNATCOLL.IO; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-io.ads000066400000000000000000000226631425465243200220170ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Calendar; with GNAT.OS_Lib; with GNAT.Strings; with GNATCOLL.Strings; use GNATCOLL.Strings; with GNATCOLL.VFS_Types; use GNATCOLL.VFS_Types; private package GNATCOLL.IO is type Item_Type is (Unknown, -- File is not determined File, -- Regular file Directory -- Directory ); -- Item_Type is used to cache the calls to Is_Regular_File or Is_Directory -- that can be pretty time consuming, and that are performed pretty often. type File_Record is abstract tagged record Ref_Count : Natural := 0; Full : FS_String_Access; -- The file's full path Normalized : FS_String_Access; -- The file's normalized form ('..' and '.' directories removed) Normalized_And_Resolved : FS_String_Access; -- The normalized form with resolved symlinks. -- This points to the same value as Normalized if these have the same -- value. Kind : Item_Type := Unknown; -- The kind of file represented by this object end record; type File_Access is access all File_Record'Class; type File_Array is array (Natural range <>) of File_Access; procedure Ref (File : File_Access); procedure Unref (File : in out File_Access); procedure Destroy (File : in out File_Record); function Dispatching_Create (Ref : not null access File_Record; Full_Path : FS_String) return File_Access is abstract; -- Create a new file using the same tagged type is Ref function To_UTF8 (Ref : not null access File_Record; Path : FS_String) return String is abstract; function From_UTF8 (Ref : not null access File_Record; Path : String) return FS_String is abstract; -- Translate a path to/from UTF8 encoded strings, according to the -- Filesystem's charset. function Is_Local (File : File_Record) return Boolean is abstract; -- Tell if IO denotes a local file or directory function Get_FS (File : not null access File_Record) return FS_Type is abstract; -- Return the kind of FS the file is on procedure Resolve_Symlinks (File : not null access File_Record) is abstract; -- Resolve all potential symlinks present in the IO path. -- Does nothing if this computation has already been done. ---------------------- -- Queries on files -- ---------------------- function Is_Regular_File (File : not null access File_Record) return Boolean is abstract; -- Return True if Local_Full_Name exists on the remote host function Size (File : not null access File_Record) return Long_Integer is abstract; -- Return the size of the file in bytes. function Is_Directory (File : not null access File_Record) return Boolean is abstract; -- Return True if File is in fact a directory function Is_Symbolic_Link (File : not null access File_Record) return Boolean is abstract; -- Whether the file is a symbolic link function File_Time_Stamp (File : not null access File_Record) return Ada.Calendar.Time is abstract; -- Return the timestamp for this file. -- If the Connection doesn't support this operation, or the file -- doesn't exists, it should return a date of No_Time, so as to force, when -- possible, a read operation from the caller. function Is_Writable (File : not null access File_Record) return Boolean is abstract; -- Return True if File is writable procedure Set_Writable (File : not null access File_Record; State : Boolean) is abstract; -- If Writable is True, make the file writable, otherwise make the file -- unwritable. function Is_Readable (File : not null access File_Record) return Boolean is abstract; -- Return True if File is readable procedure Set_Readable (File : not null access File_Record; State : Boolean) is abstract; -- If Readable is True, make the file readable, otherwise make the file -- unreadable. ---------------------- -- File operations -- ---------------------- procedure Rename (From : not null access File_Record; Dest : not null access File_Record; Success : out Boolean) is abstract; -- Rename From_Local_Name on the host to To_Local_Name on the same host. -- Return False if the renaming could not be performed. procedure Copy (From : not null access File_Record; Dest : FS_String; Success : out Boolean) is abstract; -- Copy a file into another one. -- To_Local_Name can be the name of the directory in which to copy the -- file, or the name of a file to be created. procedure Delete (File : not null access File_Record; Success : out Boolean) is abstract; -- Sends host a delete command for file function Read_Whole_File (File : not null access File_Record) return GNAT.Strings.String_Access is abstract; function Read_Whole_File (File : not null access File_Record) return GNATCOLL.Strings.XString is abstract; -- Return the contents of an entire file. -- If the file cannot be found, return null. -- The caller is responsible for freeing the returned memory. -- No special encoding/decoding for charsets is done on the file. procedure Open_Write (File : not null access File_Record; Append : Boolean := False; FD : out GNAT.OS_Lib.File_Descriptor) is abstract; -- Opens a file for writing. Return a file descriptor used to actually -- write. -- /!\ Do not call close directly on FD, but use the method below instead. procedure Close (File : not null access File_Record; FD : GNAT.OS_Lib.File_Descriptor; Success : out Boolean) is abstract; -- Closes FD and actually flushes the content to File if needed procedure Copy_File_Permissions (From, To : not null access File_Record; Success : out Boolean) is abstract; -- Copy all permissions (read, write, exec) from one file to the other, -- so that To ends up with the same permissions. This does not change -- the owner of the file. -------------------------- -- Directory management -- -------------------------- function Change_Dir (Dir : not null access File_Record) return Boolean is abstract; -- Change the current directory. -- This operation might not make sense for some remote file systems if a -- new connection is opened for every operation, since the context would -- be lost. However, it does make sense when the connection is permanent. function Read_Dir (Dir : not null access File_Record; Dirs_Only : Boolean := False; Files_Only : Boolean := False) return GNAT.Strings.String_List is abstract; -- Read the specified directory and returns a list of filenames -- (base names). If Dirs_Only is set, then the files returned are directory -- only. Same for Files_Only, concerning regular files. -- This does *not* return the two special directories "." and ".." function Make_Dir (Dir : not null access File_Record; Recursive : Boolean) return Boolean is abstract; -- Create a new directory on remote named Local_Dir_Name. -- Return the creation status. procedure Remove_Dir (Dir : not null access File_Record; Recursive : Boolean; Success : out Boolean) is abstract; -- Delete a directory. Recursive allow to remove included files or -- subdirectories. procedure Copy_Dir (From : not null access File_Record; Dest : FS_String; Success : out Boolean) is abstract; -- From_Local_Name is the name of a directory. All its files are copied -- into the directory To_Local_Name. The target directory is created if -- needed. end GNATCOLL.IO; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-json-utility.adb000066400000000000000000000213271425465243200240350ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2011-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ pragma Ada_2012; with Ada.Characters.Wide_Wide_Latin_1; use Ada.Characters.Wide_Wide_Latin_1; with Interfaces; use Interfaces; with GNAT.Encode_UTF8_String; with GNAT.Decode_UTF8_String; with GNATCOLL.Strings; package body GNATCOLL.JSON.Utility is use Ada.Strings.Unbounded; To_Hex : constant array (Unsigned_16 range 0 .. 15) of Character := "0123456789ABCDEF"; -------------------------------- -- Escape_Non_Print_Character -- -------------------------------- function Escape_Non_Print_Character (C : Wide_Wide_Character) return String is Code : constant Unsigned_32 := Wide_Wide_Character'Pos (C); Buf : String (1 .. 12); Last : Natural := Buf'First - 1; procedure Append_Escaped (Code : Unsigned_16); -------------------- -- Append_Escaped -- -------------------- procedure Append_Escaped (Code : Unsigned_16) is begin Last := Last + 6; Buf (Last - 5 .. Last - 4) := "\u"; Buf (Last - 3) := To_Hex ((Code / 16#1000#) mod 16#10#); Buf (Last - 2) := To_Hex ((Code / 16#100#) mod 16#10#); Buf (Last - 1) := To_Hex ((Code / 16#10#) mod 16#10#); Buf (Last) := To_Hex (Code mod 16#10#); end Append_Escaped; begin if Code <= 16#FFFF# then Append_Escaped (Unsigned_16 (Code)); else -- Represent character as surrogate pair Append_Escaped (16#D800# + Unsigned_16 ((Code - 16#1_0000#) / 16#400#)); Append_Escaped (16#DC00# + Unsigned_16 (Code mod 16#400#)); end if; return Buf (Buf'First .. Last); end Escape_Non_Print_Character; ------------------- -- Escape_String -- ------------------- function Escape_String (Text : UTF8_XString) return Unbounded_String is Str : GNATCOLL.Strings.Char_Array; Text_Length : Natural; Ret : Unbounded_String; Low : Natural; W_Chr : Wide_Wide_Character; begin Text.Get_String (Str, Text_Length); Append (Ret, '"'); Low := 1; while Low <= Text_Length loop -- UTF-8 sequence is maximum 4 characters long according to RFC3629 begin GNAT.Decode_UTF8_String.Decode_Wide_Wide_Character (String (Str (Low .. Natural'Min (Text_Length, Low + 3))), Low, W_Chr); exception when Constraint_Error => -- Skip the character even if it is invalid. Low := Low + 1; W_Chr := NUL; end; case W_Chr is when NUL => Append (Ret, "\u0000"); when '"' => Append (Ret, "\"""); when '\' => Append (Ret, "\\"); when BS => Append (Ret, "\b"); when FF => Append (Ret, "\f"); when LF => Append (Ret, "\n"); when CR => Append (Ret, "\r"); when HT => Append (Ret, "\t"); when others => if Wide_Wide_Character'Pos (W_Chr) < 32 then Append (Ret, Escape_Non_Print_Character (W_Chr)); elsif Wide_Wide_Character'Pos (W_Chr) >= 16#80# then Append (Ret, Escape_Non_Print_Character (W_Chr)); else Append (Ret, "" & Character'Val (Wide_Wide_Character'Pos (W_Chr))); end if; end case; end loop; Append (Ret, '"'); return Ret; end Escape_String; ---------------------- -- Un_Escape_String -- ---------------------- function Un_Escape_String (Text : String; Low : Natural; High : Natural) return UTF8_XString is First : Integer; Last : Integer; Unb : UTF8_XString; Idx : Natural; begin First := Low; Last := High; -- Trim blanks and double quotes while First <= High and then Text (First) = ' ' loop First := First + 1; end loop; if First <= High and then Text (First) = '"' then First := First + 1; end if; while Last >= Low and then Text (Last) = ' ' loop Last := Last - 1; end loop; if Last >= Low and then Text (Last) = '"' then Last := Last - 1; end if; Idx := First; while Idx <= Last loop if Text (Idx) = '\' then Idx := Idx + 1; if Idx > High then raise Invalid_JSON_Stream with "Unexpected escape character at end of line"; end if; -- See http://tools.ietf.org/html/rfc4627 for the list of -- characters that can be escaped. case Text (Idx) is when 'u' | 'U' => declare Lead : constant Unsigned_16 := Unsigned_16'Value ("16#" & Text (Idx + 1 .. Idx + 4) & "#"); Trail : Unsigned_16; Char : Wide_Wide_Character; begin Char := Wide_Wide_Character'Val (Lead); -- If character is high surrogate and next character is -- low surrogate then them represent one non-BMP -- character. if Lead in 16#D800# .. 16#DBFF# and then Text (Idx + 5) = '\' and then Text (Idx + 6) in 'u' | 'U' then Trail := Unsigned_16'Value ("16#" & Text (Idx + 7 .. Idx + 10) & '#'); Char := Wide_Wide_Character'Val (16#1_0000# + Unsigned_32 (Lead and 16#03FF#) * 16#0400# + Unsigned_32 (Trail and 16#03FF#)); Idx := Idx + 6; end if; Unb.Append (GNAT.Encode_UTF8_String.Encode_Wide_Wide_String ((1 => Char))); Idx := Idx + 4; end; when '"' => Unb.Append ('"'); when '/' => Unb.Append ('/'); when '\' => Unb.Append ('\'); when 'b' => Unb.Append (ASCII.BS); when 'f' => Unb.Append (ASCII.FF); when 'n' => Unb.Append (ASCII.LF); when 'r' => Unb.Append (ASCII.CR); when 't' => Unb.Append (ASCII.HT); when others => raise Invalid_JSON_Stream with "Unexpected escape sequence '\" & Text (Idx) & "'"; end case; else Unb.Append (Text (Idx)); end if; Idx := Idx + 1; end loop; return Unb; end Un_Escape_String; end GNATCOLL.JSON.Utility; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-json-utility.ads000066400000000000000000000046471425465243200240640ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2011-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ private package GNATCOLL.JSON.Utility is JsonMimeType : constant String := "application/json"; function Escape_Non_Print_Character (C : Wide_Wide_Character) return String; function Escape_String (Text : UTF8_XString) return Ada.Strings.Unbounded.Unbounded_String; -- Translates an UTF-8 encoded unbounded string into a JSON-escaped string function Un_Escape_String (Text : String; Low : Natural; High : Natural) return UTF8_XString; -- Translates a JSON-escaped string into an UTF-8 encoded unbounded string -- Low represents the lower bound of the JSON string in Text -- High represents the higher bound of the JSON string in Text end GNATCOLL.JSON.Utility; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-json.adb000066400000000000000000001274741425465243200223460ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2011-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Containers; use Ada.Containers; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Text_IO; with Ada.Unchecked_Deallocation; with GNATCOLL.Atomic; use GNATCOLL.Atomic; with GNATCOLL.JSON.Utility; with GNATCOLL.Strings; use GNATCOLL.Strings; package body GNATCOLL.JSON is type Text_Position is record Index : Natural := 0; Line : Natural := 0; Column : Natural := 0; end record; -- Record to represent position in a given text type Token_Kind is (J_NULL, J_TRUE, J_FALSE, J_NUMBER, J_INTEGER, J_STRING, J_ARRAY, J_OBJECT, J_ARRAY_END, J_OBJECT_END, J_COMMA, J_COLON, J_EOF); -- JSON Token kinds. Note that in ECMA 404 there is no notion of integer. -- Only numbers are supported. In our implementation we return J_INTEGER -- if there is no decimal part in the number. The semantic is that this is -- a J_NUMBER token that "might" be represented as an integer. Special -- token J_EOF means that end of stream has been reached. function Is_Value (TK : Token_Kind) return Boolean; pragma Inline (Is_Value); -- Return True if the token kind is a JSON value: null, false, true, -- a string, a number, an array or an object. procedure Free is new Ada.Unchecked_Deallocation (JSON_Array_Internal, JSON_Array_Access); procedure Free is new Ada.Unchecked_Deallocation (JSON_Object_Internal, JSON_Object_Access); procedure Report_Error (File : String; Line, Col : Natural; Msg : String); pragma No_Return (Report_Error); procedure Write (Item : JSON_Value; Compact : Boolean; Indent : Natural; Ret : in out Unbounded_String); -- Auxiliary write function function Read (Strm : String; Pos : in out Text_Position; Kind : out Token_Kind; Filename : String; Check_EOF : Boolean := False) return JSON_Value; -- Internal function that reads a JSON stream. -- -- Strm is the content to decode, -- Pos is the current position in the Strm, -- Kind is set to the last read token kind, -- Filename is the filename of corresponding to the content Strm (used for -- for error reporting only). -- If Check_EOF is set to True, check before returning the JSON value that -- we have reached the end of the stream. function Read_Token (Strm : String; Filename : String; Pos : in out Text_Position; Token_Start : out Text_Position; Token_End : out Text_Position) return Token_Kind; -- Read a token -- -- Strm is the content to decode, -- Filename is the filename of the decoded content (error reporting) -- Pos is the current position in Strm -- Token_Start are Token_End are respectively the position of the first and -- last character of the token (outside boundaries of Strm if the return -- token is J_EOF). ------------ -- Append -- ------------ procedure Append (Arr : JSON_Value; Item : JSON_Value) is begin Append (Arr.Data.Arr_Value.Arr, Item); end Append; -------------- -- Is_Empty -- -------------- function Is_Empty (Val : JSON_Value) return Boolean is begin case Val.Kind is when JSON_Null_Type => return True; when JSON_Array_Type => return Val.Data.Arr_Value.Arr.Vals.Is_Empty; when JSON_Object_Type => return Val.Data.Obj_Value.Vals.Is_Empty; when others => return False; end case; end Is_Empty; -------------- -- Is_Value -- -------------- function Is_Value (TK : Token_Kind) return Boolean is begin return TK = J_NULL or else TK = J_TRUE or else TK = J_FALSE or else TK = J_STRING or else TK = J_ARRAY or else TK = J_OBJECT or else TK = J_INTEGER or else TK = J_NUMBER; end Is_Value; ------------------ -- Report_Error -- ------------------ procedure Report_Error (File : String; Line, Col : Natural; Msg : String) is L : constant String := Line'Img; C : constant String := Col'Img; begin Ada.Text_IO.New_Line; if File = "" then Ada.Text_IO.Put (":"); else Ada.Text_IO.Put (File & ":"); end if; Ada.Text_IO.Put_Line (L (L'First + 1 .. L'Last) & ":" & C (C'First + 1 .. C'Last) & ": " & Msg); raise Invalid_JSON_Stream with Msg; end Report_Error; ---------------- -- Read_Token -- ---------------- function Read_Token (Strm : String; Filename : String; Pos : in out Text_Position; Token_Start : out Text_Position; Token_End : out Text_Position) return Token_Kind is procedure Next_Char; -- Update Pos to point to next char function Is_Whitespace return Boolean; pragma Inline (Is_Whitespace); -- Return True of current character is a whitespace function Is_Structural_Token return Boolean; pragma Inline (Is_Structural_Token); -- Return True if current character is one of the structural tokens function Is_Token_Sep return Boolean; pragma Inline (Is_Token_Sep); -- Return True if current character is a token separator procedure Error (Msg : String); pragma No_Return (Error); procedure Delimit_Keyword (Kw : String); -- Helper function to parse tokens such as null, false and true ----------- -- Error -- ----------- procedure Error (Msg : String) is begin Report_Error (Filename, Pos.Line, Pos.Column, Msg); end Error; --------------- -- Next_Char -- --------------- procedure Next_Char is begin Pos.Index := Pos.Index + 1; if Pos.Index > Strm'Last then Pos.Column := Pos.Column + 1; elsif Strm (Pos.Index) = ASCII.LF then Pos.Column := 1; Pos.Line := Pos.Line + 1; else Pos.Column := Pos.Column + 1; end if; end Next_Char; ------------------- -- Is_Whitespace -- ------------------- function Is_Whitespace return Boolean is begin return Pos.Index <= Strm'Last and then (Strm (Pos.Index) = ASCII.LF or else Strm (Pos.Index) = ASCII.CR or else Strm (Pos.Index) = ASCII.HT or else Strm (Pos.Index) = ' '); end Is_Whitespace; ------------------------- -- Is_Structural_Token -- ------------------------- function Is_Structural_Token return Boolean is begin return Pos.Index <= Strm'Last and then (Strm (Pos.Index) = '[' or else Strm (Pos.Index) = ']' or else Strm (Pos.Index) = '{' or else Strm (Pos.Index) = '}' or else Strm (Pos.Index) = ',' or else Strm (Pos.Index) = ':'); end Is_Structural_Token; ------------------ -- Is_Token_Sep -- ------------------ function Is_Token_Sep return Boolean is begin return Pos.Index > Strm'Last or else Is_Whitespace or else Is_Structural_Token; end Is_Token_Sep; --------------------- -- Delimit_Keyword -- --------------------- procedure Delimit_Keyword (Kw : String) is begin while not Is_Token_Sep loop Token_End := Pos; Next_Char; end loop; if Strm (Token_Start.Index .. Token_End.Index) /= Kw then Error ("invalid keyword starting with: " & Strm (Token_Start.Index .. Token_End.Index)); end if; end Delimit_Keyword; CC : Character; Can_Be_Integer : Boolean := True; begin -- Skip leading whitespaces while Is_Whitespace loop Next_Char; end loop; -- Initialize token delimiters Token_Start := Pos; Token_End := Pos; -- End of stream reached if Pos.Index > Strm'Last then return J_EOF; end if; CC := Strm (Pos.Index); if CC = '[' then Next_Char; return J_ARRAY; elsif CC = ']' then Next_Char; return J_ARRAY_END; elsif CC = '{' then Next_Char; return J_OBJECT; elsif CC = '}' then Next_Char; return J_OBJECT_END; elsif CC = ',' then Next_Char; return J_COMMA; elsif CC = ':' then Next_Char; return J_COLON; elsif CC = 'n' then Delimit_Keyword ("null"); return J_NULL; elsif CC = 'f' then Delimit_Keyword ("false"); return J_FALSE; elsif CC = 't' then Delimit_Keyword ("true"); return J_TRUE; elsif CC = '"' then -- We expect a string -- Just scan till the end the of the string but do not attempt -- to decode it. This means that even if we get a string token -- it might not be a valid string from the ECMA 404 point of -- view. Next_Char; while Pos.Index <= Strm'Last and then Strm (Pos.Index) /= '"' loop if Strm (Pos.Index) in ASCII.NUL .. ASCII.US then Error ("control character not allowed in string"); end if; if Strm (Pos.Index) = '\' then Next_Char; if Pos.Index > Strm'Last then Error ("non terminated string token"); end if; case Strm (Pos.Index) is when 'u' => for Idx in 1 .. 4 loop Next_Char; if Pos.Index > Strm'Last or else (Strm (Pos.Index) not in 'a' .. 'f' and then Strm (Pos.Index) not in 'A' .. 'F' and then Strm (Pos.Index) not in '0' .. '9') then Error ("invalid unicode escape sequence"); end if; end loop; when '\' | '/' | '"' | 'b' | 'f' | 'n' | 'r' | 't' => null; when others => Error ("invalid escape sequence"); end case; end if; Next_Char; end loop; -- No quote found report and error if Pos.Index > Strm'Last then Error ("non terminated string token"); end if; Token_End := Pos; -- Go to next char and ensure that this is separator. Indeed -- construction such as "string1""string2" are not allowed Next_Char; if not Is_Token_Sep then Error ("invalid syntax"); end if; return J_STRING; elsif CC = '-' or else CC in '0' .. '9' then -- We expect a number if CC = '-' then Next_Char; end if; if Pos.Index > Strm'Last then Error ("invalid number"); end if; -- Parse integer part of a number. Superfluous leading zeros are not -- allowed. if Strm (Pos.Index) = '0' then Token_End := Pos; Next_Char; elsif Strm (Pos.Index) in '1' .. '9' then Token_End := Pos; Next_Char; while Pos.Index <= Strm'Last and then Strm (Pos.Index) in '0' .. '9' loop Token_End := Pos; Next_Char; end loop; else Error ("invalid number"); end if; if Is_Token_Sep then -- Valid integer number return J_INTEGER; elsif Strm (Pos.Index) /= '.' and then Strm (Pos.Index) /= 'e' and then Strm (Pos.Index) /= 'E' then Error ("invalid number"); end if; -- Check for a fractional part if Strm (Pos.Index) = '.' then Can_Be_Integer := False; Token_End := Pos; Next_Char; if Pos.Index > Strm'Last or else Strm (Pos.Index) not in '0' .. '9' then Error ("invalid number"); end if; while Pos.Index <= Strm'Last and then Strm (Pos.Index) in '0' .. '9' loop Token_End := Pos; Next_Char; end loop; end if; -- Check for exponent part if Pos.Index <= Strm'Last and then (Strm (Pos.Index) = 'e' or else Strm (Pos.Index) = 'E') then Token_End := Pos; Next_Char; if Pos.Index > Strm'Last then Error ("invalid number"); end if; if Strm (Pos.Index) = '-' then -- Also a few corner cases can lead to an integer, assume that -- the number is not an integer. Can_Be_Integer := False; end if; if Strm (Pos.Index) = '-' or else Strm (Pos.Index) = '+' then Next_Char; end if; if Pos.Index > Strm'Last or else Strm (Pos.Index) not in '0' .. '9' then Error ("invalid number"); end if; while Pos.Index <= Strm'Last and then Strm (Pos.Index) in '0' .. '9' loop Token_End := Pos; Next_Char; end loop; end if; if Is_Token_Sep then -- Valid decimal number if Can_Be_Integer then return J_INTEGER; else return J_NUMBER; end if; else Error ("invalid number"); end if; else Error ("Unexpected character '" & CC & '''); end if; end Read_Token; ---------- -- Read -- ---------- function Read (Strm : String; Pos : in out Text_Position; Kind : out Token_Kind; Filename : String; Check_EOF : Boolean := False) return JSON_Value is procedure Error (Msg : String); pragma No_Return (Error); ----------- -- Error -- ----------- procedure Error (Msg : String) is begin Report_Error (Filename, Pos.Line, Pos.Column, Msg); end Error; Token_Start, Token_End : Text_Position; TK : Token_Kind; Result : JSON_Value; begin TK := Read_Token (Strm, Filename, Pos, Token_Start, Token_End); if TK = J_EOF then Error ("empty stream"); end if; Kind := TK; case TK is when J_NULL => Result := Create; when J_FALSE => Result := Create (False); when J_TRUE => Result := Create (True); when J_STRING => Result := Create (Utility.Un_Escape_String (Strm, Token_Start.Index, Token_End.Index)); when J_ARRAY => declare Arr : constant JSON_Array_Access := new JSON_Array_Internal; ST : Token_Kind; Element : JSON_Value; Is_First : Boolean := True; begin loop Element := Read (Strm, Pos, ST, Filename); if Is_First and then ST = J_ARRAY_END then exit; elsif Is_Value (ST) then Append (Arr.Arr, Element); Element := Read (Strm, Pos, ST, Filename); if ST = J_ARRAY_END then exit; elsif ST /= J_COMMA then Error ("comma expected"); end if; else Error ("syntax error"); end if; Is_First := False; end loop; Result := (Ada.Finalization.Controlled with Data => (Kind => JSON_Array_Type, Arr_Value => Arr)); end; when J_OBJECT => declare Is_First : Boolean := True; ST : Token_Kind; Ret : JSON_Value; Key, Value : JSON_Value; Key_Str : UTF8_XString; begin -- Allocate internal container Ret.Data := (Kind => JSON_Object_Type, Obj_Value => new JSON_Object_Internal); loop Key := Read (Strm, Pos, ST, Filename); if Is_First and then ST = J_OBJECT_END then exit; elsif ST = J_STRING then Value := Read (Strm, Pos, ST, Filename); if ST /= J_COLON then Error ("colon expected"); end if; Value := Read (Strm, Pos, ST, Filename); if not Is_Value (ST) then Error ("non expected token"); end if; Key_Str := Get (Key); Set_Field (Ret, Key_Str, Value); Value := Read (Strm, Pos, ST, Filename); if ST = J_OBJECT_END then exit; elsif ST /= J_COMMA then Error ("comma expected"); end if; else Error ("string value expected"); end if; Is_First := False; end loop; Result := Ret; end; when J_NUMBER | J_INTEGER => -- This is a number declare Number_Str : constant String := Strm (Token_Start.Index .. Token_End.Index); Has_Integer : Boolean := False; begin if TK = J_INTEGER then declare Result_Int : Long_Long_Integer; begin Result_Int := Long_Long_Integer'Value (Number_Str); Result := Create (Result_Int); Has_Integer := True; exception when Constraint_Error | Storage_Error => null; end; end if; if not Has_Integer then begin Result := Create (Long_Float'Value (Number_Str)); exception when Constraint_Error => Error ("cannot convert JSON number to Long_Float"); end; end if; end; when others => if Check_EOF then Error ("invalid JSON stream"); else Result := Create; end if; end case; if Check_EOF and then Read_Token (Strm, Filename, Pos, Token_Start, Token_End) /= J_EOF then Error ("additional data after end of JSON stream"); end if; return Result; end Read; function Read (Strm : Unbounded_String; Filename : String := "") return JSON_Value is begin return Read (To_String (Strm), Filename); end Read; function Read (Strm : String; Filename : String := "") return JSON_Value is Pos : Text_Position := (Strm'First, 1, 1); Kind : Token_Kind; begin return Read (Strm, Pos, Kind, Filename, Check_EOF => True); end Read; ----------- -- Write -- ----------- procedure Write (Item : JSON_Value; Compact : Boolean; Indent : Natural; Ret : in out Unbounded_String) is procedure Do_Indent (Val : Natural); -- Adds whitespace characters to Ret corresponding to the indentation -- level. --------------- -- Do_Indent -- --------------- procedure Do_Indent (Val : Natural) is begin if Compact then return; end if; Append (Ret, (1 .. 2 * Val => ' ')); end Do_Indent; begin case Item.Kind is when JSON_Null_Type => Append (Ret, "null"); when JSON_Boolean_Type => if Item.Data.Bool_Value then Append (Ret, "true"); else Append (Ret, "false"); end if; when JSON_Int_Type => declare S : constant String := Item.Data.Int_Value'Img; begin if S (S'First) = ' ' then Append (Ret, S (S'First + 1 .. S'Last)); else Append (Ret, S); end if; end; when JSON_Float_Type => declare S : constant String := Item.Data.Flt_Value'Img; begin if S (S'First) = ' ' then Append (Ret, S (S'First + 1 .. S'Last)); else Append (Ret, S); end if; end; when JSON_String_Type => Append (Ret, JSON.Utility.Escape_String (Item.Data.Str_Value)); when JSON_Array_Type => Append (Ret, '['); if not Compact then Append (Ret, ASCII.LF); end if; for J in Item.Data.Arr_Value.Arr.Vals.First_Index .. Item.Data.Arr_Value.Arr.Vals.Last_Index loop Do_Indent (Indent + 1); Write (Item.Data.Arr_Value.Arr.Vals.Element (J), Compact, Indent + 1, Ret); if J < Item.Data.Arr_Value.Arr.Vals.Last_Index then Append (Ret, ","); end if; if not Compact then Append (Ret, ASCII.LF); end if; end loop; Do_Indent (Indent); Append (Ret, ']'); when JSON_Object_Type => declare use Object_Items_Pkg; J : Object_Items_Pkg.Cursor := Item.Data.Obj_Value.Vals.First; begin Append (Ret, '{'); if not Compact then Append (Ret, ASCII.LF); end if; while Has_Element (J) loop Do_Indent (Indent + 1); Append (Ret, GNATCOLL.JSON.Utility.Escape_String (Element (J).Key)); Append (Ret, ':'); if not Compact then Append (Ret, ' '); end if; Write (Element (J).Val, Compact, Indent + 1, Ret); Next (J); if Has_Element (J) then Append (Ret, ","); end if; if not Compact then Append (Ret, ASCII.LF); end if; end loop; Do_Indent (Indent); Append (Ret, '}'); end; end case; end Write; ----------- -- Write -- ----------- function Write (Item : JSON_Value; Compact : Boolean := True) return String is begin return To_String (Write (Item, Compact)); end Write; ----------- -- Write -- ----------- function Write (Item : JSON_Value; Compact : Boolean := True) return Unbounded_String is Ret : Unbounded_String; begin Write (Item, Compact, 0, Ret); return Ret; end Write; ------------ -- Length -- ------------ function Length (Arr : JSON_Array) return Natural is begin return Natural (Arr.Vals.Length); end Length; -------------- -- Is_Empty -- -------------- function Is_Empty (Arr : JSON_Array) return Boolean is begin return Arr.Vals.Is_Empty; end Is_Empty; --------- -- Get -- --------- function Get (Arr : JSON_Array; Index : Positive) return JSON_Value is begin return Arr.Vals.Element (Index); end Get; ----------------- -- Set_Element -- ----------------- procedure Set_Element (Arr : in out JSON_Array; Index : Positive; Item : JSON_Value) is begin Arr.Vals.Replace_Element (Index, Item); end Set_Element; ---------- -- Sort -- ---------- procedure Sort (Arr : in out JSON_Array; Less : access function (Left, Right : JSON_Value) return Boolean) is package Sorting is new Vect_Pkg.Generic_Sorting ("<" => Less.all); begin Sorting.Sort (Arr.Vals); end Sort; procedure Sort (Val : in out JSON_Value; Less : access function (Left, Right : JSON_Value) return Boolean) is function "<" (Left, Right : Object_Item) return Boolean; function "<" (Left, Right : Object_Item) return Boolean is begin return Less (Left.Val, Right.Val); end "<"; package Sorting is new Object_Items_Pkg.Generic_Sorting ("<"); begin case Val.Kind is when JSON_Array_Type => Sort (Val.Data.Arr_Value.Arr, Less); when JSON_Object_Type => Sorting.Sort (Val.Data.Obj_Value.Vals); when others => null; end case; end Sort; ------------ -- Append -- ------------ procedure Append (Arr : in out JSON_Array; Val : JSON_Value) is begin Arr.Vals.Append (Val); end Append; ------------- -- Prepend -- ------------- procedure Prepend (Arr : in out JSON_Array; Val : JSON_Value) is begin Arr.Vals.Prepend (Val); end Prepend; --------- -- "&" -- --------- function "&" (Arr : JSON_Array; Value : JSON_Value) return JSON_Array is Result : JSON_Array := Arr; begin Append (Result, Value); return Result; end "&"; function "&" (Value1, Value2 : JSON_Value) return JSON_Array is Result : JSON_Array; begin Append (Result, Value1); Append (Result, Value2); return Result; end "&"; ----------- -- Clear -- ----------- procedure Clear (Arr : in out JSON_Array) is begin Arr.Vals.Clear; end Clear; ------------ -- Adjust -- ------------ overriding procedure Adjust (Obj : in out JSON_Value) is begin case Obj.Data.Kind is when JSON_Array_Type => if Obj.Data.Arr_Value /= null then Increment (Obj.Data.Arr_Value.Cnt); end if; when JSON_Object_Type => if Obj.Data.Obj_Value /= null then Increment (Obj.Data.Obj_Value.Cnt); end if; when others => null; end case; end Adjust; -------------- -- Finalize -- -------------- overriding procedure Finalize (Obj : in out JSON_Value) is begin case Obj.Data.Kind is when JSON_Array_Type => declare Arr : JSON_Array_Access := Obj.Data.Arr_Value; begin Obj.Data.Arr_Value := null; if Arr /= null and then Decrement (Arr.Cnt) then Free (Arr); end if; end; when JSON_Object_Type => declare Object : JSON_Object_Access := Obj.Data.Obj_Value; begin Obj.Data.Obj_Value := null; if Object /= null and then Decrement (Object.Cnt) then Free (Object); end if; end; when others => null; end case; end Finalize; ------------ -- Create -- ------------ function Create return JSON_Value is begin return JSON_Null; end Create; function Create (Val : Boolean) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (Kind => JSON_Boolean_Type, Bool_Value => Val); return Ret; end Create; function Create (Val : Integer) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (JSON_Int_Type, Int_Value => Long_Long_Integer (Val)); return Ret; end Create; function Create (Val : Long_Integer) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (JSON_Int_Type, Int_Value => Long_Long_Integer (Val)); return Ret; end Create; function Create (Val : Long_Long_Integer) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (Kind => JSON_Int_Type, Int_Value => Val); return Ret; end Create; function Create (Val : Float) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (Kind => JSON_Float_Type, Flt_Value => Long_Float (Val)); return Ret; end Create; function Create (Val : Long_Float) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (Kind => JSON_Float_Type, Flt_Value => Val); return Ret; end Create; function Create (Val : UTF8_String) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (JSON_String_Type, Str_Value => <>); Ret.Data.Str_Value.Set (Val); return Ret; end Create; function Create (Val : UTF8_Unbounded_String) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (Kind => JSON_String_Type, Str_Value => Null_XString); Ret.Data.Str_Value.Set (To_String (Val)); return Ret; end Create; function Create (Val : UTF8_XString) return JSON_Value is Ret : JSON_Value; begin Ret.Data := (Kind => JSON_String_Type, Str_Value => Val); return Ret; end Create; function Create (Val : JSON_Array) return JSON_Value is begin return (Ada.Finalization.Controlled with Data => (Kind => JSON_Array_Type, Arr_Value => new JSON_Array_Internal' (Cnt => 1, Arr => Val))); end Create; ------------------- -- Create_Object -- ------------------- function Create_Object return JSON_Value is Ret : JSON_Value; begin Ret.Data := (JSON_Object_Type, Obj_Value => new JSON_Object_Internal); return Ret; end Create_Object; ----------------- -- Unset_Field -- ----------------- procedure Unset_Field (Val : JSON_Value; Field_Name : UTF8_String) is Vals : Object_Items_Pkg.Vector renames Val.Data.Obj_Value.Vals; begin for J in Vals.First_Index .. Vals.Last_Index loop if Vals.Element (J).Key = Field_Name then Val.Data.Obj_Value.Vals.Delete (J); return; end if; end loop; end Unset_Field; --------------- -- Set_Field -- --------------- procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : JSON_Value) is Vals : Object_Items_Pkg.Vector renames Val.Data.Obj_Value.Vals; begin for J in Vals.First_Index .. Vals.Last_Index loop if Field_Name = Vals.Element (J).Key then Vals.Replace_Element (J, (Vals.Element (J).Key, Field)); return; end if; end loop; Vals.Append ((Key => To_XString (Field_Name), Val => Field)); end Set_Field; procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_XString; Field : JSON_Value) is Vals : Object_Items_Pkg.Vector renames Val.Data.Obj_Value.Vals; begin for J in Vals.First_Index .. Vals.Last_Index loop if Field_Name = Vals.Element (J).Key then Vals.Replace_Element (J, (Field_Name, Field)); return; end if; end loop; Vals.Append ((Key => Field_Name, Val => Field)); end Set_Field; procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : Boolean) is begin Set_Field (Val, Field_Name, Create (Field)); end Set_Field; procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : Integer) is begin Set_Field (Val, Field_Name, Create (Field)); end Set_Field; procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : Long_Integer) is begin Set_Field (Val, Field_Name, Create (Field)); end Set_Field; procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : Float) is begin Set_Field (Val, Field_Name, Create (Field)); end Set_Field; procedure Set_Field_Long_Float (Val : JSON_Value; Field_Name : UTF8_String; Field : Long_Float) is begin Set_Field (Val, Field_Name, Create (Field)); end Set_Field_Long_Float; procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : UTF8_String) is begin Set_Field (Val, Field_Name, Create (Field)); end Set_Field; procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : UTF8_Unbounded_String) is begin Set_Field (Val, Field_Name, Create (Field)); end Set_Field; procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : JSON_Array) is F_Val : constant JSON_Value := Create (Field); begin Set_Field (Val, Field_Name, F_Val); end Set_Field; ---------------------------- -- Set_Field_If_Not_Empty -- ---------------------------- procedure Set_Field_If_Not_Empty (Val : JSON_Value; Field_Name : UTF8_String; Field : UTF8_Unbounded_String) is begin if Field /= Null_Unbounded_String then Set_Field (Val, Field_Name, Field); end if; end Set_Field_If_Not_Empty; procedure Set_Field_If_Not_Empty (Val : JSON_Value; Field_Name : UTF8_String; Field : UTF8_String) is begin if Field /= "" then Set_Field (Val, Field_Name, Field); end if; end Set_Field_If_Not_Empty; procedure Set_Field_If_Not_Empty (Val : JSON_Value; Field_Name : UTF8_String; Field : JSON_Array) is begin if Field /= Empty_Array then Set_Field (Val, Field_Name, Field); end if; end Set_Field_If_Not_Empty; ---------- -- Kind -- ---------- function Kind (Val : JSON_Value) return JSON_Value_Type is begin return Val.Data.Kind; end Kind; --------- -- Get -- --------- function Get (Val : JSON_Value) return Boolean is begin return Val.Data.Bool_Value; end Get; function Get (Val : JSON_Value) return Integer is begin return Integer (Val.Data.Int_Value); end Get; function Get (Val : JSON_Value) return Long_Integer is begin return Long_Integer (Val.Data.Int_Value); end Get; function Get (Val : JSON_Value) return Long_Long_Integer is begin return Val.Data.Int_Value; end Get; function Get (Val : JSON_Value) return Float is begin return Float (Val.Data.Flt_Value); end Get; function Get_Long_Float (Val : JSON_Value) return Long_Float is begin return Val.Data.Flt_Value; end Get_Long_Float; function Get (Val : JSON_Value) return UTF8_String is begin return To_String (Val.Data.Str_Value); end Get; function Get (Val : JSON_Value) return UTF8_XString is begin return Val.Data.Str_Value; end Get; function Get (Val : JSON_Value) return UTF8_Unbounded_String is begin return To_Unbounded_String (Val.Data.Str_Value.To_String); end Get; function Get (Val : JSON_Value; Field : UTF8_String) return JSON_Value is Vals : Object_Items_Pkg.Vector renames Val.Data.Obj_Value.Vals; begin for J in Vals.First_Index .. Vals.Last_Index loop if Field = Vals.Element (J).Key then return Vals.Element (J).Val; end if; end loop; return JSON_Null; end Get; function Get (Val : JSON_Value) return JSON_Array is begin return Val.Data.Arr_Value.Arr; end Get; --------------- -- Has_Field -- --------------- function Has_Field (Val : JSON_Value; Field : UTF8_String) return Boolean is Vals : Object_Items_Pkg.Vector renames Val.Data.Obj_Value.Vals; begin for J in Vals.First_Index .. Vals.Last_Index loop if Field = Vals.Element (J).Key then return True; end if; end loop; return False; end Has_Field; --------- -- Get -- --------- function Get (Val : JSON_Value; Field : UTF8_String) return Boolean is begin return Get (Get (Val, Field)); end Get; function Get (Val : JSON_Value; Field : UTF8_String) return Integer is begin return Get (Get (Val, Field)); end Get; function Get (Val : JSON_Value; Field : UTF8_String) return Long_Integer is begin return Get (Get (Val, Field)); end Get; function Get (Val : JSON_Value; Field : UTF8_String) return Float is begin return Get (Get (Val, Field)); end Get; function Get_Long_Float (Val : JSON_Value; Field : UTF8_String) return Long_Float is begin return Get_Long_Float (Get (Val, Field)); end Get_Long_Float; function Get (Val : JSON_Value; Field : UTF8_String) return UTF8_String is begin return Get (Get (Val, Field)); end Get; function Get (Val : JSON_Value; Field : UTF8_String) return UTF8_Unbounded_String is begin return Get (Get (Val, Field)); end Get; function Get (Val : JSON_Value; Field : UTF8_String) return JSON_Array is begin return Get (Get (Val, Field)); end Get; ----------- -- Clone -- ----------- function Clone (Val : JSON_Value) return JSON_Value is begin case Val.Data.Kind is when JSON_Null_Type => return JSON_Null; when JSON_Boolean_Type => return Create (Val.Data.Bool_Value); when JSON_Int_Type => return Create (Val.Data.Int_Value); when JSON_Float_Type => return Create (Val.Data.Flt_Value); when JSON_String_Type => return Create (Val.Data.Str_Value); when JSON_Array_Type => declare Result : constant JSON_Value := (Ada.Finalization.Controlled with Data => (Kind => JSON_Array_Type, Arr_Value => new JSON_Array_Internal)); begin for E of Val.Data.Arr_Value.Arr.Vals loop Append (Result.Data.Arr_Value.Arr, Clone (E)); end loop; return Result; end; when JSON_Object_Type => declare Result : constant JSON_Value := Create_Object; begin for E of Val.Data.Obj_Value.Vals loop Result.Set_Field (To_String (E.Key), Clone (E.Val)); end loop; return Result; end; end case; end Clone; --------- -- "=" -- --------- function "=" (Left, Right : JSON_Value) return Boolean is Found : Boolean; begin if Left.Data.Kind /= Right.Data.Kind then return False; end if; case Left.Data.Kind is when JSON_Null_Type => return True; when JSON_Boolean_Type => return Left.Data.Bool_Value = Right.Data.Bool_Value; when JSON_Int_Type => return Left.Data.Int_Value = Right.Data.Int_Value; when JSON_Float_Type => return Left.Data.Flt_Value = Right.Data.Flt_Value; when JSON_String_Type => return Left.Data.Str_Value = Right.Data.Str_Value; when JSON_Array_Type => -- Same pointer ? if Left.Data.Arr_Value = Right.Data.Arr_Value then return True; elsif Left.Data.Arr_Value.Arr.Vals.Length /= Right.Data.Arr_Value.Arr.Vals.Length then return False; else for J in Left.Data.Arr_Value.Arr.Vals.First_Index .. Left.Data.Arr_Value.Arr.Vals.Last_Index loop if not (Left.Data.Arr_Value.Arr.Vals (J) = -- recursive Right.Data.Arr_Value.Arr.Vals (J)) then return False; end if; end loop; return True; end if; when JSON_Object_Type => -- Same pointer ? if Left.Data.Obj_Value = Right.Data.Obj_Value then return True; elsif Left.Data.Obj_Value.Vals.Length /= Right.Data.Obj_Value.Vals.Length then return False; else -- We have the same number of elements, and no duplicates for L of Left.Data.Obj_Value.Vals loop Found := False; for R of Right.Data.Obj_Value.Vals loop if R.Key = L.Key then if not (R.Val = L.Val) then -- recursive return False; end if; Found := True; exit; end if; end loop; if not Found then return False; end if; end loop; return True; end if; end case; end "="; --------------------- -- Map_JSON_Object -- --------------------- procedure Map_JSON_Object (Val : JSON_Value; CB : access procedure (Name : UTF8_String; Value : JSON_Value)) is Vals : Object_Items_Pkg.Vector renames Val.Data.Obj_Value.Vals; begin for J in Vals.First_Index .. Vals.Last_Index loop CB (To_String (Vals.Element (J).Key), Vals.Element (J).Val); end loop; end Map_JSON_Object; --------------------- -- Map_JSON_Object -- --------------------- procedure Gen_Map_JSON_Object (Val : JSON_Value; CB : access procedure (User_Object : in out Mapped; Name : UTF8_String; Value : JSON_Value); User_Object : in out Mapped) is procedure Internal (Name : UTF8_String; Value : JSON_Value); -------------- -- Internal -- -------------- procedure Internal (Name : UTF8_String; Value : JSON_Value) is begin CB (User_Object, Name, Value); end Internal; begin Map_JSON_Object (Val, Internal'Access); end Gen_Map_JSON_Object; end GNATCOLL.JSON; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-json.ads000066400000000000000000000413071425465243200223550ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2011-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Finalization; with Ada.Strings.Unbounded; with GNATCOLL.Strings; private with Ada.Containers.Vectors; private with GNATCOLL.Atomic; package GNATCOLL.JSON is type JSON_Value_Type is (JSON_Null_Type, JSON_Boolean_Type, JSON_Int_Type, JSON_Float_Type, JSON_String_Type, JSON_Array_Type, JSON_Object_Type); Invalid_JSON_Stream : exception; subtype UTF8_String is String; type UTF8_String_Access is access all UTF8_String; subtype UTF8_Unbounded_String is Ada.Strings.Unbounded.Unbounded_String; subtype UTF8_XString is GNATCOLL.Strings.XString; subtype JSON_Elementary_Value_Type is JSON_Value_Type range JSON_Null_Type .. JSON_String_Type; subtype JSON_Container_Value_Type is JSON_Value_Type range JSON_Array_Type .. JSON_Object_Type; type JSON_Value is tagged private; -- Stores a JSON value, which can be either a simple type (integer, -- string, ...) or an object with multiple fields, or an array. -- -- This type works by reference. Using the standard assignment operator -- as in -- A := B; -- means that modifying B will also modify A (and modifying A will of -- course modify B). -- -- If you want to create a separate copy, you must use the Clone function. type JSON_Array is private; JSON_Null : constant JSON_Value; Empty_Array : constant JSON_Array; -- Array handling function Is_Empty (Arr : JSON_Array) return Boolean; function Length (Arr : JSON_Array) return Natural; function Get (Arr : JSON_Array; Index : Positive) return JSON_Value; procedure Append (Arr : in out JSON_Array; Val : JSON_Value); procedure Prepend (Arr : in out JSON_Array; Val : JSON_Value); procedure Clear (Arr : in out JSON_Array); procedure Sort (Arr : in out JSON_Array; Less : access function (Left, Right : JSON_Value) return Boolean); -- Reorders the elements of array such that the elements are sorted -- smallest first as determined by the strict comparison provided by -- function Less. procedure Set_Element (Arr : in out JSON_Array; Index : Positive; Item : JSON_Value); -- If Index is not in the array index range, then Constraint_Error is -- propagated. Otherwise Set_Element assigns the value New_Item to the -- element at position Index. function "&" (Arr : JSON_Array; Value : JSON_Value) return JSON_Array; function "&" (Value1, Value2 : JSON_Value) return JSON_Array; -- Create a new array. This is less efficient than Append because it -- results in an extra copy of the array, but is easier to use when -- manipulating small arrays. function Is_Empty (Val : JSON_Value) return Boolean; -- Returns True if Val is empty array, empty object or null value -- Read or write JSON values into strings function Read (Strm : Ada.Strings.Unbounded.Unbounded_String; Filename : String := "") return JSON_Value; function Read (Strm : String; Filename : String := "") return JSON_Value; function Write (Item : JSON_Value; Compact : Boolean := True) return String; function Write (Item : JSON_Value; Compact : Boolean := True) return Ada.Strings.Unbounded.Unbounded_String; -- Creation of JSON values function Create return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_Null_Type); -- Creates a 'null' JSON value function Create (Val : Boolean) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_Boolean_Type); -- Creates a boolean-typed JSON value function Create (Val : Integer) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_Int_Type); function Create (Val : Long_Integer) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_Int_Type); function Create (Val : Long_Long_Integer) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_Int_Type); -- Creates an integer-typed JSON value function Create (Val : Float) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_Float_Type); -- Creates a float-typed JSON value function Create (Val : Long_Float) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_Float_Type); function Create (Val : UTF8_String) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_String_Type); -- Creates a string-typed JSON value function Create (Val : UTF8_Unbounded_String) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_String_Type); -- Creates a string-typed JSON value function Create (Val : UTF8_XString) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_String_Type); -- Creates a string-typed JSON value function Create (Val : JSON_Array) return JSON_Value; pragma Postcondition (Kind (Create'Result) = JSON_Array_Type); -- Creates a JSON value from the JSON array function Create_Object return JSON_Value; pragma Postcondition (Kind (Create_Object'Result) = JSON_Object_Type); -- Creates an empty object. Values need to be added using the below -- Set_Field methods procedure Sort (Val : in out JSON_Value; Less : access function (Left, Right : JSON_Value) return Boolean); -- Reorders the elements of array or fields of object such that the -- values are sorted smallest first as determined by the strict comparision -- provided by function Less. procedure Append (Arr : JSON_Value; Item : JSON_Value); pragma Precondition (Arr.Kind = JSON_Array_Type); -- Append Arr only in case of it is an array, raise Constraint_Error -- otherwise. function Clone (Val : JSON_Value) return JSON_Value; -- Returns a deep clone of Val. -- Any change in Val or its fields (recursively) will have no impact -- on the resulting value. function "=" (Left, Right : JSON_Value) return Boolean; -- Compare to values. -- The actual contents is compared, not the pointers. So two objects -- constructed independently, with the same contents, will match. -- The order that fields were created is irrelevant, for objects. -- The order in arrays is relevant. procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : JSON_Value); pragma Precondition (Kind (Val) = JSON_Object_Type); -- Adds or modifies the named field for the specified json object, using -- the Field value. procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_XString; Field : JSON_Value); pragma Precondition (Kind (Val) = JSON_Object_Type); -- Adds or modifies the named field for the specified json object, using -- the Field value. procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : Boolean); pragma Precondition (Kind (Val) = JSON_Object_Type); procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : Integer); pragma Precondition (Kind (Val) = JSON_Object_Type); procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : Long_Integer); pragma Precondition (Kind (Val) = JSON_Object_Type); procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : Float); pragma Precondition (Kind (Val) = JSON_Object_Type); procedure Set_Field_Long_Float (Val : JSON_Value; Field_Name : UTF8_String; Field : Long_Float); pragma Precondition (Kind (Val) = JSON_Object_Type); procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : UTF8_String); pragma Precondition (Kind (Val) = JSON_Object_Type); procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : UTF8_Unbounded_String); pragma Precondition (Kind (Val) = JSON_Object_Type); procedure Set_Field (Val : JSON_Value; Field_Name : UTF8_String; Field : JSON_Array); pragma Precondition (Kind (Val) = JSON_Object_Type); -- Any change you do to the array afterward will not impact Val procedure Set_Field_If_Not_Empty (Val : JSON_Value; Field_Name : UTF8_String; Field : UTF8_Unbounded_String); pragma Precondition (Kind (Val) = JSON_Object_Type); -- Set Field only if it is not empty string procedure Set_Field_If_Not_Empty (Val : JSON_Value; Field_Name : UTF8_String; Field : UTF8_String); pragma Precondition (Kind (Val) = JSON_Object_Type); -- Set Field only if it is not empty string procedure Set_Field_If_Not_Empty (Val : JSON_Value; Field_Name : UTF8_String; Field : JSON_Array); pragma Precondition (Kind (Val) = JSON_Object_Type); -- Set Field only if it is not empty array. -- Any change you do to the array afterward will not impact Val. procedure Unset_Field (Val : JSON_Value; Field_Name : UTF8_String); -- Unset the field with the given name, just as if Set_Field had never -- been called. -- Utility functions used to translate a JSON value into an ordinary object function Kind (Val : JSON_Value) return JSON_Value_Type; function Get (Val : JSON_Value) return Boolean; pragma Precondition (Kind (Val) = JSON_Boolean_Type); function Get (Val : JSON_Value) return Integer; pragma Precondition (Kind (Val) = JSON_Int_Type); function Get (Val : JSON_Value) return Long_Integer; pragma Precondition (Kind (Val) = JSON_Int_Type); function Get (Val : JSON_Value) return Long_Long_Integer; pragma Precondition (Kind (Val) = JSON_Int_Type); function Get (Val : JSON_Value) return Float; pragma Precondition (Kind (Val) = JSON_Float_Type); function Get_Long_Float (Val : JSON_Value) return Long_Float; pragma Precondition (Kind (Val) = JSON_Float_Type); function Get (Val : JSON_Value) return UTF8_String; pragma Precondition (Kind (Val) = JSON_String_Type); function Get (Val : JSON_Value) return UTF8_Unbounded_String; pragma Precondition (Kind (Val) = JSON_String_Type); function Get (Val : JSON_Value) return UTF8_XString; pragma Precondition (Kind (Val) = JSON_String_Type); function Get (Val : JSON_Value) return JSON_Array; pragma Precondition (Kind (Val) = JSON_Array_Type); function Has_Field (Val : JSON_Value; Field : UTF8_String) return Boolean; pragma Precondition (Kind (Val) = JSON_Object_Type); -- Tell whether the object val contains a field named Field function Get (Val : JSON_Value; Field : UTF8_String) return JSON_Value; pragma Precondition (Kind (Val) = JSON_Object_Type); function Get (Val : JSON_Value; Field : UTF8_String) return Boolean; pragma Precondition (Kind (Val) = JSON_Object_Type and then Kind (Get (Val, Field)) = JSON_Boolean_Type); function Get (Val : JSON_Value; Field : UTF8_String) return Integer; pragma Precondition (Kind (Val) = JSON_Object_Type and then Kind (Get (Val, Field)) = JSON_Int_Type); function Get (Val : JSON_Value; Field : UTF8_String) return Long_Integer; pragma Precondition (Kind (Val) = JSON_Object_Type and then Kind (Get (Val, Field)) = JSON_Int_Type); function Get (Val : JSON_Value; Field : UTF8_String) return Float; pragma Precondition (Kind (Val) = JSON_Object_Type and then Kind (Get (Val, Field)) = JSON_Float_Type); function Get_Long_Float (Val : JSON_Value; Field : UTF8_String) return Long_Float; pragma Precondition (Kind (Val) = JSON_Object_Type and then Kind (Get (Val, Field)) = JSON_Float_Type); function Get (Val : JSON_Value; Field : UTF8_String) return UTF8_String; pragma Precondition (Kind (Val) = JSON_Object_Type and then Kind (Get (Val, Field)) = JSON_String_Type); function Get (Val : JSON_Value; Field : UTF8_String) return UTF8_Unbounded_String; pragma Precondition (Kind (Val) = JSON_Object_Type and then Kind (Get (Val, Field)) = JSON_String_Type); function Get (Val : JSON_Value; Field : UTF8_String) return JSON_Array; pragma Precondition (Kind (Val) = JSON_Object_Type and then Kind (Get (Val, Field)) = JSON_Array_Type); --------------- -- Iteration -- --------------- procedure Map_JSON_Object (Val : JSON_Value; CB : access procedure (Name : UTF8_String; Value : JSON_Value)); pragma Precondition (Kind (Val) = JSON_Object_Type); -- Iterate over all fields of the object generic type Mapped is private; procedure Gen_Map_JSON_Object (Val : JSON_Value; CB : access procedure (User_Object : in out Mapped; Name : UTF8_String; Value : JSON_Value); User_Object : in out Mapped); pragma Precondition (Kind (Val) = JSON_Object_Type); -- Iter on all fields of the object, like Map_JSON_Object does, -- but the callback can return a value which is also returned by -- Gen_Map_JSON_Object itself. private type JSON_Array_Internal; type JSON_Array_Access is access all JSON_Array_Internal; type JSON_Object_Internal; type JSON_Object_Access is access all JSON_Object_Internal; type Data_Type (Kind : JSON_Value_Type := JSON_Null_Type) is record case Kind is when JSON_Null_Type => null; when JSON_Boolean_Type => Bool_Value : Boolean; when JSON_Int_Type => Int_Value : Long_Long_Integer; when JSON_Float_Type => Flt_Value : Long_Float; when JSON_String_Type => Str_Value : UTF8_XString; when JSON_Array_Type => Arr_Value : JSON_Array_Access; when JSON_Object_Type => Obj_Value : JSON_Object_Access; end case; end record; type JSON_Value is new Ada.Finalization.Controlled with record Data : Data_Type; end record; -- We cannot merge Data_Type and JSON_Value, because JSON_Value cannot -- have a discriminant with a default value. overriding procedure Adjust (Obj : in out JSON_Value); overriding procedure Finalize (Obj : in out JSON_Value); -- JSON Array definition: package Vect_Pkg is new Ada.Containers.Vectors (Index_Type => Positive, Element_Type => JSON_Value); type JSON_Array is record Vals : Vect_Pkg.Vector; end record; type JSON_Array_Internal is record Cnt : aliased GNATCOLL.Atomic.Atomic_Counter := 1; Arr : JSON_Array; end record; Empty_Array : constant JSON_Array := (Vals => Vect_Pkg.Empty_Vector); -- JSON Object definition: type Object_Item is record Key : UTF8_XString; Val : JSON_Value; end record; package Object_Items_Pkg is new Ada.Containers.Vectors (Positive, Object_Item); type JSON_Object_Internal is record Cnt : aliased GNATCOLL.Atomic.Atomic_Counter := 1; Vals : Object_Items_Pkg.Vector; end record; JSON_Null : constant JSON_Value := (Ada.Finalization.Controlled with others => <>); -- Can't call Create, because we would need to see the body of -- Initialize and Adjust. end GNATCOLL.JSON; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-memory.adb000066400000000000000000000250161425465243200226720ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Exceptions; with System.Storage_Elements; use System.Storage_Elements; pragma Warnings (Off); with System.CRTL; -- Force a user's s-memory.adb to be part of the link, -- otherwise s-memory.o will simply be ignored by gprbuild with System.Memory; pragma Warnings (On); package body GNATCOLL.Memory is Memory_Pool : GNAT.Debug_Pools.Debug_Pool; use Ada.Exceptions; Memory_Monitor : Boolean := False; Memory_Check : Boolean := False; Debug_Pool_Initialization_Needed : Boolean := True; procedure Initialize_System_Memory_Debug_Pool (Has_Unhandled_Memory : Boolean := False); -- If not already done, let Debug_Pools know that System.Memory will use -- Debug_Pools, and have to handle memory allocated by System.CRTL package. ----------------------------------------- -- Initialize_System_Memory_Debug_Pool -- ----------------------------------------- procedure Initialize_System_Memory_Debug_Pool (Has_Unhandled_Memory : Boolean := False) is begin if Debug_Pool_Initialization_Needed then Debug_Pool_Initialization_Needed := False; GNAT.Debug_Pools.System_Memory_Debug_Pool (Has_Unhandled_Memory); end if; end Initialize_System_Memory_Debug_Pool; ----------- -- Alloc -- ----------- function Alloc (Size : size_t) return System.Address is Result : System.Address; Actual_Size : size_t := Size; begin if Size = size_t'Last then Raise_Exception (Storage_Error'Identity, "object too large"); end if; -- Change size from zero to non-zero. We still want a proper pointer -- for the zero case because pointers to zero length objects have to -- be distinct, but we can't just go ahead and allocate zero bytes, -- since some malloc's return zero for a zero argument. if Size = 0 then Actual_Size := 1; end if; if Memory_Monitor then Initialize_System_Memory_Debug_Pool; Memory_Pool.Allocate (Storage_Address => Result, Size_In_Storage_Elements => Storage_Count (Actual_Size), Alignment => Standard'Maximum_Alignment); else Result := System.CRTL.malloc (System.CRTL.size_t (Actual_Size)); end if; if Result = System.Null_Address then Raise_Exception (Storage_Error'Identity, "heap exhausted"); end if; return Result; end Alloc; ---------- -- Free -- ---------- procedure Free (Ptr : System.Address) is begin if Ptr /= System.Null_Address and not Memory_Check then if Memory_Monitor then Initialize_System_Memory_Debug_Pool; Memory_Pool.Deallocate (Storage_Address => Ptr, Size_In_Storage_Elements => Storage_Count'Last, Alignment => Standard'Maximum_Alignment); else System.CRTL.free (Ptr); end if; end if; end Free; ------------- -- Realloc -- ------------- function Realloc (Ptr : System.Address; Size : size_t) return System.Address is Result : System.Address; Actual_Size : size_t := Size; begin if Size = size_t'Last then Raise_Exception (Storage_Error'Identity, "object too large"); end if; if not Memory_Monitor then Result := System.CRTL.realloc (Ptr, System.CRTL.size_t (Actual_Size)); else declare Size_Was : Storage_Count; Valid : Boolean; procedure Memmove (Dest : System.Address; Src : System.Address; N : size_t); pragma Import (C, Memmove, "memmove"); begin Initialize_System_Memory_Debug_Pool; Get_Size (Storage_Address => Ptr, Size_In_Storage_Elements => Size_Was, Valid => Valid); if not Valid then declare Reallocated : System.Address; begin Reallocated := System.CRTL.realloc (Ptr, System.CRTL.size_t (Actual_Size)); Memory_Pool.Allocate (Storage_Address => Result, Size_In_Storage_Elements => Storage_Count (Actual_Size), Alignment => Standard'Maximum_Alignment); Memmove (Dest => Result, Src => Reallocated, N => Actual_Size); System.CRTL.free (Reallocated); end; else Memory_Pool.Allocate (Storage_Address => Result, Size_In_Storage_Elements => Storage_Count (Size), Alignment => Standard'Maximum_Alignment); if size_t (Size_Was) < Actual_Size then Actual_Size := size_t (Size_Was); end if; Memmove (Dest => Result, Src => Ptr, N => Actual_Size); Free (Ptr); end if; end; end if; if Result = System.Null_Address then Raise_Exception (Storage_Error'Identity, "heap exhausted"); end if; return Result; end Realloc; ----------------------- -- Redirectable_Dump -- ----------------------- procedure Redirectable_Dump (Size : Positive; Report : Report_Type := All_Reports) is procedure Redirected_Dump is new GNAT.Debug_Pools.Dump (Put_Line => Put_Line, Put => Put); begin Redirected_Dump (Memory_Pool, Size => Size, Report => GNAT.Debug_Pools.Report_Type (Report)); end Redirectable_Dump; procedure Dump (Size : Positive; Report : Report_Type := All_Reports) is begin Memory_Pool.Dump_Stdout (Size => Size, Report => GNAT.Debug_Pools.Report_Type (Report)); end Dump; ------------------------- -- Get_Ada_Allocations -- ------------------------- function Get_Ada_Allocations return Watermark_Info is begin return (High => GNATCOLL.Memory.Byte_Count (Memory_Pool.High_Water_Mark), Current => GNATCOLL.Memory.Byte_Count (Memory_Pool.Current_Water_Mark) ); end Get_Ada_Allocations; --------------------- -- Get_Allocations -- --------------------- function Get_Allocations return Watermark_Info is function Get_Peak_RSS return size_t; pragma Import (C, Get_Peak_RSS, "gnatcoll_getPeakRSS"); function Get_Current_RSS return size_t; pragma Import (C, Get_Current_RSS, "gnatcoll_getCurrentRSS"); begin return (High => Byte_Count (Get_Peak_RSS), Current => Byte_Count (Get_Current_RSS)); end Get_Allocations; ----------- -- Reset -- ----------- procedure Reset is begin GNAT.Debug_Pools.Reset; end Reset; --------------- -- Configure -- --------------- procedure Configure (Activate_Monitor : Boolean := False; Disable_Free : Boolean := False; Stack_Trace_Depth : Natural := 30; Maximum_Logically_Freed_Memory : Long_Long_Integer := 50_000_000; Minimum_To_Free : Long_Long_Integer := 0; Reset_Content_On_Free : Boolean := True; Raise_Exceptions : Boolean := False; Advanced_Scanning : Boolean := False; Errors_To_Stdout : Boolean := True; Low_Level_Traces : Boolean := False) is begin Memory_Check := Disable_Free; if Activate_Monitor and not Memory_Monitor then Initialize_System_Memory_Debug_Pool (Has_Unhandled_Memory => True); Memory_Monitor := True; end if; if Memory_Monitor then Memory_Pool.Configure (Stack_Trace_Depth => Stack_Trace_Depth, Maximum_Logically_Freed_Memory => SSC (Maximum_Logically_Freed_Memory), Minimum_To_Free => SSC (Minimum_To_Free + 1), Reset_Content_On_Free => Reset_Content_On_Free, Raise_Exceptions => Raise_Exceptions, Advanced_Scanning => Advanced_Scanning, Errors_To_Stdout => Errors_To_Stdout, Low_Level_Traces => Low_Level_Traces); end if; end Configure; -------------------- -- Mark_Traceback -- -------------------- procedure Mark_Traceback is Size_Was : Byte_Count; pragma Unreferenced (Size_Was); begin null; end Mark_Traceback; end GNATCOLL.Memory; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-memory.ads000066400000000000000000000265241425465243200227200ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides a reimplementation of GNAT's low-level memory -- allocation mechanism. Its goal is to provide an additional monitoring -- facility to check where your program allocates memory. -- -- To activate this alternates implementation in your application, you -- must provide your own s-memory.adb somewhere in your source directories. -- Then simply recompile the modified body of that package with -- gnatmake -u -a -g s-memory.adb (or use the -a switch when you compile -- your own application) and make sure that the ali and object files for -- this unit are found in the object search path. -- -- Your version of System.Memory (in file s-memory.adb) should be: -- -- with GNATCOLL.Memory; -- package body System.Memory is -- package M renames GNATCOLL.Memory; -- -- function Alloc (Size : size_t) return System.Address is -- begin -- return M.Alloc (M.size_t (Size)); -- end Alloc; -- -- procedure Free (Ptr : System.Address) -- renames M.Free; -- -- function Realloc -- (Ptr : System.Address; -- Size : size_t) -- return System.Address is -- begin -- return M.Realloc (Ptr, M.size_t (Size)); -- end Realloc; -- end System.Memory; -- -- As a child package of System, this package must be compiled with -gnatg -- switch to the compiler. with System; use System; with GNAT.Debug_Pools; use GNAT.Debug_Pools; package GNATCOLL.Memory is type size_t is mod 2 ** Standard'Address_Size; -- Same as System.Memory.size_t, but defined here to avoid elaboration -- circularity issues function Alloc (Size : size_t) return System.Address; -- This is the low level allocation routine. Given a size in storage -- units, it returns the address of a maximally aligned block of -- memory. The implementation of this routine is guaranteed to be -- task safe, and also aborts are deferred if necessary. -- -- If size_t is set to size_t'Last on entry, then a Storage_Error -- exception is raised with a message "object too large". -- -- If size_t is set to zero on entry, then a minimal (but non-zero) -- size block is allocated. -- -- Note: this is roughly equivalent to the standard C malloc call -- with the additional semantics as described above. procedure Free (Ptr : System.Address); -- This is the low level free routine. It frees a block previously -- allocated with a call to Alloc. As in the case of Alloc, this -- call is guaranteed task safe, and aborts are deferred. -- -- Note: this is roughly equivalent to the standard C free call -- with the additional semantics as described above. function Realloc (Ptr : System.Address; Size : size_t) return System.Address; -- This is the low level reallocation routine. It takes an existing -- block address returned by a previous call to Alloc or Realloc, -- and reallocates the block. The size can either be increased or -- decreased. If possible the reallocation is done in place, so that -- the returned result is the same as the value of Ptr on entry. -- However, it may be necessary to relocate the block to another -- address, in which case the information is copied to the new -- block, and the old block is freed. The implementation of this -- routine is guaranteed to be task safe, and also aborts are -- deferred as necessary. -- -- If size_t is set to size_t'Last on entry, then a Storage_Error -- exception is raised with a message "object too large". -- -- If size_t is set to zero on entry, then a minimal (but non-zero) -- size block is allocated. -- -- Note: this is roughly equivalent to the standard C realloc call -- with the additional semantics as described above. ------------- -- Monitor -- ------------- procedure Configure (Activate_Monitor : Boolean := False; Disable_Free : Boolean := False; Stack_Trace_Depth : Natural := 30; Maximum_Logically_Freed_Memory : Long_Long_Integer := 50_000_000; Minimum_To_Free : Long_Long_Integer := 0; Reset_Content_On_Free : Boolean := True; Raise_Exceptions : Boolean := False; Advanced_Scanning : Boolean := False; Errors_To_Stdout : Boolean := True; Low_Level_Traces : Boolean := False); -- Configure this package (these are global settings, not task-specific). -- -- If Activate_Monitor is true, GPS will monitor all memory allocations and -- deallocations, and through the Dump procedure below be able to report -- the memory usage. The overhead is almost null when the monitor is -- disabled. -- -- If Disable_Free is true, no deallocation is ever performed. This can be -- temporarily useful when investigating memory issues. -- -- Stack_Trace_Depth. This parameter controls the maximum depth of stack -- traces that are output to indicate locations of actions for error -- conditions such as bad allocations. If set to zero, the debug pool -- will not try to compute backtraces. This is more efficient but gives -- less information on problem locations -- -- Maximum_Logically_Freed_Memory: maximum amount of memory (bytes) -- that should be kept before starting to physically deallocate some. -- This value should be non-zero, since having memory that is logically -- but not physically freed helps to detect invalid memory accesses. -- -- Minimum_To_Free is the minimum amount of memory that should be freed -- every time the pool starts physically releasing memory. The algorithm -- to compute which block should be physically released needs some -- expensive initialization (see Advanced_Scanning below), and this -- parameter can be used to limit the performance impact by ensuring -- that a reasonable amount of memory is freed each time. Even in the -- advanced scanning mode, marked blocks may be released to match this -- Minimum_To_Free parameter. -- -- Reset_Content_On_Free: If true, then the contents of the freed memory -- is reset to the pattern 16#DEADBEEF#, following an old IBM convention. -- This helps in detecting invalid memory references from the debugger. -- -- Raise_Exceptions: If true, the exceptions below will be raised every -- time an error is detected. If you set this to False, then the action -- is to generate output on standard error or standard output, depending -- on Errors_To_Stdout, noting the errors, but to -- keep running if possible (of course if storage is badly damaged, this -- attempt may fail. This helps to detect more than one error in a run. -- -- Advanced_Scanning: If true, the pool will check the contents of all -- allocated blocks before physically releasing memory. Any possible -- reference to a logically free block will prevent its deallocation. -- Note that this algorithm is approximate, and it is recommended -- that you set Minimum_To_Free to a non-zero value to save time. -- -- Errors_To_Stdout: Errors messages will be displayed on stdout if -- this parameter is True, or to stderr otherwise. -- -- Low_Level_Traces: Traces all allocation and deallocations on the -- stream specified by Errors_To_Stdout. This can be used for -- post-processing by your own application, or to debug the -- debug_pool itself. The output indicates the size of the allocated -- block both as requested by the application and as physically -- allocated to fit the additional information needed by the debug -- pool. type Report_Type is new GNAT.Debug_Pools.Report_Type; generic with procedure Put_Line (S : String) is <>; with procedure Put (S : String) is <>; procedure Redirectable_Dump (Size : Positive; Report : Report_Type := All_Reports); -- Dump information about memory usage to configurable output -- Size is the number of the biggest memory users we want to show. Report -- indicates which sorting order is used in the report procedure Dump (Size : Positive; Report : Report_Type := All_Reports); -- Dump information about memory usage. -- Size is the number of the biggest memory users we want to show. Report -- indicates which sorting order is used in the report procedure Reset; -- Reset all internal data. This is in general not needed, unless you want -- to know what memory is used by specific parts of your application procedure Mark_Traceback; -- Add a special chunk in the monitor for the current traceback. This is -- a convenient way to check how many times we go through a given path, -- and where this is called from. -- Nothing is done if the memory monitor has not been activated type Byte_Count is new GNAT.Debug_Pools.Byte_Count; type Watermark_Info is record High : Byte_Count; Current : Byte_Count; end record; function Get_Ada_Allocations return Watermark_Info; -- Return information about the allocations done from Ada. -- This does not include allocations done from other languages. function Get_Allocations return Watermark_Info; -- Return information about the allocations done in any language. -- This uses system calls to find out the program's resident size (RSS) -- information, both the peak and the current size. private pragma Convention (C, Alloc); pragma Convention (C, Free); pragma Convention (C, Realloc); end GNATCOLL.Memory; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-mmap-system__unix.adb000066400000000000000000000215071425465243200250410ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2007-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.IO_Exceptions; with System; use System; with GNAT.OS_Lib; use GNAT.OS_Lib; package body GNATCOLL.Mmap.System is type Mmap_Prot is mod Interfaces.C.int'Last; for Mmap_Prot'Size use Interfaces.C.int'Size; -- PROT_NONE : constant Mmap_Prot := 16#00#; -- PROT_EXEC : constant Mmap_Prot := 16#04#; PROT_READ : constant Mmap_Prot := 16#01#; PROT_WRITE : constant Mmap_Prot := 16#02#; type Mmap_Flags is mod Interfaces.C.int'Last; for Mmap_Flags'Size use Interfaces.C.int'Size; -- MAP_NONE : constant Mmap_Flags := 16#00#; -- MAP_FIXED : constant Mmap_Flags := 16#10#; MAP_SHARED : constant Mmap_Flags := 16#01#; MAP_PRIVATE : constant Mmap_Flags := 16#02#; function Mmap (Start : Standard.System.Address := Null_Address; Length : File_Size; Prot : Mmap_Prot := PROT_READ; Flags : Mmap_Flags := MAP_PRIVATE; Fd : GNAT.OS_Lib.File_Descriptor; Offset : File_Size := 0) return Standard.System.Address; pragma Import (C, Mmap, "gnatcoll_mmap"); function Munmap (Start : Standard.System.Address; Length : File_Size) return Integer; pragma Import (C, Munmap, "gnatcoll_munmap"); procedure Madvise (Addr : Standard.System.Address; Length : File_Size; Advice : Use_Advice); pragma Import (C, Madvise, "gnatcoll_madvise"); -- Allows a process that has knowledge of its memory behavior to -- describe it to the system. This advice applies to the mapped -- region at address Addr, and for the given Length. If Length -- is 0, this applies to the whole region. function Align (Addr : File_Size) return File_Size; -- Align some offset/length to the lowest page boundary function Is_Mapping_Available return Boolean; -- Wheter memory mapping is actually available on this system. It is an -- error to use Create_Mapping and Dispose_Mapping if this is False. --------------- -- Open_Read -- --------------- function Open_Read (Filename : String; Use_Mmap_If_Available : Boolean := True) return System_File is Fd : constant File_Descriptor := Open_Read (Filename, Binary); begin if Fd = Invalid_FD then raise Ada.IO_Exceptions.Name_Error with "Cannot open " & Filename; end if; return (Fd => Fd, Mapped => Use_Mmap_If_Available and then Is_Mapping_Available, Write => False, Length => File_Size (File_Length (Fd))); end Open_Read; ---------------- -- Open_Write -- ---------------- function Open_Write (Filename : String; Use_Mmap_If_Available : Boolean := True) return System_File is Fd : constant File_Descriptor := Open_Read_Write (Filename, Binary); begin if Fd = Invalid_FD then raise Ada.IO_Exceptions.Name_Error with "Cannot open " & Filename; end if; return (Fd => Fd, Mapped => Use_Mmap_If_Available and then Is_Mapping_Available, Write => True, Length => File_Size (File_Length (Fd))); end Open_Write; ----------- -- Close -- ----------- procedure Close (File : in out System_File) is begin Close (File.Fd); File.Fd := Invalid_FD; end Close; -------------------- -- Read_From_Disk -- -------------------- function Read_From_Disk (File : System_File; Offset, Length : File_Size) return GNAT.Strings.String_Access is Buffer : GNAT.Strings.String_Access := new String (1 .. Integer (Length)); begin -- ??? Lseek offset should be a size_t instead of a Long_Integer Lseek (File.Fd, Long_Integer (Offset), Seek_Set); if GNAT.OS_Lib.Read (File.Fd, Buffer.all'Address, Integer (Length)) /= Integer (Length) then GNAT.Strings.Free (Buffer); raise Ada.IO_Exceptions.Device_Error; end if; return Buffer; end Read_From_Disk; ------------------- -- Write_To_Disk -- ------------------- procedure Write_To_Disk (File : System_File; Offset, Length : File_Size; Buffer : GNAT.Strings.String_Access) is begin pragma Assert (File.Write); Lseek (File.Fd, Long_Integer (Offset), Seek_Set); if GNAT.OS_Lib.Write (File.Fd, Buffer.all'Address, Integer (Length)) /= Integer (Length) then raise Ada.IO_Exceptions.Device_Error; end if; end Write_To_Disk; -------------------- -- Create_Mapping -- -------------------- procedure Create_Mapping (File : System_File; Offset, Length : in out File_Size; Mutable : Boolean; Mapping : out System_Mapping; Advice : Use_Advice := Use_Normal) is Prot : Mmap_Prot; Flags : Mmap_Flags; begin if File.Write then Prot := PROT_READ or PROT_WRITE; Flags := MAP_SHARED; else Prot := PROT_READ; if Mutable then Prot := Prot or PROT_WRITE; end if; Flags := MAP_PRIVATE; end if; -- Adjust offset and mapping length to account for the required -- alignment of offset on page boundary. declare Queried_Offset : constant File_Size := Offset; begin Offset := Align (Offset); -- First extend the length to compensate the offset shift, then align -- it on the upper page boundary, so that the whole queried area is -- covered. Length := Length + Queried_Offset - Offset; Length := Align (Length + Get_Page_Size - 1); end; Mapping := (Address => Mmap (Offset => Offset, Length => Length, Prot => Prot, Flags => Flags, Fd => File.Fd), Length => Length); if Advice /= Use_Normal then Madvise (Mapping.Address, Length => 0, Advice => Advice); end if; end Create_Mapping; --------------------- -- Dispose_Mapping -- --------------------- procedure Dispose_Mapping (Mapping : in out System_Mapping) is Ignored : Integer; pragma Unreferenced (Ignored); begin Ignored := Munmap (Mapping.Address, Mapping.Length); Mapping := Invalid_System_Mapping; end Dispose_Mapping; -------------------------- -- Is_Mapping_Available -- -------------------------- function Is_Mapping_Available return Boolean is function Has_Mmap return Integer; pragma Import (C, Has_Mmap, "gnatcoll_has_mmap"); begin return Has_Mmap /= 0; end Is_Mapping_Available; ------------------- -- Get_Page_Size -- ------------------- function Get_Page_Size return File_Size is function Internal return Integer; pragma Import (C, Internal, "getpagesize"); begin return File_Size (Internal); end Get_Page_Size; ----------- -- Align -- ----------- function Align (Addr : File_Size) return File_Size is begin return Addr - Addr mod Get_Page_Size; end Align; end GNATCOLL.Mmap.System; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-mmap-system__unix.ads000066400000000000000000000103071425465243200250560ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2007-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with System; with GNAT.OS_Lib; -- OS pecularities abstraction package for Unix systems. package GNATCOLL.Mmap.System is type System_File is record Fd : GNAT.OS_Lib.File_Descriptor; Mapped : Boolean; -- Whether mapping is requested by the user and available on the system Write : Boolean; -- Whether this file can be written to Length : File_Size; -- Length of the file. Used to know what can be mapped in the file end record; type System_Mapping is record Address : Standard.System.Address; Length : File_Size; end record; Invalid_System_File : constant System_File := (GNAT.OS_Lib.Invalid_FD, False, False, 0); Invalid_System_Mapping : constant System_Mapping := (Standard.System.Null_Address, 0); function Open_Read (Filename : String; Use_Mmap_If_Available : Boolean := True) return System_File; -- Open a file for reading and return the corresponding System_File. Raise -- a Ada.IO_Exceptions.Name_Error if unsuccessful. function Open_Write (Filename : String; Use_Mmap_If_Available : Boolean := True) return System_File; -- Likewise for writing to a file procedure Close (File : in out System_File); -- Close a system file function Read_From_Disk (File : System_File; Offset, Length : File_Size) return GNAT.Strings.String_Access; -- Read a fragment of a file. It is up to the caller to free the result -- when done with it. -- Doesn't use mmap. procedure Write_To_Disk (File : System_File; Offset, Length : File_Size; Buffer : GNAT.Strings.String_Access); -- Write some content to a fragment of a file procedure Create_Mapping (File : System_File; Offset, Length : in out File_Size; Mutable : Boolean; Mapping : out System_Mapping; Advice : Use_Advice := Use_Normal); -- Create a memory mapping for the given File, for the area starting at -- Offset and containing Length bytes. Store it to Mapping. -- Note that Offset and Length may be modified according to the system -- needs (for boudaries, for instance). The caller must cope with actually -- wider mapped areas. procedure Dispose_Mapping (Mapping : in out System_Mapping); -- Unmap a previously-created mapping function Get_Page_Size return File_Size; -- Return the number of bytes in a system page. end GNATCOLL.Mmap.System; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-mmap-system__win32.adb000066400000000000000000000216431425465243200250210ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2007-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.IO_Exceptions; with System; use System; with GNAT.Strings; use GNAT.Strings; with GNATCOLL.IO.Native; use GNATCOLL.IO.Native; package body GNATCOLL.Mmap.System is use Win; function Align (Addr : File_Size) return File_Size; -- Align some offset/length to the lowest page boundary function Open_Common (Filename : String; Use_Mmap_If_Available : Boolean; Write : Boolean) return System_File; ----------------- -- Open_Common -- ----------------- function Open_Common (Filename : String; Use_Mmap_If_Available : Boolean; Write : Boolean) return System_File is dwDesiredAccess, dwShareMode : DWORD; PageFlags : DWORD; W_Filename : constant Wide_String := Codec.From_UTF8 (Filename) & Wide_Character'Val (0); File_Handle, Mapping_Handle : HANDLE; SizeH : aliased DWORD; Size : File_Size; begin if Write then dwDesiredAccess := GENERIC_READ + GENERIC_WRITE; dwShareMode := 0; PageFlags := Win.PAGE_READWRITE; else dwDesiredAccess := GENERIC_READ; dwShareMode := Win.FILE_SHARE_READ; PageFlags := Win.PAGE_READONLY; end if; -- Actually open the file File_Handle := CreateFile (W_Filename'Address, dwDesiredAccess, dwShareMode, null, OPEN_EXISTING, Win.FILE_ATTRIBUTE_NORMAL, 0); if File_Handle = Win.INVALID_HANDLE_VALUE then raise Ada.IO_Exceptions.Name_Error with "Cannot open " & Filename; end if; -- Compute its size Size := File_Size (Win.GetFileSize (File_Handle, SizeH'Access)); if Size = Win.INVALID_FILE_SIZE then raise Ada.IO_Exceptions.Use_Error; end if; if SizeH /= 0 and then File_Size'Size > 32 then Size := Size + (File_Size (SizeH) * 2 ** 32); end if; -- Then create a mapping object, if needed. On Win32, file memory -- mapping is always available. if Use_Mmap_If_Available then Mapping_Handle := Win.CreateFileMapping (File_Handle, null, PageFlags, 0, DWORD (Size), Standard.System.Null_Address); else Mapping_Handle := Win.INVALID_HANDLE_VALUE; end if; return (Handle => File_Handle, Mapped => Use_Mmap_If_Available, Mapping_Handle => Mapping_Handle, Write => Write, Length => Size); end Open_Common; --------------- -- Open_Read -- --------------- function Open_Read (Filename : String; Use_Mmap_If_Available : Boolean := True) return System_File is begin return Open_Common (Filename, Use_Mmap_If_Available, False); end Open_Read; ---------------- -- Open_Write -- ---------------- function Open_Write (Filename : String; Use_Mmap_If_Available : Boolean := True) return System_File is begin return Open_Common (Filename, Use_Mmap_If_Available, True); end Open_Write; ----------- -- Close -- ----------- procedure Close (File : in out System_File) is Ignored : BOOL; pragma Unreferenced (Ignored); begin Ignored := CloseHandle (File.Mapping_Handle); Ignored := CloseHandle (File.Handle); File.Handle := Win.INVALID_HANDLE_VALUE; File.Mapping_Handle := Win.INVALID_HANDLE_VALUE; end Close; -------------------- -- Read_From_Disk -- -------------------- function Read_From_Disk (File : System_File; Offset, Length : File_Size) return GNAT.Strings.String_Access is Buffer : String_Access := new String (1 .. Integer (Length)); Pos : DWORD; NbRead : aliased DWORD; pragma Unreferenced (Pos); begin Pos := Win.SetFilePointer (File.Handle, Win.LONG (Offset), null, Win.FILE_BEGIN); if Win.ReadFile (File.Handle, Buffer.all'Address, DWORD (Length), NbRead'Unchecked_Access, null) = Win.FALSE then GNAT.Strings.Free (Buffer); raise Ada.IO_Exceptions.Device_Error; end if; return Buffer; end Read_From_Disk; ------------------- -- Write_To_Disk -- ------------------- procedure Write_To_Disk (File : System_File; Offset, Length : File_Size; Buffer : GNAT.Strings.String_Access) is Pos : DWORD; NbWritten : aliased DWORD; pragma Unreferenced (Pos); begin pragma Assert (File.Write); Pos := Win.SetFilePointer (File.Handle, Win.LONG (Offset), null, Win.FILE_BEGIN); if Win.WriteFile (File.Handle, Buffer.all'Address, DWORD (Length), NbWritten'Unchecked_Access, null) = Win.FALSE then raise Ada.IO_Exceptions.Device_Error; end if; end Write_To_Disk; -------------------- -- Create_Mapping -- -------------------- procedure Create_Mapping (File : System_File; Offset, Length : in out File_Size; Mutable : Boolean; Mapping : out System_Mapping; Advice : Use_Advice := Use_Normal) is pragma Unreferenced (Advice); Flags : DWORD; begin if File.Write then Flags := Win.FILE_MAP_WRITE; elsif Mutable then Flags := Win.FILE_MAP_COPY; else Flags := Win.FILE_MAP_READ; end if; -- Adjust offset and mapping length to account for the required -- alignment of offset on page boundary. declare Queried_Offset : constant File_Size := Offset; begin Offset := Align (Offset); -- First extend the length to compensate the offset shift, then align -- it on the upper page boundary, so that the whole queried area is -- covered. Length := Length + Queried_Offset - Offset; Length := Align (Length + Get_Page_Size - 1); -- But do not exceed the length of the file if Offset + Length > File.Length then Length := File.Length - Offset; end if; end; Mapping := (Address => Win.MapViewOfFile (File.Mapping_Handle, Flags, 0, DWORD (Offset), SIZE_T (Length)), Length => Length); end Create_Mapping; --------------------- -- Dispose_Mapping -- --------------------- procedure Dispose_Mapping (Mapping : in out System_Mapping) is Ignored : BOOL; pragma Unreferenced (Ignored); begin Ignored := Win.UnmapViewOfFile (Mapping.Address); Mapping := Invalid_System_Mapping; end Dispose_Mapping; ------------------- -- Get_Page_Size -- ------------------- function Get_Page_Size return File_Size is SystemInfo : aliased SYSTEM_INFO; begin GetSystemInfo (SystemInfo'Unchecked_Access); return File_Size (SystemInfo.dwAllocationGranularity); end Get_Page_Size; ----------- -- Align -- ----------- function Align (Addr : File_Size) return File_Size is begin return Addr - Addr mod Get_Page_Size; end Align; end GNATCOLL.Mmap.System; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-mmap-system__win32.ads000066400000000000000000000221031425465243200250320ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2007-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with System; -- OS pecularities abstraction package for Win32 systems. package GNATCOLL.Mmap.System is -- The Win package contains copy of definition found in recent System.Win32 -- unit provided with the GNAT compiler. The copy is needed to be able to -- compile this unit with older compilers. Note that this internal Win -- package can be removed when GNAT 6.1.0 is not supported anymore. package Win is subtype PVOID is Standard.System.Address; type HANDLE is new Interfaces.C.ptrdiff_t; type WORD is new Interfaces.C.unsigned_short; type DWORD is new Interfaces.C.unsigned_long; type LONG is new Interfaces.C.long; type SIZE_T is new Interfaces.C.size_t; type BOOL is new Interfaces.C.int; for BOOL'Size use Interfaces.C.int'Size; FALSE : constant := 0; GENERIC_READ : constant := 16#80000000#; GENERIC_WRITE : constant := 16#40000000#; OPEN_EXISTING : constant := 3; type OVERLAPPED is record Internal : DWORD; InternalHigh : DWORD; Offset : DWORD; OffsetHigh : DWORD; hEvent : HANDLE; end record; type SECURITY_ATTRIBUTES is record nLength : DWORD; pSecurityDescriptor : PVOID; bInheritHandle : BOOL; end record; type SYSTEM_INFO is record dwOemId : DWORD; dwPageSize : DWORD; lpMinimumApplicationAddress : PVOID; lpMaximumApplicationAddress : PVOID; dwActiveProcessorMask : PVOID; dwNumberOfProcessors : DWORD; dwProcessorType : DWORD; dwAllocationGranularity : DWORD; wProcessorLevel : WORD; wProcessorRevision : WORD; end record; type LP_SYSTEM_INFO is access all SYSTEM_INFO; INVALID_HANDLE_VALUE : constant HANDLE := -1; FILE_BEGIN : constant := 0; FILE_SHARE_READ : constant := 16#00000001#; FILE_ATTRIBUTE_NORMAL : constant := 16#00000080#; FILE_MAP_COPY : constant := 1; FILE_MAP_READ : constant := 4; FILE_MAP_WRITE : constant := 2; PAGE_READONLY : constant := 16#0002#; PAGE_READWRITE : constant := 16#0004#; INVALID_FILE_SIZE : constant := 16#FFFFFFFF#; function CreateFile (lpFileName : Standard.System.Address; dwDesiredAccess : DWORD; dwShareMode : DWORD; lpSecurityAttributes : access SECURITY_ATTRIBUTES; dwCreationDisposition : DWORD; dwFlagsAndAttributes : DWORD; hTemplateFile : HANDLE) return HANDLE; pragma Import (Stdcall, CreateFile, "CreateFileW"); function WriteFile (hFile : HANDLE; lpBuffer : Standard.System.Address; nNumberOfBytesToWrite : DWORD; lpNumberOfBytesWritten : access DWORD; lpOverlapped : access OVERLAPPED) return BOOL; pragma Import (Stdcall, WriteFile, "WriteFile"); function ReadFile (hFile : HANDLE; lpBuffer : Standard.System.Address; nNumberOfBytesToRead : DWORD; lpNumberOfBytesRead : access DWORD; lpOverlapped : access OVERLAPPED) return BOOL; pragma Import (Stdcall, ReadFile, "ReadFile"); function CloseHandle (hObject : HANDLE) return BOOL; pragma Import (Stdcall, CloseHandle, "CloseHandle"); function GetFileSize (hFile : HANDLE; lpFileSizeHigh : access DWORD) return DWORD; pragma Import (Stdcall, GetFileSize, "GetFileSize"); function SetFilePointer (hFile : HANDLE; lDistanceToMove : LONG; lpDistanceToMoveHigh : access LONG; dwMoveMethod : DWORD) return DWORD; pragma Import (Stdcall, SetFilePointer, "SetFilePointer"); function CreateFileMapping (hFile : HANDLE; lpSecurityAttributes : access SECURITY_ATTRIBUTES; flProtect : DWORD; dwMaximumSizeHigh : DWORD; dwMaximumSizeLow : DWORD; lpName : Standard.System.Address) return HANDLE; pragma Import (Stdcall, CreateFileMapping, "CreateFileMappingW"); function MapViewOfFile (hFileMappingObject : HANDLE; dwDesiredAccess : DWORD; dwFileOffsetHigh : DWORD; dwFileOffsetLow : DWORD; dwNumberOfBytesToMap : SIZE_T) return Standard.System.Address; pragma Import (Stdcall, MapViewOfFile, "MapViewOfFile"); function UnmapViewOfFile (lpBaseAddress : Standard.System.Address) return BOOL; pragma Import (Stdcall, UnmapViewOfFile, "UnmapViewOfFile"); procedure GetSystemInfo (lpSystemInfo : LP_SYSTEM_INFO); pragma Import (Stdcall, GetSystemInfo, "GetSystemInfo"); end Win; type System_File is record Handle : Win.HANDLE; Mapped : Boolean; -- Whether mapping is requested by the user and available on the system Mapping_Handle : Win.HANDLE; Write : Boolean; -- Whether this file can be written to Length : File_Size; -- Length of the file. Used to know what can be mapped in the file end record; type System_Mapping is record Address : Standard.System.Address; Length : File_Size; end record; Invalid_System_File : constant System_File := (Win.INVALID_HANDLE_VALUE, False, Win.INVALID_HANDLE_VALUE, False, 0); Invalid_System_Mapping : constant System_Mapping := (Standard.System.Null_Address, 0); function Open_Read (Filename : String; Use_Mmap_If_Available : Boolean := True) return System_File; -- Open a file for reading and return the corresponding System_File. Raise -- a Ada.IO_Exceptions.Name_Error if unsuccessful. function Open_Write (Filename : String; Use_Mmap_If_Available : Boolean := True) return System_File; -- Likewise for writing to a file procedure Close (File : in out System_File); -- Close a system file function Read_From_Disk (File : System_File; Offset, Length : File_Size) return GNAT.Strings.String_Access; -- Read a fragment of a file. It is up to the caller to free the result -- when done with it. procedure Write_To_Disk (File : System_File; Offset, Length : File_Size; Buffer : GNAT.Strings.String_Access); -- Write some content to a fragment of a file procedure Create_Mapping (File : System_File; Offset, Length : in out File_Size; Mutable : Boolean; Mapping : out System_Mapping; Advice : Use_Advice := Use_Normal); -- Create a memory mapping for the given File, for the area starting at -- Offset and containing Length bytes. Store it to Mapping. -- Note that Offset and Length may be modified according to the system -- needs (for boudaries, for instance). The caller must cope with actually -- wider mapped areas. procedure Dispose_Mapping (Mapping : in out System_Mapping); -- Unmap a previously-created mapping function Get_Page_Size return File_Size; -- Return the number of bytes in a system page. end GNATCOLL.Mmap.System; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-mmap.adb000066400000000000000000000400431425465243200223110ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2007-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.IO_Exceptions; with Ada.Unchecked_Deallocation; with GNATCOLL.Mmap.System; use GNATCOLL.Mmap.System; with GNATCOLL.Strings; use GNATCOLL.Strings; with System; use System; with System.Storage_Elements; use System.Storage_Elements; package body GNATCOLL.Mmap is type Mapped_File_Record is record Current_Region : Mapped_Region; -- The legacy API enables only one region to be mapped, directly -- associated with the mapped file. This references this region. File : System_File; -- Underlying OS-level file end record; type Mapped_Region_Record is record File : Mapped_File; -- The file this region comes from. Be careful: for reading file, it is -- valid to have it closed before one of its regions is free'd. Write : Boolean; -- Whether the file this region comes from is open for writing. Data : Standard.System.Address := Standard.System.Null_Address; -- Unbounded access to the mapped content. System_Offset : File_Size; -- Position in the file of the first byte actually mapped in memory User_Offset : File_Size; -- Position in the file of the first byte requested by the user System_Size : File_Size; -- Size of the region actually mapped in memory User_Size : File_Size; -- Size of the region requested by the user Mapped : Boolean; -- Whether this region is actually memory mapped Mutable : Boolean; -- If the file is opened for reading, wheter this region is writable Buffer : GNAT.Strings.String_Access; -- When this region is not actually memory mapped, contains the -- requested bytes. Mapping : System_Mapping; -- Underlying OS-level data for the mapping, if any end record; Invalid_Mapped_Region_Record : constant Mapped_Region_Record := (null, False, Standard.System.Null_Address, 0, 0, 0, 0, False, False, null, Invalid_System_Mapping); Invalid_Mapped_File_Record : constant Mapped_File_Record := (Invalid_Mapped_Region, Invalid_System_File); Empty_String : constant String := ""; -- Used to provide a valid empty Data for empty files, for instanc. procedure Dispose is new Ada.Unchecked_Deallocation (Mapped_File_Record, Mapped_File); procedure Dispose is new Ada.Unchecked_Deallocation (Mapped_Region_Record, Mapped_Region); procedure Compute_Data (Region : Mapped_Region); -- Fill the Data field according to system and user offsets. The region -- must actually be mapped or bufferized. procedure From_Disk (Region : Mapped_Region); -- Read a region of some file from the disk. -- Doesn't use the mmap system call. procedure To_Disk (Region : Mapped_Region); -- Write the region of the file back to disk if necessary, and free memory --------------- -- Open_Read -- --------------- function Open_Read (Filename : String; Use_Mmap_If_Available : Boolean := True) return Mapped_File is File : constant System_File := Open_Read (Filename, Use_Mmap_If_Available); begin return new Mapped_File_Record' (Current_Region => Invalid_Mapped_Region, File => File); end Open_Read; ---------------- -- Open_Write -- ---------------- function Open_Write (Filename : String; Use_Mmap_If_Available : Boolean := True) return Mapped_File is File : constant System_File := Open_Write (Filename, Use_Mmap_If_Available); begin return new Mapped_File_Record' (Current_Region => Invalid_Mapped_Region, File => File); end Open_Write; ----------- -- Close -- ----------- procedure Close (File : in out Mapped_File) is begin -- Closing a closed file is allowed and should do nothing if File = Invalid_Mapped_File then return; end if; if File.Current_Region /= null then Free (File.Current_Region); end if; if File.File /= Invalid_System_File then Close (File.File); end if; Dispose (File); end Close; ---------- -- Free -- ---------- procedure Free (Region : in out Mapped_Region) is Ignored : Integer; pragma Unreferenced (Ignored); begin -- Freeing an already free'd file is allowed and should do nothing if Region = Invalid_Mapped_Region then return; end if; if Region.Mapping /= Invalid_System_Mapping then Dispose_Mapping (Region.Mapping); end if; To_Disk (Region); Dispose (Region); end Free; ---------- -- Read -- ---------- procedure Read (File : Mapped_File; Region : in out Mapped_Region; Offset : File_Size := 0; Length : File_Size := 0; Mutable : Boolean := False; Advice : Use_Advice := Use_Normal) is File_Length : constant File_Size := GNATCOLL.Mmap.Length (File); Req_Offset : constant File_Size := Offset; Req_Length : File_Size := Length; -- Offset and Length of the region to map, used to adjust mapping -- bounds, reflecting what the user will see. Region_Allocated : Boolean := False; begin -- If this region comes from another file, or simply if the file is -- writeable, we cannot re-use this mapping: free it first. if Region /= Invalid_Mapped_Region and then (Region.File /= File or else File.File.Write) then Free (Region); end if; if Region = Invalid_Mapped_Region then Region := new Mapped_Region_Record'(Invalid_Mapped_Region_Record); Region_Allocated := True; end if; Region.File := File; if Req_Offset >= File_Length then -- If the requested offset goes beyond file size, map nothing Req_Length := 0; elsif Length = 0 or else Length > File_Length - Req_Offset then -- If Length is 0 or goes beyond file size, map till end of file Req_Length := File_Length - Req_Offset; else Req_Length := Length; end if; -- Past this point, the offset/length the user will see is fixed. On the -- other hand, the system offset/length is either already defined, from -- a previous mapping, or it is set to 0. In the latter case, the next -- step will set them according to the mapping. Region.User_Offset := Req_Offset; Region.User_Size := Req_Length; -- If the requested region is inside an already mapped region, adjust -- user-requested data and do nothing else. if (File.File.Write or else Region.Mutable = Mutable) and then Req_Offset >= Region.System_Offset and then (Req_Offset + Req_Length <= Region.System_Offset + Region.System_Size) then Region.User_Offset := Req_Offset; Compute_Data (Region); return; elsif Region.Buffer /= null then -- Otherwise, as we are not going to re-use the buffer, free it GNAT.Strings.Free (Region.Buffer); Region.Buffer := null; elsif Region.Mapping /= Invalid_System_Mapping then -- Otherwise, there is a memory mapping that we need to unmap. Dispose_Mapping (Region.Mapping); end if; -- mmap() will sometimes return NULL when the file exists but is empty, -- which is not what we want, so in the case of a zero length file we -- fall back to read(2)/write(2)-based mode. if File_Length > 0 and then File.File.Mapped then Region.System_Offset := Req_Offset; Region.System_Size := Req_Length; Create_Mapping (File.File, Region.System_Offset, Region.System_Size, Mutable, Region.Mapping, Advice); Region.Mapped := True; Region.Mutable := Mutable; else -- There is no alignment requirement when manually reading the file. Region.System_Offset := Req_Offset; Region.System_Size := Req_Length; Region.Mapped := False; Region.Mutable := True; From_Disk (Region); end if; Region.Write := File.File.Write; Compute_Data (Region); exception when others => -- Before propagating any exception, free any region we allocated -- here. if Region_Allocated then Dispose (Region); end if; raise; end Read; ---------- -- Read -- ---------- procedure Read (File : Mapped_File; Offset : File_Size := 0; Length : File_Size := 0; Mutable : Boolean := False) is begin Read (File, File.Current_Region, Offset, Length, Mutable); end Read; ---------- -- Read -- ---------- function Read (File : Mapped_File; Offset : File_Size := 0; Length : File_Size := 0; Mutable : Boolean := False; Advice : Use_Advice := Use_Normal) return Mapped_Region is Region : Mapped_Region := Invalid_Mapped_Region; begin Read (File, Region, Offset, Length, Mutable, Advice); return Region; end Read; ------------ -- Length -- ------------ function Length (File : Mapped_File) return File_Size is begin return File.File.Length; end Length; ------------ -- Offset -- ------------ function Offset (Region : Mapped_Region) return File_Size is begin return Region.User_Offset; end Offset; ------------ -- Offset -- ------------ function Offset (File : Mapped_File) return File_Size is begin return Offset (File.Current_Region); end Offset; --------------- -- Data_Size -- --------------- function Data_Size (Region : Mapped_Region) return File_Size is begin return Region.User_Size; end Data_Size; --------------- -- Data_Size -- --------------- function Data_Size (File : Mapped_File) return File_Size is begin return Data_Size (File.Current_Region); end Data_Size; ------------------ -- Data_Address -- ------------------ function Data_Address (Region : Mapped_Region) return Standard.System.Address is begin return Region.Data; end Data_Address; ------------------ -- Data_Address -- ------------------ function Data_Address (File : Mapped_File) return Standard.System.Address is begin return Data_Address (File.Current_Region); end Data_Address; ---------------- -- Is_Mutable -- ---------------- function Is_Mutable (Region : Mapped_Region) return Boolean is begin return Region.Mutable or Region.Write; end Is_Mutable; ---------------- -- Is_Mmapped -- ---------------- function Is_Mmapped (File : Mapped_File) return Boolean is begin return File.File.Mapped; end Is_Mmapped; ------------------- -- Get_Page_Size -- ------------------- function Get_Page_Size return Positive is Result : constant File_Size := Get_Page_Size; begin return Positive (Result); end Get_Page_Size; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (Filename : String; Empty_If_Not_Found : Boolean := False) return GNAT.Strings.String_Access is File : Mapped_File := Open_Read (Filename); Region : Mapped_Region renames File.Current_Region; Result : String_Access; begin Read (File); if Region.Data /= Standard.System.Null_Address then Result := new String' (String (Data (Region) (1 .. Integer (Last (Region))))); elsif Region.Buffer /= null then Result := Region.Buffer; Region.Buffer := null; -- So that it is not deallocated end if; Close (File); return Result; exception when Ada.IO_Exceptions.Name_Error => if Empty_If_Not_Found then return new String'(""); else return null; end if; when others => Close (File); return null; end Read_Whole_File; --------------------- -- Read_Whole_File -- --------------------- function Read_Whole_File (Filename : String) return GNATCOLL.Strings.XString is File : Mapped_File := Open_Read (Filename); Region : Mapped_Region renames File.Current_Region; Result : XString; begin Read (File); if Region.Data /= Standard.System.Null_Address then Result.Set (String (Data (Region) (1 .. Last (Region)))); elsif Region.Buffer /= null then Result.Set (Region.Buffer.all); end if; Close (File); return Result; exception when Ada.IO_Exceptions.Name_Error => return GNATCOLL.Strings.Null_XString; when others => Close (File); return GNATCOLL.Strings.Null_XString; end Read_Whole_File; --------------- -- From_Disk -- --------------- procedure From_Disk (Region : Mapped_Region) is begin pragma Assert (Region.File.all /= Invalid_Mapped_File_Record); pragma Assert (Region.Buffer = null); Region.Buffer := Read_From_Disk (Region.File.File, Region.User_Offset, Region.User_Size); Region.Mapped := False; end From_Disk; ------------- -- To_Disk -- ------------- procedure To_Disk (Region : Mapped_Region) is begin if Region.Write and then Region.Buffer /= null then pragma Assert (Region.File.all /= Invalid_Mapped_File_Record); Write_To_Disk (Region.File.File, Region.User_Offset, Region.User_Size, Region.Buffer); end if; GNAT.Strings.Free (Region.Buffer); Region.Buffer := null; end To_Disk; ------------------ -- Compute_Data -- ------------------ procedure Compute_Data (Region : Mapped_Region) is Data_Shift : constant Storage_Offset := Storage_Offset (Region.User_Offset - Region.System_Offset); begin if Region.User_Size = 0 then Region.Data := Empty_String'Address; elsif Region.Mapped then Region.Data := Region.Mapping.Address + Data_Shift; else Region.Data := Region.Buffer.all'Address + Data_Shift; end if; end Compute_Data; end GNATCOLL.Mmap; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-mmap.ads000066400000000000000000000436351425465243200223440ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2007-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides memory mapping of files. Depending on your operating -- system, this might provide a more efficient method for accessing the -- contents of files. -- A description of memory-mapping is available on the sqlite page, at: -- http://www.sqlite.org/mmap.html -- -- The traditional method for reading a file is to allocate a buffer in the -- application address space, then open the file and copy its contents. When -- memory mapping is available though, the application asks the operating -- system to return a pointer to the requested page, if possible. If the -- requested page has been or can be mapped into the application address -- space, the system returns a pointer to that page for the application to -- use without having to copy anything. Skipping the copy step is what makes -- memory mapped I/O faster. -- -- When memory mapping is not available, this package automatically falls -- back to the traditional copy method. -- -- Example of use for this package, when reading a file that can be fully -- mapped -- -- declare -- File : Mapped_File; -- Str : Str_Access; -- begin -- File := Open_Read ("/tmp/file_on_disk"); -- Read (File); -- read the whole file -- Str := Data (File); -- for S in 1 .. Last (File) loop -- Put (Str (S)); -- end loop; -- Close (File); -- end; -- -- When the file is big, or you only want to access part of it at a given -- time, you can use the following type of code. -- declare -- File : Mapped_File; -- Str : Str_Access; -- Offs : File_Size := 0; -- Page : constant Integer := Get_Page_Size; -- begin -- File := Open_Read ("/tmp/file_on_disk"); -- while Offs < Length (File) loop -- Read (File, Offs, Length => Long_Integer (Page) * 4); -- Str := Data (File); -- -- -- Print characters for this chunk: -- for S in Integer (Offs - Offset (File)) + 1 .. Last (File) loop -- Put (Str (S)); -- end loop; -- -- -- Since we are reading multiples of Get_Page_Size, we can simplify -- -- with -- -- for S in 1 .. Last (File) loop ... -- -- Offs := Offs + Long_Integer (Last (File)); -- end loop; with Ada.Unchecked_Conversion; with Interfaces.C; with GNAT.Strings; use GNAT.Strings; with GNATCOLL.Strings; with System; package GNATCOLL.Mmap is type Mapped_File is private; -- File to be mapped in memory. -- This package will use the fastest possible algorithm to load the -- file in memory. On systems that support it, the file is not really -- loaded in memory. Instead, a call to the mmap() system call (or -- CreateFileMapping()) will keep the file on disk, but make it -- accessible as if it was in memory. -- When the system does not support it, the file is actually loaded in -- memory through calls to read(), and written back with write() when you -- close it. This is of course much slower. -- Legacy: each mapped file has a "default" mapped region in it. type Mapped_Region is private; -- A representation of part of a file in memory. Actual reading/writing -- is done through a mapped region. After being returned by Read, a mapped -- region must be free'd when done. If the original Mapped_File was open -- for reading, it can be closed before the mapped region is free'd. Invalid_Mapped_File : constant Mapped_File; Invalid_Mapped_Region : constant Mapped_Region; type File_Size is new Interfaces.C.size_t; function Open_Read (Filename : String; Use_Mmap_If_Available : Boolean := True) return Mapped_File; -- Open a file for reading. The same file can be shared by multiple -- processes, that will see each others's changes as they occur. -- Any attempt to write the data might result in a segmentation fault, -- depending on how the file is open. -- Name_Error is raised if the file does not exist. -- Filename should be compatible with the filesystem. function Open_Write (Filename : String; Use_Mmap_If_Available : Boolean := True) return Mapped_File; -- Open a file for writing. -- You cannot change the length of the file. -- Name_Error is raised if the file does not exist -- Filename should be compatible with the filesystem. procedure Close (File : in out Mapped_File); -- Close the file, and unmap the memory that is used for the region -- contained in File. If the system does not support the unmmap() system -- call or equivalent, or these were not available for the file itself, -- then the file is written back to the disk if it was opened for writing. procedure Free (Region : in out Mapped_Region); -- Unmap the memory that is used for this region and deallocate the region type Use_Advice is (Use_Normal, Use_Random, Use_Sequential); for Use_Advice use (Use_Normal => 1, Use_Random => 2, Use_Sequential => 4); -- This type can be used to provide advice to some operation systems on -- how a mapped page will be used. -- -- If you specify Use_Sequential, you are telling the system that the -- contents of the page will be read sequentially from lower to higher -- address, and therefore the system should use prefetching aggressively. -- -- If you specify Use_Random, the page will be accessed in a -- non-sequential manner. -- -- This advice might be ignored by the system (depending on whether the -- madvise() system call is supported). It will always be ignored for -- systems that do not support mmap. procedure Read (File : Mapped_File; Region : in out Mapped_Region; Offset : File_Size := 0; Length : File_Size := 0; Mutable : Boolean := False; Advice : Use_Advice := Use_Normal); -- Read a specific part of File and set Region to the corresponding mapped -- region, or re-use it if possible. -- Offset is the number of bytes since the beginning of the file at which -- we should start reading. Length is the number of bytes that should be -- read. If set to 0, as much of the file as possible is read (presumably -- the whole file unless you are reading a _huge_ file). -- Note that no (un)mapping is is done if that part of the file is already -- available through Region. -- If the file was opened for writing, any modification you do to the -- data stored in File will be stored on disk (either immediately when the -- file is opened through a mmap() system call, or when the file is closed -- otherwise). -- Mutable is processed only for reading files. If set to True, the -- data can be modified, even through it will not be carried through the -- underlying file, nor it is guaranteed to be carried through remapping. -- This function takes care of page size alignment issues. The accessors -- below only expose the region that has been requested by this call, even -- if more bytes were actually mapped by this function. -- -- TODO??? Enable to have a private copy for readable files -- -- Operating systems generally limit the number of open file descriptors -- that an application can have at one time (typically 1024 or 2048). -- They however often have a much higher limit on the number of mapped -- regions (65535 for instance). If you hitting the first limit, you -- could use the following workflow: -- -- File := Open_Read ("filename.txt"); -- Region := Read (File); -- Close (File); -- release the file descriptor -- ... -- Free (Region); -- release the mapped file function Read (File : Mapped_File; Offset : File_Size := 0; Length : File_Size := 0; Mutable : Boolean := False; Advice : Use_Advice := Use_Normal) return Mapped_Region; -- Likewise, return a new mapped region procedure Read (File : Mapped_File; Offset : File_Size := 0; Length : File_Size := 0; Mutable : Boolean := False) with Obsolescent; -- Likewise, use the legacy "default" region in File function Length (File : Mapped_File) return File_Size with Inline; -- Size of the file on the disk function Offset (Region : Mapped_Region) return File_Size with Inline; -- Return the offset, in the physical file on disk, corresponding to the -- requested mapped region. The first byte in the file has offest 0. function Offset (File : Mapped_File) return File_Size with Inline, Obsolescent; -- Likewise for the region contained in File function Data_Address (Region : Mapped_Region) return System.Address with Inline; function Data_Address (File : Mapped_File) return System.Address with Inline, Obsolescent; -- Return the address of the internal buffer. -- Do not use this function directly, but via an instance of the -- package Data_Getters below. function Data_Size (Region : Mapped_Region) return File_Size with Inline; function Data_Size (File : Mapped_File) return File_Size with Inline, Obsolescent; -- Full size of the mapped region. -- Better to use one of the instances of Data_Getters instead. generic type Index_Type is range <>; -- The type of indexes used when mapping the file to memory. -- Typical values are 'Positive' when you want to read files less than -- 2Gb in size, although you might want to use -- System.Storage_Elements.Storage_Offset or Long_Long_Integer on -- 64 bits system supporting the mmap system call (which will allow -- you to manipulate Petabytes files...) type Base_Unconstrained_String is array (Index_Type range <>) of Character; -- How is memory represented. -- For small strings, it is recommended to use the String type -- directly for ease of use for the user. package Data_Getters is pragma Compile_Time_Error (Index_Type'First /= 1, "Wrong index type"); subtype Extended_Index_Type is Index_Type'Base range 0 .. Index_Type'Last; subtype Unconstrained_String is Base_Unconstrained_String (Index_Type); type Str_Access is access all Unconstrained_String; pragma No_Strict_Aliasing (Str_Access); -- We do not use a String, which would limit the index to Integer and -- not allow us to load files larger than 2Gb. -- We also do not systematically use a -- System.Storage_Elements.Storage_Array, since it is easier for users -- if we directly have Character elements rather than Storage_Element. function Convert is new Ada.Unchecked_Conversion (System.Address, Str_Access); function To_Str_Access (Str : GNAT.Strings.String_Access) return Str_Access is (if Str = null then null else Convert (Str.all'Address)); -- Convert Str. The returned value points to the same memory block, -- but no longer includes the bounds, which you need to manage yourself function Last (Region : Mapped_Region) return Extended_Index_Type is (Extended_Index_Type (Data_Size (Region))); -- Return the number of requested bytes mapped in this region. It is -- erroneous to access Data for indices outside 1 .. Last (Region). -- Such accesses may cause Storage_Error to be raised. -- -- A constraint error is raised if the size of the region is larger -- than can be represented by Index_Type. So you need to pass a -- compatible Length parameter in your call to Open_Read. function Last (File : Mapped_File) return Extended_Index_Type is (Extended_Index_Type (Data_Size (File))) with Obsolescent; -- Return the number of requested bytes mapped in the region contained -- in File. It is erroneous to access Data for indices outside -- of 1 .. Last (File); such accesses may cause Storage_Error to -- be raised. function Data (Region : Mapped_Region) return Str_Access is (Convert (Data_Address (Region))); -- The data mapped in Region as requested. The result is an -- unconstrained string, so you cannot use the usual 'First and -- 'Last attributes. Instead, these are respectively 1 and Size. function Data (File : Mapped_File) return Str_Access is (Convert (Data_Address (File))) with Obsolescent; -- Likewise for the region contained in File end Data_Getters; package Short is new Data_Getters (Positive, String); -- This package can be used when mapping files less than 2Gb. -- A range of the result of Data can be converted to a String, as in: -- S : constant String := String (Data (Region) (1 .. Last (Region))); subtype Long_Index is Long_Long_Integer range 1 .. Long_Long_Integer'Last; type Large_Unconstrained_String is array (Long_Index range <>) of Character; package Long is new Data_Getters (Long_Index, Large_Unconstrained_String); -- This package can be used when mapping files up to a petabyte. -- The whole data cannot be represented as a single string, so you'll -- need to iterate on it. subtype Str_Access is Short.Str_Access; function "=" (Left, Right : Str_Access) return Boolean renames Short."="; function Last (Region : Mapped_Region) return Positive renames Short.Last; function Last (File : Mapped_File) return Positive renames Short.Last; function Data (Region : Mapped_Region) return Str_Access renames Short.Data; function Data (File : Mapped_File) return Str_Access renames Short.Data; -- Convenient renamings, for backward compatibility. -- These functions only work for files up to 2Gb. For larger sizes, -- you should use Long.Str_Access, Long.Last and Long.Data instead. function Is_Mutable (Region : Mapped_Region) return Boolean; -- Return whether it is safe to change bytes in Data (Region). This is true -- for regions from writeable files, for regions mapped with the "Mutable" -- flag set, and for regions that are copied in a buffer. Note that it is -- not specified whether empty regions are mutable or not, since there is -- no byte no modify. function Is_Mmapped (File : Mapped_File) return Boolean with Inline; -- Whether regions for this file are opened through an mmap() system call -- or equivalent. This is in general irrelevant to your application, unless -- the file can be accessed by multiple concurrent processes or tasks. In -- such a case, and if the file is indeed mmap-ed, then the various parts -- of the file can be written simulatenously, and thus you cannot ensure -- the integrity of the file. If the file is not mmapped, the latest -- process to Close it overwrite what other processes have done. function Get_Page_Size return Positive; -- Returns the number of bytes in a page. Once a file is mapped from the -- disk, its offset and Length should be multiples of this page size (which -- is ensured by this package in any case). Knowing this page size allows -- you to map as much memory as possible at once, thus potentially reducing -- the number of system calls to read the file by chunks. function Read_Whole_File (Filename : String; Empty_If_Not_Found : Boolean := False) return GNAT.Strings.String_Access; function Read_Whole_File (Filename : String) return GNATCOLL.Strings.XString; -- Returns the whole contents of the file. -- The returned string must be freed by the user. -- This is a convenience function, which is of course slower than the ones -- above since we also need to allocate some memory, actually read the file -- and copy the bytes. -- If the file does not exist, null is returned. However, if -- Empty_If_Not_Found is True, then the empty string is returned instead. -- Filename should be compatible with the filesystem. -- -- This function only works for files smaller than 2Gb. private type Mapped_File_Record; type Mapped_File is access Mapped_File_Record; type Mapped_Region_Record; type Mapped_Region is access Mapped_Region_Record; Invalid_Mapped_File : constant Mapped_File := null; Invalid_Mapped_Region : constant Mapped_Region := null; end GNATCOLL.Mmap; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-os-constants__osx.ads000066400000000000000000000056231425465243200250700ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L . O S . C O N S T A N T S -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This is the MacOS version of GNATCOLL.OS.Constants package package GNATCOLL.OS.Constants is pragma Pure; ----------------------- -- OS identification -- ----------------------- OS : constant OS_Type := MacOS; ------------------------------------- -- File system specific constants -- ------------------------------------- Dir_Sep : constant Character := '/'; -- The character that separates qualified filename components Path_Sep : constant Character := ':'; -- The character that separates paths in a path list Exe_Ext : constant String := ""; -- Executable image extension Default_Casing_Policy : constant Filename_Casing_Policy := Preserving; -- Default casing policy chosen by the OS ------------------------------------------------ -- Dynamic link libraries specific constants -- ------------------------------------------------ DLL_Name : constant String := "shared library"; -- The OS-specific term to refer to a DLL DLL_Search_Path_Var : constant String := "DYLD_LIBRARY_PATH"; -- Environment variable used to search for DLLs DLL_Ext : constant String := ".dylib"; -- DLL image extension end GNATCOLL.OS.Constants; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-os-constants__unix.ads000066400000000000000000000056131425465243200252410ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L . O S . C O N S T A N T S -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This is the Unix version of GNATCOLL.OS.Constants package package GNATCOLL.OS.Constants is pragma Pure; ----------------------- -- OS identification -- ----------------------- OS : constant OS_Type := Unix; ------------------------------------- -- File system specific constants -- ------------------------------------- Dir_Sep : constant Character := '/'; -- The character that separates qualified filename components Path_Sep : constant Character := ':'; -- The character that separates paths in a path list Exe_Ext : constant String := ""; -- Executable image extension Default_Casing_Policy : constant Filename_Casing_Policy := Sensitive; -- Default casing policy chosen by the OS ------------------------------------------------ -- Dynamic link libraries specific constants -- ------------------------------------------------ DLL_Name : constant String := "shared library"; -- The OS-specific term to refer to a DLL DLL_Search_Path_Var : constant String := "LD_LIBRARY_PATH"; -- Environment variable used to search for DLLs DLL_Ext : constant String := ".so"; -- DLL image extension end GNATCOLL.OS.Constants; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-os-constants__windows.ads000066400000000000000000000056011425465243200257450ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L . O S . C O N S T A N T S -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This is the Windows version of GNATCOLL.OS.Constants package package GNATCOLL.OS.Constants is pragma Pure; ----------------------- -- OS identification -- ----------------------- OS : constant OS_Type := Windows; ------------------------------------- -- File system specific constants -- ------------------------------------- Dir_Sep : constant Character := '\'; -- The character that separates qualified filename components Path_Sep : constant Character := ';'; -- The character that separates paths in a path list Exe_Ext : constant String := ".exe"; -- Executable image extension Default_Casing_Policy : constant Filename_Casing_Policy := Preserving; -- Default casing policy chosen by the OS ------------------------------------------------ -- Dynamic link libraries specific constants -- ------------------------------------------------ DLL_Name : constant String := "DLL"; -- The OS-specific term to refer to a DLL DLL_Search_Path_Var : constant String := "PATH"; -- Environment variable used to search for DLLs DLL_Ext : constant String := ".dll"; -- DLL image extension end GNATCOLL.OS.Constants; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-os.ads000066400000000000000000000043041425465243200220210ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L . O S -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ package GNATCOLL.OS is pragma Pure; -- Supported OS types type OS_Type is (Windows, Unix, MacOS); -- The filename resolution policy of a given file system type Filename_Casing_Policy is ( Lower_Case, -- case insensitive file system, normalized lower case Upper_Case, -- case insensitive file system, normalized upper case Preserving, -- case insensitive file system, case is preserved Sensitive -- case sensitive file system ); end GNATCOLL.OS; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-path.adb000066400000000000000000000452131425465243200223170ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Characters.Handling; use Ada.Characters.Handling; with GNAT.OS_Lib; use GNAT.OS_Lib; package body GNATCOLL.Path is function Dir_Separator (FS : FS_Type) return Character; -- return '/' or '\' depending of FS ------------------- -- Dir_Separator -- ------------------- function Dir_Separator (FS : FS_Type) return Character is begin case FS is when FS_Unix | FS_Unix_Case_Insensitive => return '/'; when FS_Windows => return '\'; when FS_Unknown => raise Invalid_Filesystem; end case; end Dir_Separator; function Internal_Local_FS return FS_Type; -- We cache this value as it is very often referenced... and is -- a constant ! ----------------------- -- Internal_Local_FS -- ----------------------- function Internal_Local_FS return FS_Type is function Get_File_Names_Case_Sensitive return Integer; pragma Import (C, Get_File_Names_Case_Sensitive, "__gnat_get_file_names_case_sensitive"); begin if GNAT.OS_Lib.Directory_Separator = '\' then return FS_Windows; else if Get_File_Names_Case_Sensitive = 0 then return FS_Unix_Case_Insensitive; else return FS_Unix; end if; end if; end Internal_Local_FS; Loc_FS : constant FS_Type := Internal_Local_FS; -------------- -- Local_FS -- -------------- function Local_FS return FS_Type is begin return Loc_FS; end Local_FS; ----------------------- -- Is_Case_Sensitive -- ----------------------- function Is_Case_Sensitive (FS : FS_Type) return Boolean is begin case FS is when FS_Unix => return True; when FS_Windows | FS_Unix_Case_Insensitive => return False; when FS_Unknown => raise Invalid_Filesystem; end case; end Is_Case_Sensitive; ----------------- -- Has_Devices -- ----------------- function Has_Devices (FS : FS_Type) return Boolean is begin case FS is when FS_Unix | FS_Unix_Case_Insensitive => return False; when FS_Windows => return True; when FS_Unknown => raise Invalid_Filesystem; end case; end Has_Devices; --------------------------- -- Multi_Unit_Index_Char -- --------------------------- function Multi_Unit_Index_Char (FS : FS_Type) return Character is pragma Unreferenced (FS); begin return '~'; end Multi_Unit_Index_Char; ------------------- -- Exe_Extension -- ------------------- function Exe_Extension (FS : FS_Type) return FS_String is begin case FS is when FS_Unix | FS_Unix_Case_Insensitive => return ""; when FS_Windows => return ".exe"; when FS_Unknown => raise Invalid_Filesystem; end case; end Exe_Extension; -------------- -- Get_Root -- -------------- function Get_Root (FS : FS_Type; Path : FS_String) return FS_String is Found_One : Boolean; begin case FS is when FS_Unix | FS_Unix_Case_Insensitive => return "/"; when FS_Windows => if Path'Length >= 2 and then Path (Path'First + 1) = ':' then return Path (Path'First) & ":\"; elsif Path'Length > 3 and then Path (Path'First .. Path'First + 1) = "\\" then -- We need to return "\\machine\svc\" in this case Found_One := False; -- Used to determine that we found at least one -- '\' after the initial "\\" for J in Path'First + 2 .. Path'Last loop if Path (J) = '\' then if not Found_One then Found_One := True; else return Path (Path'First .. J); end if; end if; end loop; if Found_One then -- Case where we had "\\machine\svc" to analyse. The root -- is then "\\machine\src\" return Path & '\'; else -- Incomplete ... return the default return "\"; end if; else return "\"; end if; when FS_Unknown => raise Invalid_Filesystem; end case; end Get_Root; ---------------------- -- Is_Absolute_Path -- ---------------------- function Is_Absolute_Path (FS : FS_Type; Path : FS_String) return Boolean is begin if Path'Length = 0 then return False; end if; case FS is when FS_Unix | FS_Unix_Case_Insensitive => return Path (Path'First) = '/'; when FS_Windows => if Path'Length >= 3 and then Path (Path'First + 1 .. Path'First + 2) = ":\" then return True; elsif Path'Length > 1 and then (Path (Path'First) = '\' or else Path (Path'First) = '/') then return True; end if; when FS_Unknown => raise Invalid_Filesystem; end case; return False; end Is_Absolute_Path; ---------- -- Path -- ---------- function Path (FS : FS_Type; Device : FS_String; Dir : FS_String; File : FS_String) return FS_String is Has_Dirsep : constant Boolean := Dir'Length >= 1 and then Dir (Dir'Last) = Dir_Separator (FS); begin if FS = FS_Unknown then raise Invalid_Filesystem; end if; if FS in FS_Unix .. FS_Unix_Case_Insensitive or else Device = "" then if Has_Dirsep then return Dir & From_Unix (FS, File); else return Dir & Dir_Separator (FS) & From_Unix (FS, File); end if; else if Has_Dirsep then return Device & ":" & Dir & From_Unix (FS, File); else return Device & ":" & Dir & Dir_Separator (FS) & From_Unix (FS, File); end if; end if; end Path; ----------- -- Equal -- ----------- function Equal (FS : FS_Type; Path1, Path2 : FS_String) return Boolean is function Internal (S1, S2 : FS_String) return Boolean; -- Compare, taking care of trailing dir separators -------------- -- Internal -- -------------- function Internal (S1, S2 : FS_String) return Boolean is begin return S1 = S2 or else (S2'Length > 0 and then S2 (S2'Last) = Dir_Separator (FS) and then S1 = S2 (S2'First .. S2'Last - 1)) or else (S1'Length > 0 and then S1 (S1'Last) = Dir_Separator (FS) and then S2 = S1 (S1'First .. S1'Last - 1)); end Internal; begin if Is_Case_Sensitive (FS) then return Internal (Path1, Path2); else return Internal (FS_String (To_Lower (String (Path1))), FS_String (To_Lower (String (Path2)))); end if; end Equal; ------------- -- To_Unix -- ------------- function To_Unix (FS : FS_Type; Path : FS_String; Cygwin_Path : Boolean := False) return FS_String is begin case FS is when FS_Unix | FS_Unix_Case_Insensitive => return Path; when FS_Windows => declare Ret : FS_String := Path; begin for J in Ret'Range loop if Ret (J) = '\' then Ret (J) := '/'; end if; end loop; if Cygwin_Path and then Ret'Length > 2 and then Ret (Ret'First + 1) = ':' then return "/cygdrive/" & Ret (Ret'First) & Ret (Ret'First + 2 .. Ret'Last); else return Ret; end if; end; when FS_Unknown => raise Invalid_Filesystem; end case; end To_Unix; --------------- -- From_Unix -- --------------- function From_Unix (FS : FS_Type; Path : FS_String) return FS_String is begin case FS is when FS_Unix | FS_Unix_Case_Insensitive => return Path; when FS_Windows => declare Ret : FS_String := Path; begin for J in Ret'Range loop if Ret (J) = '/' then Ret (J) := '\'; end if; end loop; if Ret'Length >= 11 -- "/cygdrive/X"'Length and then Ret (Ret'First .. Ret'First + 9) = "\cygdrive\" then return Ret (Ret'First + 10) & ":" & Ret (Ret'First + 11 .. Ret'Last); else return Ret; end if; end; when FS_Unknown => raise Invalid_Filesystem; end case; end From_Unix; -------------------- -- File_Extension -- -------------------- function File_Extension (FS : FS_Type; Path : FS_String) return FS_String is begin for J in reverse Path'Range loop if Path (J) = '.' then case FS is when FS_Unix | FS_Unix_Case_Insensitive => return Path (J .. Path'Last); when FS_Windows => return FS_String (To_Lower (String (Path (J .. Path'Last)))); when FS_Unknown => raise Invalid_Filesystem; end case; end if; end loop; return ""; end File_Extension; --------------- -- Base_Name -- --------------- function Base_Name (FS : FS_Type; Path : FS_String; Suffix : FS_String := "") return FS_String is begin for J in reverse Path'Range loop if Path (J) = Dir_Separator (FS) then if Path'Last - J < Suffix'Length or else Path (Path'Last - Suffix'Length + 1 .. Path'Last) /= Suffix then return Path (J + 1 .. Path'Last); else return Path (J + 1 .. Path'Last - Suffix'Length); end if; end if; end loop; return Path; end Base_Name; ------------------- -- Base_Dir_Name -- ------------------- function Base_Dir_Name (FS : FS_Type; Path : FS_String) return FS_String is Root : constant FS_String := Get_Root (FS, Path); begin if Path = Root then return Path; elsif Path (Path'Last) = Dir_Separator (FS) then return Base_Name (FS, Path (Path'First .. Path'Last - 1)); else return Base_Name (FS, Path); end if; end Base_Dir_Name; -------------- -- Dir_Name -- -------------- function Dir_Name (FS : FS_Type; Path : FS_String) return FS_String is Root : constant FS_String := Get_Root (FS, Path); begin if Root'Length > Path'Length then return ""; end if; for J in reverse Path'Range loop if Path (J) = Dir_Separator (FS) then return Path (Path'First .. J); end if; end loop; return Path; end Dir_Name; ---------------- -- Get_Parent -- ---------------- function Get_Parent (FS : FS_Type; Path : FS_String) return FS_String is begin if not Is_Dir_Name (FS, Path) then return Dir_Name (FS, Path); else return Dir_Name (FS, Path (Path'First .. Path'Last - 1)); end if; end Get_Parent; ----------------- -- Is_Dir_Name -- ----------------- function Is_Dir_Name (FS : FS_Type; Path : FS_String) return Boolean is begin return Path'Length > 0 and then Path (Path'Last) = Dir_Separator (FS); end Is_Dir_Name; ---------------------- -- Ensure_Directory -- ---------------------- function Ensure_Directory (FS : FS_Type; Path : FS_String) return FS_String is begin if not Is_Dir_Name (FS, Path) then return Path & Dir_Separator (FS); else return Path; end if; end Ensure_Directory; ----------------- -- Device_Name -- ----------------- function Device_Name (FS : FS_Type; Path : FS_String) return FS_String is begin if FS = FS_Windows and then Path'Length > 2 and then Path (Path'First + 1) = ':' then return "" & Path (Path'First); else return ""; end if; end Device_Name; --------------- -- Normalize -- --------------- function Normalize (FS : FS_Type; Path : FS_String) return FS_String is Dest : FS_String := Path; Src : Natural := Path'First; Idx : Natural := Dest'First; Tmp : Natural; DS : Character renames Dir_Separator (FS); begin while Src <= Path'Last loop if Idx > Dest'First and then Dest (Idx - 1) = DS then if Path (Src) = '.' then -- Skip when the "directory" is just "." if Src >= Path'Last or else Path (Src + 1) = DS then Src := Src + 2; elsif Path (Src + 1) = '.' then -- The "directory" part is ".." (not followed by a name). -- Insert ".." if we are at beginning of string. if Src + 1 >= Path'Last or else Path (Src + 2) = DS then -- Need to remove the previous directory name, unless -- it itself was a ".." that could not be normalized -- because it was at the beginning of the string. Tmp := Idx - 2; while Tmp >= Dest'First and then Dest (Tmp) /= DS loop Tmp := Tmp - 1; end loop; if Dest (Tmp + 1 .. Idx - 2) /= ".." then Idx := Tmp + 1; Src := Src + 3; -- Skip "../" else Dest (Idx) := '.'; Dest (Idx + 1) := '.'; Idx := Idx + 2; Src := Src + 2; -- Skip ".." end if; -- A name that starts with ".." else Dest (Idx) := '.'; Dest (Idx + 1) := '.'; Idx := Idx + 2; Src := Src + 2; end if; else Dest (Idx) := Path (Src); Idx := Idx + 1; Src := Src + 1; end if; else Dest (Idx) := Path (Src); Idx := Idx + 1; Src := Src + 1; end if; else Dest (Idx) := Path (Src); Idx := Idx + 1; Src := Src + 1; end if; end loop; return Dest (Dest'First .. Idx - 1); end Normalize; ------------------- -- Relative_Path -- ------------------- function Relative_Path (FS : FS_Type; Ref : FS_String; Path : FS_String) return FS_String is Depth : Natural := 0; Last : Natural := Ref'Last; Old : Natural; function Depth_Image return FS_String; -- Return "../" * Depth ----------------- -- Depth_Image -- ----------------- function Depth_Image return FS_String is Ret : FS_String (1 .. 3 * Depth); Sep : constant FS_String := ".." & Dir_Separator (FS); begin for J in 1 .. Depth loop Ret (J * 3 - 2 .. J * 3) := Sep; end loop; return Ret; end Depth_Image; begin -- If roots are not identical, then this means that we need to return -- the file's full name. if not Equal (FS, Get_Root (FS, Ref), Get_Root (FS, Path)) then return Path; end if; if Equal (FS, Ref, Path) then return "."; end if; loop exit when Last - Ref'First + 1 <= Path'Length and then Equal (FS, Path (Path'First .. Path'First + Last - Ref'First), Ref (Ref'First .. Last)); Old := Last; for J in reverse Ref'First .. Last - 1 loop if Ref (J) = Dir_Separator (FS) then Depth := Depth + 1; Last := J; exit; end if; end loop; if Old = Last then -- No Dir_Separator in Ref... Let's return Path return Path; end if; end loop; return Depth_Image & Path (Path'First + Last - Ref'First + 1 .. Path'Last); end Relative_Path; end GNATCOLL.Path; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-path.ads000066400000000000000000000130161425465243200223340ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.VFS_Types; use GNATCOLL.VFS_Types; private package GNATCOLL.Path is Invalid_Filesystem : exception; -- Raised when calling any of the below methods with FS_Unknown ------------------- -- FS Properties -- ------------------- function Local_FS return FS_Type; pragma Inline (Local_FS); -- Get the local FS type function Is_Case_Sensitive (FS : FS_Type) return Boolean; -- Tell if FS is case sensitive function Has_Devices (FS : FS_Type) return Boolean; -- Tell if the Filesystem handles devices (hard disk letters for windows) function Multi_Unit_Index_Char (FS : FS_Type) return Character; -- The character used by GNAT when creating ALI files for multi-unit files -- on the given filesystem (this is generally '~' expect on VMS where it is -- set to '$'). function Exe_Extension (FS : FS_Type) return FS_String; -- .exe on Windows, nothing on Unix ------------------ -- Path queries -- ------------------ function Get_Root (FS : FS_Type; Path : FS_String) return FS_String; -- Return the root directory of the path function Is_Absolute_Path (FS : FS_Type; Path : FS_String) return Boolean; -- Tell wether the path is absolute ------------------------ -- Path manipulations -- ------------------------ function Path (FS : FS_Type; Device : FS_String; Dir : FS_String; File : FS_String) return FS_String; -- Return a path composed of Device, Dir, and File function Equal (FS : FS_Type; Path1, Path2 : FS_String) return Boolean; -- Tell if Path1 and Path2 are equivalent function To_Unix (FS : FS_Type; Path : FS_String; Cygwin_Path : Boolean := False) return FS_String; -- Translate a Path to unix style function From_Unix (FS : FS_Type; Path : FS_String) return FS_String; -- Translate a Path from unix style function File_Extension (FS : FS_Type; Path : FS_String) return FS_String; -- Return the file extension, including the last '.' function Base_Name (FS : FS_Type; Path : FS_String; Suffix : FS_String := "") return FS_String; -- Return the base file name function Base_Dir_Name (FS : FS_Type; Path : FS_String) return FS_String; -- Return the directory base name. Root directories will be returned -- as-is ("/", "C:\", "\\machine\service\") function Get_Parent (FS : FS_Type; Path : FS_String) return FS_String; -- Return the parent directory of Path. This differs from Dir_Name in that -- calling Get_Parent on a directory will return the directory's parent. function Dir_Name (FS : FS_Type; Path : FS_String) return FS_String; -- Return the directory path. Calling Dir_Name on a directory will return -- the directory itself. function Is_Dir_Name (FS : FS_Type; Path : FS_String) return Boolean; -- Return true if Path denotes a directory path in FS (e.g. ends with a -- directory separator). function Ensure_Directory (FS : FS_Type; Path : FS_String) return FS_String; -- Return a directory path from furnished path. -- On Windows, for a path C:\path\to, this will return C:\path\to\ -- On VMS, for a path disk:[path]to.dir, this will return disk:[path.to] function Device_Name (FS : FS_Type; Path : FS_String) return FS_String; -- Return the device of the path (if applicable). Empty string otherwise function Normalize (FS : FS_Type; Path : FS_String) return FS_String; -- Replace every ./ or ../ items of the path function Relative_Path (FS : FS_Type; Ref : FS_String; Path : FS_String) return FS_String; -- Return the path of Path relative to Ref end GNATCOLL.Path; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-plugins.ads000066400000000000000000000051261425465243200230640ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with System; package GNATCOLL.Plugins is type Plugin is private; No_Plugin : constant Plugin; function Load (Path : String) return Plugin; -- Attempts to load the plugin located at Path. -- Returns No_Plugin if plugin not found. function Routine_Address (P : Plugin; Name : String) return System.Address; -- Returns address of the routine named Unit_Name defined in the plugin P. -- Returns Null_Address if such routine not found in the plugin. function Last_Error_Message return String; -- Returns last error message in case of Load or Routine_Address returned -- empty result. procedure Unload (P : in out Plugin); -- Remove the plugin from service. Note the actual effect is -- operating-system dependent. private type Plugin is new System.Address; No_Plugin : constant Plugin := Plugin (System.Null_Address); end GNATCOLL.Plugins; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-plugins__unix.adb000066400000000000000000000062721425465243200242500ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with System; use System; with Interfaces.C.Strings; use Interfaces; package body GNATCOLL.Plugins is ---------- -- Load -- ---------- function Load (Path : String) return Plugin is function dlopen (Lib_Name : String; Mode : C.int) return Plugin; pragma Import (C, dlopen, "dlopen"); RTLD_LAZY : constant := 1; C_Path : constant String := Path & ASCII.NUL; begin return dlopen (C_Path, RTLD_LAZY); end Load; --------------------- -- Routine_Address -- --------------------- function Routine_Address (P : Plugin; Name : String) return Address is function dlsym (Handle : Plugin; Sym_Name : String) return Address; pragma Import (C, dlsym, "dlsym"); C_Name : constant String := Name & ASCII.NUL; begin return dlsym (Handle => P, Sym_Name => C_Name); end Routine_Address; ------------------------ -- Last_Error_Message -- ------------------------ function Last_Error_Message return String is function dlerror return C.Strings.chars_ptr; pragma Import (C, dlerror, "dlerror"); begin return C.Strings.Value (dlerror); end Last_Error_Message; ------------ -- Unload -- ------------ procedure Unload (P : in out Plugin) is function dlclose (Handle : Plugin) return C.int; pragma Import (C, dlclose, "dlclose"); Ignored : C.int; pragma Unreferenced (Ignored); begin Ignored := dlclose (P); end Unload; end GNATCOLL.Plugins; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-plugins__windows.adb000066400000000000000000000066141425465243200247570ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with System; use System; with Interfaces.C; with Ada.Unchecked_Conversion; package body GNATCOLL.Plugins is type LPCSTR is access constant Interfaces.C.char; pragma Convention (C, LPCSTR); function LoadLibrary (lpLibFileName : LPCSTR) return Plugin; pragma Import (Stdcall, LoadLibrary, "LoadLibraryA"); procedure FreeLibrary (hModule : Plugin); pragma Import (Stdcall, FreeLibrary, "FreeLibrary"); function GetProcAddress (hModule : Plugin; lpProcName : LPCSTR) return Address; pragma Import (Stdcall, GetProcAddress, "GetProcAddress"); function GetLastError return Integer; pragma Import (Stdcall, GetLastError, "GetLastError"); function As_LPCSTR is new Ada.Unchecked_Conversion (Source => System.Address, Target => LPCSTR); ---------- -- Load -- ---------- function Load (Path : String) return Plugin is Local_Path : aliased constant String := Path & ASCII.NUL; begin return LoadLibrary (As_LPCSTR (Local_Path'Address)); end Load; --------------------- -- Routine_Address -- --------------------- function Routine_Address (P : Plugin; Name : String) return Address is RN : aliased constant String := Name & ASCII.NUL; begin return GetProcAddress (P, As_LPCSTR (RN'Address)); end Routine_Address; ------------------------ -- Last_Error_Message -- ------------------------ function Last_Error_Message return String is begin return "Last error code" & GetLastError'Img; end Last_Error_Message; ------------ -- Unload -- ------------ procedure Unload (P : in out Plugin) is begin FreeLibrary (P); P := No_Plugin; end Unload; end GNATCOLL.Plugins; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-pools.adb000066400000000000000000000270331425465243200225170ustar00rootroot00000000000000------------------------------------------------------------------------------ -- M O D E L I N G -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Unchecked_Deallocation; with GNATCOLL.Refcount; use GNATCOLL.Refcount; with GNATCOLL.Traces; use GNATCOLL.Traces; with Interfaces; use Interfaces; package body GNATCOLL.Pools is use Pointers; Me : constant Trace_Handle := Create ("Pools"); type Pool_Array is array (Positive range <>) of Pool_Resource_Access; type Pool_Array_Access is access all Pool_Array; type Resource_Set_Data is record Elements : Pool_Array_Access; Param : aliased Factory_Param; Available : aliased Integer_32 := 0; end record; type Sets is array (Resource_Set range <>) of Resource_Set_Data; type Sets_Access is access all Sets; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Pool_Resource, Pool_Resource_Access); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Pool_Array, Pool_Array_Access); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Sets, Sets_Access); protected type Pool is entry Get (Resource_Set) (Element : out Resource'Class); -- Get one resource -- You must have called Set_Factory before. -- The resource must be released explicitly by calling Release, or -- there will be starvation procedure Release (In_Pool : in out Pool_Resource_Access; Set : Resource_Set); -- Release the resource, and make it available to others. -- In_Pool might have been freed on exit procedure Set_Factory (Descr : Factory_Param; Max_Elements : Positive; Set : Resource_Set); -- Describe how to connect to the database. This can be called only -- once ie before getting the first connection procedure Free; -- Detach all resources from the pool. -- If they are in use elsewhere they will not be freed immediately, only -- when they are no longer in use. function Get_Factory_Param (Set : Resource_Set) return access Factory_Param; private Elements : Sets_Access; end Pool; protected body Pool is ----------------- -- Set_Factory -- ----------------- procedure Set_Factory (Descr : Factory_Param; Max_Elements : Positive; Set : Resource_Set) is begin if Elements = null then Elements := new Sets (Resource_Set'Range); end if; if Elements (Set).Elements = null then Elements (Set) := (Elements => new Pool_Array'(1 .. Max_Elements => null), Available => Integer_32 (Max_Elements), Param => Descr); else raise Program_Error with "Set_Factory can be called only once per resource_set"; end if; end Set_Factory; ----------------------- -- Get_Factory_Param -- ----------------------- function Get_Factory_Param (Set : Resource_Set) return access Factory_Param is begin return Elements (Set).Param'Access; end Get_Factory_Param; --------- -- Get -- --------- entry Get (for Set in Resource_Set) (Element : out Resource'Class) when Elements (Set).Available > 0 is In_Pool : Resource_Data; begin Elements (Set).Available := Elements (Set).Available - 1; -- Get the first available resource. Since they are allocated -- sequentially, this ensures that we preferably reuse an existing -- connection rather than create a new one. for E in Elements (Set).Elements'Range loop if Elements (Set).Elements (E) = null then -- ??? Issue: the factory might take a long time (for -- instance establishing a database connection). During -- that time, all threads waiting on Get are blocked. -- We should mark the slot as no longer available, and -- initialize the resource once returned to the user. Trace (Me, "Get: creating resource, at index" & E'Img); -- We have to cheat with the refcounting temporarily: the -- above call, if initialized at refcount=1, would call -- adjust once, and then finalize, thus try to call Release, -- resulting in a deadlock. Instead, we start with an -- off-by-one refcount, and put things back straight afterward. Elements (Set).Elements (E) := new Pool_Resource' (Element => Factory (Elements (Set).Param), Available => False); In_Pool := Resource_Data' (Set => Set, In_Set => Elements (Set).Elements (E)); Element.Set (In_Pool); return; elsif Elements (Set).Elements (E).Available then if Active (Me) then Trace (Me, "Get: pool " & Set'Img & " returning resources at index" & E'Img); end if; Elements (Set).Elements (E).Available := False; In_Pool := Resource_Data' (Set => Set, In_Set => Elements (Set).Elements (E)); Element.Set (In_Pool); return; end if; end loop; -- The entry guard said we had an available resource raise Program_Error with "A resource should have been available"; end Get; ------------- -- Release -- ------------- procedure Release (In_Pool : in out Pool_Resource_Access; Set : Resource_Set) is begin -- Nothing to do after the pool itself has been freed. -- Normal reference counting will take place if Elements /= null then Trace (Me, "Released one resource"); In_Pool.Available := True; Elements (Set).Available := Elements (Set).Available + 1; else -- The pool has been destroyed and the resource is no longer used. -- Simply free it. Free (In_Pool.Element); Unchecked_Free (In_Pool); end if; end Release; ---------- -- Free -- ---------- procedure Free is R : Pool_Resource_Access; begin Increase_Indent (Me, "Global_Pool.Free"); if Elements /= null then for Set in Elements'Range loop if Elements (Set).Elements /= null then for E in Elements (Set).Elements'Range loop R := Elements (Set).Elements (E); if R /= null and then R.Available then Trace (Me, "Freeing a resource"); Free (R.Element); Unchecked_Free (R); elsif R /= null then Trace (Me, "One ressource still in use, can't be freed"); end if; end loop; Free_Param (Elements (Set).Param); Unchecked_Free (Elements (Set).Elements); end if; end loop; Unchecked_Free (Elements); end if; Decrease_Indent (Me, "Done Global_Pool.Free"); end Free; end Pool; Global_Pool : Pool; -- a global pool -- This is task safe. ------------- -- Element -- ------------- function Element (Self : Resource) return access Element_Type is Enc : constant access Resource_Data := Get (Self).Element; begin Assert (Me, Enc /= null, "A wrapper should not exist without an element"); return Enc.In_Set.Element'Access; end Element; --------- -- Get -- --------- procedure Get (Self : out Resource'Class; Set : Resource_Set := Default_Set) is begin Global_Pool.Get (Set) (Self); end Get; -------------- -- Get_Weak -- -------------- function Get_Weak (Self : Resource'Class) return Weak_Resource is begin return Weak_Resource'(Ref => Self.Weak); end Get_Weak; --------- -- Get -- --------- procedure Get (Self : Weak_Resource; Res : out Resource) is begin Res.Set (Self.Ref); end Get; --------------- -- Was_Freed -- --------------- function Was_Freed (Self : Weak_Resource) return Boolean is begin return Pointers.Was_Freed (Self.Ref); end Was_Freed; ---------- -- Free -- ---------- procedure Free is begin Global_Pool.Free; end Free; ---------- -- Free -- ---------- procedure Free (Self : in out Resource_Data) is begin -- Call the user's callback before releasing into the pool, so that the -- resource doesn't get reused in the meantime. On_Release (Self.In_Set.Element); begin Global_Pool.Release (Self.In_Set, Self.Set); exception when E : Program_Error => Trace (Me, "Global pool was already finalized"); Trace (Me, E); end; end Free; ----------------- -- Set_Factory -- ----------------- procedure Set_Factory (Param : Factory_Param; Max_Elements : Positive; Set : Resource_Set := Default_Set) is begin Global_Pool.Set_Factory (Param, Max_Elements, Set); end Set_Factory; ----------------------- -- Get_Factory_Param -- ----------------------- function Get_Factory_Param (Set : Resource_Set := Default_Set) return access Factory_Param is begin return Global_Pool.Get_Factory_Param (Set); end Get_Factory_Param; ------------------ -- Get_Refcount -- ------------------ function Get_Refcount (Self : Resource) return Natural is begin return Pointers.Get_Refcount (Self); end Get_Refcount; end GNATCOLL.Pools; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-pools.ads000066400000000000000000000215321425465243200225360ustar00rootroot00000000000000------------------------------------------------------------------------------ -- M O D E L I N G -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package implements resource pools. -- The resources are created once (the first time they are needed). The -- application can then get a temporary exclusive handle on a resource (ie if -- another part of the application is also requesting a resource, it will in -- fact retrieve another instance). When the resource is no longer used by the -- application, it is automatically released into the pool, and will be reused -- the next time the application requests a resource. -- -- A typical usage is when the resource creation is expensive, such as a pool -- of database connections. -- -- Each instantiation of this package provides one task-safe global pool. -- However, this pool can contains multiple sets of elements. Each sets has -- its own factory parameter. The subprograms will by default apply to the -- first such subset, since in most cases you will only need one such subset -- in your application. An example where multiple subsets might be needed is -- for instance when we have a pool of database connections. We would for -- instance one subset for each DBMS we want to connect to it. Each subset -- then contains a number of connections to that specific DBMS. -- Of course, this pattern could be implemented by having multiple -- instantiations of GNATCOLL.Pools, but this makes the API more complex and -- forces the duplication of the whole GNATCOLL.SQL.Session API. pragma Ada_2012; private with GNATCOLL.Refcount; generic type Element_Type is private; -- The elements that are pooled type Factory_Param is private; with function Factory (Param : Factory_Param) return Element_Type; -- Information needed to create new elements as needed. This is passed as -- is to the Factory function. type Resource_Set is (<>); -- Represents a set of elements within the pool. -- There can be multiple such sets in one pool. Each set is associated with -- its own factory parameter, but all other elements are compatible between -- the various sets (in particular, the resources are the same, so the rest -- of the application doesn't need to know which set this resource is -- from). -- Most times, a pool will need only one such subset, which is created by -- default. All subprograms below apply to this default set, unless -- otherwise specified. with procedure Free (Self : in out Element_Type) is null; -- Called when the [Self] is finally removed from the pool with procedure On_Release (Self : in out Element_Type) is null; -- Called when Self is released into the pool. -- The application has no more reference to that element, apart from the -- one in the pool. -- The result of Element.Element should not be freed yet, since it is -- returned to the pool (instead, override the formal [Free] parameter). -- But any other custom field from Element should be reset at that time. with procedure Free_Param (Data : in out Factory_Param) is null; -- Free Factory_Param. -- Called when the pool itself is freed. package GNATCOLL.Pools is Default_Set : constant Resource_Set; type Resource is tagged private; No_Resource : constant Resource; -- A resource retrieved from the pool. -- This is a smart pointer to an Element_Type. When your application has no -- more references to it, the Element_Type is released into the pool (not -- destroyed). -- The resource itself does its refcounting in a task-safe manner. function Element (Self : Resource) return access Element_Type; -- Get a copy of the element stored in the wrapper. The result should -- really only be used while you have a handle on Self, so that you are -- sure it has not been released into the pool, and thus reset. type Weak_Resource is private; Null_Weak_Resource : constant Weak_Resource; function Get_Weak (Self : Resource'Class) return Weak_Resource; procedure Get (Self : Weak_Resource; Res : out Resource); -- A resource with a weak-reference. -- Such a resource does not prevent the release into the pool when no other -- Resource exists. While the resource has not been released, you can get -- access to it through this Weak_Resource. One it has been released, the -- Weak_Resource will return No_Resource. -- This datatype can thus be stored in some long-lived data structure, if -- you do not want to prevent the release. For instance if you have a -- cache of some sort. function Was_Freed (Self : Weak_Resource) return Boolean; -- Whether the resource monitored by Self was released. procedure Set_Factory (Param : Factory_Param; Max_Elements : Positive; Set : Resource_Set := Default_Set); -- Configure the internal resource pool. This must be called before -- calling Get, and only once. procedure Get (Self : out Resource'Class; Set : Resource_Set := Default_Set); -- Return an available resource (or create a new one if the pool is not -- full yet and none is available). -- In a multitasking context, this blocks until a resource is actually -- available. -- The resource is automatically released when you no longer have a -- reference to the wrapper. procedure Free; -- Detach all resources from the pool. -- Any resource that is not in use elsewhere (ie retrieved by Get) will -- get freed (and the corresponding [Free] formal subprogram will be -- called). function Get_Refcount (Self : Resource) return Natural; -- Return the reference counting for self function Get_Factory_Param (Set : Resource_Set := Default_Set) return access Factory_Param; -- Returns a the factory param used for the set. -- Remember that the factory will not be called again for resources that -- have already been created, even if they have been released to the pool -- since then. -- This must only be called when you have called Set_Factory for the -- corresponding set. -- The returned value is shared among multiple threads, so you should only -- modify it from a protected region or before tasks are created. private type Pool_Resource is record Element : aliased Element_Type; Available : Boolean; -- Is the resource available ? end record; type Pool_Resource_Access is access all Pool_Resource; -- The data stored in the pool. -- These are not smart pointers, which are created on demand in Get. Default_Set : constant Resource_Set := Resource_Set'First; type Resource_Data is record In_Set : Pool_Resource_Access; Set : Resource_Set; end record; procedure Free (Self : in out Resource_Data); package Pointers is new GNATCOLL.Refcount.Shared_Pointers (Resource_Data, Free); -- The smart pointers returned to the application. When no longer -- referenced, the resource is released back into the pool. type Weak_Resource is record Ref : Pointers.Weak_Ref; end record; type Resource is new Pointers.Ref with null record; No_Resource : constant Resource := Resource'(Pointers.Null_Ref with null record); Null_Weak_Resource : constant Weak_Resource := (Ref => Pointers.Null_Weak_Ref); end GNATCOLL.Pools; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-promises.adb000066400000000000000000000313661425465243200232300ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Containers.Vectors; with Ada.Exceptions; use Ada.Exceptions; with Ada.Unchecked_Deallocation; with GNAT.Strings; use GNAT.Strings; with GNATCOLL.Atomic; use GNATCOLL.Atomic; package body GNATCOLL.Promises is use type Impl.Promise_Callback_Access; package Cb_Vectors is new Ada.Containers.Vectors (Positive, Impl.Promise_Callback_Access, Impl."="); ---------- -- Free -- ---------- procedure Free (Self : in out Freeable_Access) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (IFreeable'Class, Freeable_Access); begin if Self /= null then Free (Self.all); Unchecked_Free (Self); end if; end Free; --------------- -- Subscribe -- --------------- procedure Subscribe (Self : Promise_Chain) is begin null; end Subscribe; ---------- -- Impl -- ---------- package body Impl is ------------------- -- Dispatch_Free -- ------------------- procedure Dispatch_Free (Self : in out IPromise_Data'Class) is begin Free (Self); end Dispatch_Free; end Impl; -------------- -- Promises -- -------------- package body Promises is type T_Access is access all T; type Promise_Data is new Impl.IPromise_Data with record State : aliased Promise_State := Pending; Callbacks : Cb_Vectors.Vector; -- Need a vector here, but should try to limit memory allocs. -- A bounded vector might be more efficient, and sufficient in -- practice. Value : T_Access; -- ??? Using the ada-traits-containers approach, we could avoid -- some memory allocation here. Reason : GNAT.Strings.String_Access; end record; type Promise_Data_Access is access all Promise_Data'Class; overriding procedure Free (Self : in out Promise_Data); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (T, T_Access); --------------- -- Get_State -- --------------- function Get_State (Self : Promise'Class) return Actual_Promise_State is D : constant not null access Promise_Data'Class := Promise_Data_Access (Impl.Promise_Pointers.Unchecked_Get (Self)); begin return Actual_Promise_State (D.State); end Get_State; ------------ -- Create -- ------------ function Create return Promise is begin return P : Promise do P.Set (Data => Promise_Data' (Callbacks => Cb_Vectors.Empty_Vector, State => Pending, Value => null, Reason => null)); end return; end Create; ---------- -- Free -- ---------- overriding procedure Free (Self : in out Promise_Data) is begin Unchecked_Free (Self.Value); Free (Self.Reason); end Free; --------------- -- Set_Value -- --------------- procedure Set_Value (Self : in out Promise; R : T) is D : constant not null access Promise_Data'Class := Promise_Data_Access (Impl.Promise_Pointers.Unchecked_Get (Self)); Old : Actual_Promise_State; begin loop Old := Actual_Promise_State (Sync_Val_Compare_And_Swap_Counter (Ptr => D.State'Access, Oldval => Pending, Newval => Resolving)); case Old is when Resolved | Failed => -- Promise has already been completed, this is an error return; when Resolving | Failing | Subscribing => -- Try again null; when Pending => -- OK, we can change the state for Cb of D.Callbacks loop Callback_Access (Cb).On_Next (R); Free (Freeable_Access (Cb)); end loop; D.Callbacks.Clear; -- No longer needed, release them D.Value := new T'(R); D.State := Resolved; -- Fully resolved now exit; end case; end loop; end Set_Value; --------------- -- Set_Error -- --------------- procedure Set_Error (Self : in out Promise; Reason : String) is D : constant not null access Promise_Data'Class := Promise_Data_Access (Impl.Promise_Pointers.Unchecked_Get (Self)); Old : Actual_Promise_State; begin loop Old := Actual_Promise_State (Sync_Val_Compare_And_Swap_Counter (Ptr => D.State'Access, Oldval => Pending, Newval => Failing)); case Old is when Resolved | Failed => -- Promise has already been completed, this is an error return; when Resolving | Failing | Subscribing => -- Try again null; when Pending => -- OK, we can change the state for Cb of D.Callbacks loop Callback_Access (Cb).On_Error (Reason); Free (Freeable_Access (Cb)); end loop; D.Callbacks.Clear; -- No longer needed, release them D.Reason := new String'(Reason); D.State := Failed; -- Fully failed now exit; end case; end loop; end Set_Error; --------------- -- Subscribe -- --------------- procedure Subscribe (Self : Promise; Cb : not null access Callback'Class) is D : constant not null access Promise_Data'Class := Promise_Data_Access (Impl.Promise_Pointers.Unchecked_Get (Self)); -- ??? Unrestricted_Access is temporary, so that user can -- use "new Cb" directly in the call to Subscribe. C : Callback_Access := Cb.all'Unrestricted_Access; Old : Actual_Promise_State; begin loop Old := Actual_Promise_State (Sync_Val_Compare_And_Swap_Counter (Ptr => D.State'Access, Oldval => Pending, Newval => Subscribing)); case Old is when Resolving | Failing | Subscribing => -- Try again null; when Resolved => -- We don't need to change D, so we leave the state to -- Pending C.On_Next (D.Value.all); Free (Freeable_Access (C)); return; when Failed => C.On_Error (D.Reason.all); Free (Freeable_Access (C)); return; when Pending => D.Callbacks.Append (Impl.Promise_Callback_Access (C)); D.State := Pending; exit; end case; end loop; end Subscribe; ----------- -- "and" -- ----------- function "and" (Self : Promise; Cb : Callback_List) return Promise_Chain is begin for C of Cb loop Self.Subscribe (C); end loop; return Promise_Chain'(null record); end "and"; ----------- -- "and" -- ----------- function "and" (Self : Promise; Cb : not null access Callback'Class) return Promise_Chain is begin Self.Subscribe (Cb); return Promise_Chain'(null record); end "and"; --------- -- "&" -- --------- function "&" (Cb : not null access Callback'Class; Cb2 : not null access Callback'Class) return Callback_List is begin return (Cb.all'Unrestricted_Access, Cb2.all'Unrestricted_Access); end "&"; --------- -- "&" -- --------- function "&" (List : Callback_List; Cb2 : not null access Callback'Class) return Callback_List is begin return List & (1 => Cb2.all'Unrestricted_Access); end "&"; end Promises; ------------ -- Chains -- ------------ package body Chains is ----------- -- "and" -- ----------- function "and" (Input : Input_Promises.Promise; Cb : not null access Callback'Class) return Output_Promises.Promise is begin Cb.Promise := Output_Promises.Create; Input_Promises.Subscribe (Input, Cb.all'Unrestricted_Access); return Cb.Promise; end "and"; ----------- -- "and" -- ----------- function "and" (Input : Input_Promises.Promise; Cb : Callback_List) return Output_Promises.Promise is P : constant Output_Promises.Promise := Input and Cb.Cb; begin for C of Cb.Cb2 loop Input_Promises.Subscribe (Input, C); end loop; return P; end "and"; ------------------- -- Is_Registered -- ------------------- function Is_Registered (Self : not null access Callback'Class) return Boolean is begin return Self.Promise.Is_Created; end Is_Registered; ------------------- -- Is_Registered -- ------------------- function Is_Registered (Self : Callback_List) return Boolean is begin return Self.Cb.Promise.Is_Created; end Is_Registered; ------------- -- On_Next -- ------------- overriding procedure On_Next (Self : in out Callback; P : Input_Promises.Result_Type) is begin On_Next (Callback'Class (Self), P, Self.Promise); exception when E : others => Self.Promise.Set_Error (Exception_Message (E)); end On_Next; -------------- -- On_Error -- -------------- overriding procedure On_Error (Self : in out Callback; Reason : String) is begin -- Propagate the failure Self.Promise.Set_Error (Reason); end On_Error; ----------- -- "&" -- ----------- function "&" (Cb : not null access Callback'Class; Cb2 : not null access Input_Promises.Callback'Class) return Callback_List is begin return Callback_List' (N => 1, Cb => Cb.all'Unrestricted_Access, Cb2 => (1 => Cb2.all'Unrestricted_Access)); end "&"; ----------- -- "&" -- ----------- function "&" (List : Callback_List; Cb2 : not null access Input_Promises.Callback'Class) return Callback_List is begin return Callback_List' (N => List.N + 1, Cb => List.Cb, Cb2 => List.Cb2 & (1 => Cb2.all'Unrestricted_Access)); end "&"; end Chains; end GNATCOLL.Promises; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-promises.ads000066400000000000000000000467451425465243200232600ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- A promise (also known sometimes as a future or deferred) is a -- a synchronization mechanism between asynchronous routines. -- -- Such routines could be implemented as tasks, but also be handled -- via the system's asynchronous I/O primitives, or an event loop in a -- GUI program for instance. -- -- A promise is a value that such a routine can return immediately to the -- caller, before it even starts its processing or the actual value is -- available. The caller can then subscribe to the promise, so that when -- the value becomes actually known, it gets notified and a callback is -- executed. -- -- Here is a simple example: -- -- package Str_Promises is new Promises (String); -- -- type Process_Page is new Str_Promises.Callback with null record; -- overriding procedure On_Next -- (Self : in out Process_Page; Page : String) -- is -- begin -- Put_Line ("Page contents is known: " & Page); -- end On_Next; -- -- P : Str_Promises.Promise; -- -- P := Fetch_URL_Asynchronously ("http://..."); -- P.Subscribe (new Process_Page); -- -- Where Fetch_URL_Asynchronously could run in a task, connect to a -- web server and query a document. -- -- But promises are more interesting when they are chained, i.e. the -- action executed when the first promise is resolved will itself -- return a promise. Here is an example: -- -- package Str_Promises is new Promises (String); -- package Int_Promises is new Promises (Integer); -- package Str_To_Int is new Chains (Str_Promises, Int_Promises); -- use Str_To_Int, Int_Promises; -- -- type Count_Elements is new Str_To_Int.Callback with null record; -- overriding procedure On_Next -- (Self : in out Process_Page; -- Page : String; -- Output : in out Int_Promises.Promise); -- -- For instance, count the number of elements in the XML, and -- -- would call Output.Set_Value -- -- type Report_Count is new Int_Promises.Callback with null record; -- overriding procedure On_Next -- (Self : in out Report_Count; -- Count : Integer); -- -- For instance display the number of elements in a GUI -- -- Subscribe -- (Fetch_URL_Asynchronously ("http://...") -- and new Count_Elements -- and new Report_Count); -- -- The code above returns immediately, even though the URL will be fetched -- in the background (which could take a few seconds), then parsed to count -- the number of elements (which could be done in a separate task and take -- a few milliseconds), and finally this count will be displayed in a GUI. -- -- The advantage of this code is that it is composed of small, independent -- building blocks that are executed when data becomes available. The caller -- does not have to take care of the synchronization, since the promises -- handle that. -- -- Behavior -- ======== -- -- A Promise is a concept that has been adopted by multiple programming -- languages, starting with javascript and C++ (promises and futures). -- -- There are some standard behaviors associated with promises, which this -- package tries to conform with: -- -- * A promise can be in one of three states: -- - Pending: the promise has no associated value yet. Some subprogram is -- still running in the background to fetch that value. -- - Resolved: the routine has successfully finished running, and given -- an actual value to the promise (via a call to Set_Value) -- - Failed: the routine failed, and no value will ever be provided to the -- routine. A reason for the failure is provided via a call -- to Set_Error) -- -- * Any number of callbacks can be set on a routine. They will all be -- executed once when the promise is resolved or failed. They are never -- executed again afterwards. -- -- * A promise can be resolved at any time. Whenever it is resolved, all -- callbacks currently set on the promise are executed and then -- disconnected. It is an error to resolve a promise more than once. -- -- * A callback can be added to a promise at any time. If the promise has -- already been resolved, the callback is executed immediately with the -- value set on that promise. -- -- Tasks -- ===== -- -- Promises are task safe. They can be used from multiple threads (and, as -- always, a single call to Set_Value or Set_Error can be done), subscribed -- to from multiple threads,... -- However, the value itself is under your control. Although the promise -- will only execute one callback at a time, to which is passes the value, -- you should ensure that the value is not used from another thread in -- parallel, or provide appropriate locking. -- Using simple types like Integers or Strings should be safe. -- -- Chaining and callbacks -- ====================== -- -- Promises can be chained, so that the callback for the first promise will -- itself return a promise, whose callback might in turn return a promise, -- and so on. -- -- The syntax to chain promises is: -- -- Subscribe (P and new A and new B and new C; -- -- Let's take the following chain: -- -- P and new A -- A is the callback on P -- and new B -- B is the callback on the promise returned by A -- and new C; -- C is the callback on the promise returned by C -- -- The following callbacks might occur (where *.P is the promise output -- by the routine, *.V is the value of that promise, and *.R is the reason -- for the failure of that promise, which defaults to the reason received -- from the previous release unless overridden): -- -- promises calls -- If P is resolved: A.On_Next (P.V) -- If A.P is resolved: B.On_Next (A.V) -- if B.P is resolved: C.On_Next (B.V) -- else B.P failed: C.On_Error (B.R) -- else A.P failed: B.On_Error (A.R), C.On_Error (B.R) -- else P failed: A.On_Error (P.R), B.On_Error (A.R), -- C.On_Error (B.R) -- -- Q: What if I want multiple callbacks on the same promise ? -- A: You need to use intermediate variables, as in: -- Q := P and new A; -- Subscribe (Q and new B); -- Subscribe (Q and new C); -- Where both B and C are callbacks on A's return promise (and not -- chained together). -- -- A more convenient syntax exists, as in the following example: -- -- P and (new A & new B) -- A.P is passed on to the next step -- and (new C & new D) -- C.P is passed on to the next step -- and new E; -- -- If P is resolved: A.On_Next (P.V), B.On_Next (P.V) -- if A.P is resolved: C.On_Next (A.V), D.On_Next (A.V) -- if C.P is resolved: E.On_Next (C.V) -- else C.P failed: E.On_Error (C.R) -- else A.P failed: C.On_Error (A.R), D.On_Error (A.R), -- E.On_Error (C.R) -- else P failed: A.On_Error (P.R), B.On_Error (P.R), -- C.On_Error (A.R), D.On_Error (A.R), -- E.On_Error (C.R) -- -- Note that there is no guaranteed order in which the callbacks are -- executed, so for instance it is possible that C.On_Next and -- E.On_Next are called before B.On_Next. -- -- Q: What if I want different success and failure callbacks ? -- A: A callback is an object with both a On_Next and a On_Error primitive -- operations. So you could set two different callbacks on the same -- promise (as we did above in the first question) with GNATCOLL.Atomic; with GNATCOLL.Refcount; package GNATCOLL.Promises is use type GNATCOLL.Atomic.Atomic_Counter; subtype Promise_State is GNATCOLL.Atomic.Atomic_Counter; Pending : constant Promise_State := 0; Resolved : constant Promise_State := 1; Failed : constant Promise_State := 2; Resolving : constant Promise_State := 3; Failing : constant Promise_State := 4; Subscribing : constant Promise_State := 5; subtype Actual_Promise_State is Promise_State range Pending .. Subscribing; -- The various states that a promise can have. -- We use atomic operations when possible to manipulate it, to make -- promises task safe. type Promise_Chain is tagged private; procedure Subscribe (Self : Promise_Chain) with Inline => True; -- A dummy type used when chaining promises with the "and" -- operator. See below for an example of code. -- -- Do not mark this procedure as "is null", since otherwise GNAT -- does not even call the last "and" in the chain. -------------- -- IFreeable -- -------------- type IFreeable is interface; type Freeable_Access is access all IFreeable'Class; -- a general interface for objects that have an explicit Free -- primitive operation. procedure Free (Self : in out IFreeable) is null; -- Free internal data of Self procedure Free (Self : in out Freeable_Access); -- Free self, via its primitive operation, and then free the pointer ---------- -- Impl -- ---------- -- This package is for implementation details package Impl is type IPromise_Data is interface; procedure Free (Self : in out IPromise_Data) is null; procedure Dispatch_Free (Self : in out IPromise_Data'Class); type IAbstract_Promise is interface; package Promise_Pointers is new GNATCOLL.Refcount.Shared_Pointers (Element_Type => IPromise_Data'Class, Release => Dispatch_Free, Atomic_Counters => True); -- thread-safe type Root_Promise is new Promise_Pointers.Ref and IAbstract_Promise with null record; type IPromise_Callback is interface and IFreeable; type Promise_Callback_Access is access all IPromise_Callback'Class; procedure On_Error (Self : in out IPromise_Callback; Reason : String) is null; -- Called when a promise has failed and will never be resolved. end Impl; -------------- -- Promises -- -------------- generic type T (<>) is private; package Promises is type Promise is new Impl.IAbstract_Promise with private; -- A promise is a smart pointer: it is a wrapper around shared -- data that is freed when no more reference to the promise -- exists. subtype Result_Type is T; --------------- -- Callbacks -- --------------- type Callback is interface and Impl.IPromise_Callback; type Callback_Access is access all Callback'Class; procedure On_Next (Self : in out Callback; R : Result_Type) is null; -- Executed when a promise is resolved. It provides the real value -- associated with the promise. type Callback_List (<>) is private; -- Multiple callbacks, all subscribed to the same promise (or -- will be subscribed to the same promise). -------------- -- Promises -- -------------- function Create return Promise with Post => Create'Result.Is_Created and Create'Result.Get_State = Pending; -- Create a new promise, with no associated value. procedure Set_Value (Self : in out Promise; R : T) with Pre => Self.Is_Created and Self.Get_State /= Resolved and Self.Get_State /= Failed, Post => Self.Get_State = Resolved; -- Give a result to the promise. -- The callbacks' On_Next methods are executed. -- This can only be called once on a promise. procedure Set_Error (Self : in out Promise; Reason : String) with Pre => Self.Is_Created and Self.Get_State /= Resolved and Self.Get_State /= Failed, Post => Self.Get_State = Failed; -- Mark the promise has failed. It will never be resolved. -- The callbacks' On_Error method are executed. procedure Subscribe (Self : Promise; Cb : not null access Callback'Class) with Pre => Self.Is_Created; function "and" (Self : Promise; Cb : not null access Callback'Class) return Promise_Chain with Pre => Self.Is_Created; function "and" (Self : Promise; Cb : Callback_List) return Promise_Chain with Pre => Self.Is_Created; -- Will call Cb when Self is resolved or failed (or immediately if Self -- has already been resolved or failed). -- Any number of callbacks can be set on each promise. -- If you want to chain promises (i.e. your callback itself returns -- a promise), take a look at the Chains package below. -- -- Cb must be allocated specifically for this call, and will be -- freed as needed. You must not reuse the same pointer for multiple -- calls to Subscribe. -- ??? This is unsafe -- -- Self is modified, but does not need to be "in out" since a promise -- is a pointer. This means that Subscribe can be directly called on -- the result of a function call, for instance. function "&" (Cb : not null access Callback'Class; Cb2 : not null access Callback'Class) return Callback_List; function "&" (List : Callback_List; Cb2 : not null access Callback'Class) return Callback_List; -- Create a list of callbacks that will all be subscribed to the same -- promise. function Is_Created (Self : Promise'Class) return Boolean with Inline_Always; -- Whether the promise has been created function Get_State (Self : Promise'Class) return Actual_Promise_State with Inline_Always; -- Used for pre and post conditions private type Promise is new Impl.Root_Promise with null record; type Callback_List is array (Natural range <>) of not null access Callback'Class; function Is_Created (Self : Promise'Class) return Boolean is (not Self.Is_Null); end Promises; ------------ -- Chains -- ------------ generic with package Input_Promises is new Promises (<>); with package Output_Promises is new Promises (<>); package Chains is type Callback is abstract new Input_Promises.Callback with private; procedure On_Next (Self : in out Callback; Input : Input_Promises.Result_Type; Output : in out Output_Promises.Promise) is abstract with Post'Class => Output.Get_State = Resolved or Output.Get_State = Failed; -- This is the procedure that needs overriding, not the one inherited -- from Input_Promises. When chaining, a callback returns another -- promise, to which the user can attach further callbacks, and so on. -- -- Failures in a promise are by default propagated to the output -- promise, unless you override the Failed primitive operation of -- Self. type Callback_List (<>) is private; function Is_Registered (Self : not null access Callback'Class) return Boolean with Inline; function Is_Registered (Self : Callback_List) return Boolean with Inline; -- Whether the callback has already been set on a promise. It is -- invalid to use the same callback on multiple promises (or even -- multiple times on the same promise). function "and" (Input : Input_Promises.Promise; Cb : not null access Callback'Class) return Output_Promises.Promise with Pre => not Is_Registered (Cb) and Input.Is_Created, Post => Is_Registered (Cb) and "and"'Result.Is_Created; -- Chains two properties. -- When Input is resolved, Cb is executed and will in turn resolve -- the output promise -- These functions return immediately a promise that will be resolved -- later. function "&" (Cb : not null access Callback'Class; Cb2 : not null access Input_Promises.Callback'Class) return Callback_List with Pre => not Is_Registered (Cb); -- ??? Results in GNAT bug box -- Post => "and"'Result = Cb -- and not Is_Registered ("and"'Result); function "&" (List : Callback_List; Cb2 : not null access Input_Promises.Callback'Class) return Callback_List; -- Used to set multiple callbacks on the same promise, as in: -- P & (new A and new B) & new C -- Only Cb is expected to output a promise, which will be -- forwarded to the next step (C in this example). Cb2 only -- gets notified via its On_Next and On_Error primitives. function "and" (Input : Input_Promises.Promise; Cb : Callback_List) return Output_Promises.Promise with Pre => not Is_Registered (Cb) and Input.Is_Created, Post => Is_Registered (Cb) and "and"'Result.Is_Created; -- Chaining multiple callbacks on the same promise private type Callback is abstract new Input_Promises.Callback with record Promise : aliased Output_Promises.Promise; end record; overriding procedure On_Next (Self : in out Callback; P : Input_Promises.Result_Type); overriding procedure On_Error (Self : in out Callback; Reason : String); type Callback_Array is array (Natural range <>) of not null access Input_Promises.Callback'Class; type Callback_List (N : Natural) is record Cb : not null access Callback'Class; Cb2 : Callback_Array (1 .. N); end record; end Chains; private type Promise_Chain is tagged null record; end GNATCOLL.Promises; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-multiple_queue_cyclic_server.adb000066400000000000000000000131651425465243200313210ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Ravenscar.Utils; package body GNATCOLL.Ravenscar.Multiple_Queue_Cyclic_Server is use GNATCOLL.Ravenscar.Utils; procedure Put_Request (Req : Request; Kind : Request_Kind) is begin -- Simply delegates to Protocol.Put Protocol.Put (Req, Kind); end Put_Request; protected body Protocol is procedure Put (Req : Request; Kind : Request_Kind) is Ref : constant Request_Type_Ref := Queues (Kind) (Insert_Index (Kind))'Access; begin -- put the Req in the appropriate queue Queues (Kind) (Insert_Index (Kind)) := Req; -- increase insert index Increase_Counter (Insert_Index (Kind), QS); if Pending < Pointer_Queue_Range_Max then Pending := Pending + 1; end if; -- save pointer to last Req on a queue Ptr_Queue (Pointer_Queue_Insert_Index) := (Kind, Ref); Increase_Counter (Pointer_Queue_Insert_Index, Pointer_Queue_Range_Max); -- If there has been an overflow, increase also the Extract index. -- This is because the insert index has surpassed the extract index, -- overwriting older request. It is thus necessary to increase the -- extract index to avoid to fetch a newly posted request instead -- of older ones. if Pointer_Queue_Overflow then Increase_Counter (Pointer_Queue_Extract_Index, Pointer_Queue_Range_Max); end if; -- Check if the Insert_Index is going to surpass the extract index if Pointer_Queue_Insert_Index = Pointer_Queue_Extract_Index then Pointer_Queue_Overflow := True; end if; end Put; procedure Get_Next_Request (Req : out Request) is Ref : Pointer_Queue_Item_Ref := null; begin -- If the insert and extract index have the same value, it is -- possible to avoid overflow if a request is fetched before a new -- one is posted: this case addresses exactly this. if Pointer_Queue_Insert_Index = Pointer_Queue_Extract_Index then Pointer_Queue_Overflow := False; end if; -- get the oldest Req Ref := Ptr_Queue (Pointer_Queue_Extract_Index)'Access; Increase_Counter (Pointer_Queue_Extract_Index, Pointer_Queue_Range_Max); Req := Ref.Req.all; -- decrease number of pending requests Pending := Pending - 1; end Get_Next_Request; pragma Inline (Get_Next_Request); procedure Get (Req : out Request; Has_Pending : out Boolean) is begin -- check if there are pending requests Has_Pending := Pending > 0; if Pending > 0 then Get_Next_Request (Req); end if; end Get; end Protocol; task body Cyclic_Task is Req : Request; Next_Time : Ada.Real_Time.Time := System_Start_Time; Has_Pending : Boolean := False; use Ada.Real_Time; begin Next_Time := Next_Time + Milliseconds (Phase); loop delay until Next_Time; Protocol.Get (Req, Has_Pending); if Has_Pending then Dispatch (Req); else Cyclic_Operation; end if; Next_Time := Next_Time + Milliseconds (Period); end loop; end Cyclic_Task; end GNATCOLL.Ravenscar.Multiple_Queue_Cyclic_Server; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-multiple_queue_cyclic_server.ads000066400000000000000000000160031425465243200313340ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- This version of a Ravenscar-compliant cyclic server extends the behaviour -- of GNAT.Ravenscar.Simple_Cyclic_Task by accepting multiple types of -- requests reified in a single variant type; if no requests have been posted -- during the previous period, the server executes its nominal operation -- (Cyclic_Operation). It shares all basic properties of -- GNAT.Ravenscar.Simple_Cyclic_Task. -- -- A typical example of usage is the following: -- -- type Req is (REQ1, REQ2, REQ3); -- type Par (R : Req := REQ1) is -- record -- Req : Req := R; -- case R is -- when REQ1 => -- null; -- when REQ2 => -- P1 : Type1; -- when REQ3 => -- P2 : Type2; -- P3 : Type3; -- end case; -- end record; -- -- procedure Dispatch(P : Par) is -- begin -- case P.Req is -- when REQ1 => -- Do_Something; -- when REQ2 => -- Do_Something(P.P1); -- when REQ3 => -- Do_Something(P.P2, P.P3); -- end case; -- end Dispatch; -- -- procedure Cyclic_Operation; -- -- package My_Cyclic_Server is new GNAT.Ravenscar.Multiple_Queue_Cyclic_Server -- (Task_Priority => 10, -- Period => 1_000, -- Phase => 200, -- System_Start_Time => System_Properties.Start_UP_Time, -- Cyclic_Operation => Cyclic_Operation, -- Protocol_Ceiling => 15, -- QS => 4, -- Request_Kind => Req, -- Param => Par, -- Dispatch => Dispatch); -- -- [...] -- declare -- P : Par(REQ2); -- begin -- -- fill parameters -- P.P2 := Val; -- -- Release the task -- -- My_Sporadic_Task.Put_Request(P); -- -- BEHAVIOUR -- If no Req is posted via Put_Request, My_Cyclic_Server executes -- Cyclic_Operation at its frequency; otherwise it fulfill the posted Req. with System; with Ada.Real_Time; generic Task_Priority : System.Priority; -- the priority of the server Period : Millisecond; -- the constant perios of the server System_Start_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock; -- the absolute instant in time for the release of the systems as a whole Phase : Millisecond; -- the phase of the server with procedure Cyclic_Operation; -- the nominal operation which is executed if no requestests have been -- posted within the previous cycle Protocol_Ceiling : System.Any_Priority; -- the ceiling priority of the protected object used to post and fetch -- requests QS : Queue_Size; -- the size of accepted requests type Request_Kind is (<>); -- an enumeration type identificng the possible kinds of request type Request is private; -- the reified request type with procedure Dispatch (Req : Request); -- the procedure invoked by the server to dispatch the fetched request package GNATCOLL.Ravenscar.Multiple_Queue_Cyclic_Server is procedure Put_Request (Req : Request; Kind : Request_Kind); -- Invoked by clients to post reified requests to be fetched and executed -- by the server private type Request_Type_Ref is access all Request; -- pointer type for request type Request_Queue is array (1 .. QS) of aliased Request; -- physical queue for posted requests type All_Queue is array (Request_Kind'Range) of Request_Queue; -- the entire set of queues (one for each possible request) type All_Queue_Index is array (Request_Kind'Range) of Queue_Range; -- type to collect all indexes to access requests Pointer_Queue_Range_Max : constant Integer := QS; -- maximum index value type Pointer_Queue_Item is record Kind : Request_Kind; Req : Request_Type_Ref; end record; -- reified request descriptor saved in a queue type Pointer_Queue_Item_Ref is access all Pointer_Queue_Item; -- pointer type to reified request descriptors type Pointer_Queue is array (Integer range 1 .. Pointer_Queue_Range_Max) of aliased Pointer_Queue_Item; -- logical queue of posted requests protected Protocol is pragma Priority (Protocol_Ceiling); procedure Put (Req : Request; Kind : Request_Kind); procedure Get (Req : out Request; Has_Pending : out Boolean); private Queues : All_Queue; Insert_Index : All_Queue_Index := (others => 1); Pending : Integer := 0; Ptr_Queue : Pointer_Queue := (others => (Request_Kind'First, null)); Pointer_Queue_Insert_Index : Integer := 1; Pointer_Queue_Extract_Index : Integer := 1; Pointer_Queue_Overflow : Boolean := False; end Protocol; -- the protected object used to post/fetch requests task Cyclic_Task is pragma Priority (Task_Priority); end Cyclic_Task; -- the cyclic server end GNATCOLL.Ravenscar.Multiple_Queue_Cyclic_Server; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-multiple_queue_sporadic_server.adb000066400000000000000000000130121425465243200316460ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Ravenscar.Utils; package body GNATCOLL.Ravenscar.Multiple_Queue_Sporadic_Server is use GNATCOLL.Ravenscar.Utils; procedure Put_Request (Req : Request; Kind : Request_Kind) is begin -- Simply delegates to Protocol.Put Protocol.Put (Req, Kind); end Put_Request; protected body Protocol is procedure Update_Barrier is begin Barrier := Pending > 0; end Update_Barrier; pragma Inline (Update_Barrier); procedure Put (Req : Request; Kind : Request_Kind) is Ref : constant Request_Type_Ref := Queues (Kind) (Insert_Index (Kind))'Access; begin -- put the Req in the appropriate queue Queues (Kind) (Insert_Index (Kind)) := Req; -- increase insert index Increase_Counter (Insert_Index (Kind), QS); if Pending < Pointer_Queue_Range_Max then Pending := Pending + 1; end if; -- save pointer to last Req on a queue Ptr_Queue (Pointer_Queue_Insert_Index) := (Kind, Ref); Increase_Counter (Pointer_Queue_Insert_Index, Pointer_Queue_Range_Max); -- if there has been an overflow, increase also the Extract index. -- This is because the insert index has surpassed the extract index, -- overwriting older request. It is thus necessary to increase the -- extract index to avoid to fetch a newly posted request instead -- of older ones. if Pointer_Queue_Overflow then Increase_Counter (Pointer_Queue_Extract_Index, Pointer_Queue_Range_Max); end if; -- Check if the Insert_Index is going to surpass the extract index if Pointer_Queue_Insert_Index = Pointer_Queue_Extract_Index then Pointer_Queue_Overflow := True; end if; -- update the barrier Update_Barrier; end Put; procedure Get_Next_Request (Req : out Request) is Ref : Pointer_Queue_Item_Ref := null; begin if Pointer_Queue_Insert_Index = Pointer_Queue_Extract_Index then Pointer_Queue_Overflow := False; end if; -- get the oldest Req Ref := Ptr_Queue (Pointer_Queue_Extract_Index)'Access; Increase_Counter (Pointer_Queue_Extract_Index, Pointer_Queue_Range_Max); Req := Ref.Req.all; Pending := Pending - 1; end Get_Next_Request; pragma Inline (Get_Next_Request); entry Get (Req : out Request; Release_Time : out Ada.Real_Time.Time) when Barrier is begin Release_Time := Ada.Real_Time.Clock; Get_Next_Request (Req); Update_Barrier; end Get; end Protocol; task body Sporadic_Task is Req : Request; Release_Time : Ada.Real_Time.Time; Next_Time : Ada.Real_Time.Time := System_Start_Time; use Ada.Real_Time; begin loop -- report.Print(natural'Image(Pointer_Queue_Range_Max)); delay until Next_Time; Protocol.Get (Req, Release_Time); Dispatch (Req); Next_Time := Release_Time + Milliseconds (Minimum_Interelease_Time); end loop; end Sporadic_Task; end GNATCOLL.Ravenscar.Multiple_Queue_Sporadic_Server; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-multiple_queue_sporadic_server.ads000066400000000000000000000151701425465243200316760ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- This version of a Ravenscar-compliant sporadic server extends the behaviour -- of GNAT.Ravenscar.Sporadic_Server by accepting multiple types of requests -- reified in a single variant type. It shares all basic properties of -- GNAT.Ravenscar.Sporadic_Server. -- -- A typical example of usage is the following: -- -- type Req is (REQ1, REQ2, REQ3); -- type Par (R : Req := REQ1) is -- record -- Req : Req := R; -- case R is -- when REQ1 => -- null; -- when REQ2 => -- P1 : Type1; -- when REQ3 => -- P2 : Type2; -- P3 : Type3; -- end case; -- end record; -- -- procedure Dispatch(P : Par) is -- begin -- case P.Req is -- when REQ1 => -- Do_Something; -- when REQ2 => -- Do_Something(P.P1); -- when REQ3 => -- Do_Something(P.P2, P.P3); -- end case; -- end Dispatch; -- -- package My_Sporadic_Server is -- new GNAT.Ravenscar.Multiple_Queue_Sporadic_Server -- (Task_Priority => 10, -- Minimum_Interelease_Time => 1_000, -- Protocol_Ceiling => 15, -- System_Start_Time => System_Properties.Start_UP_Time, -- QS => 4, -- Request_Kind => Req, -- Param => Par, -- Dispatch => Dispatch); -- -- [...] -- declare -- P : Par(REQ2); -- begin -- -- fill parameters -- P.P2 := Val; -- -- Release the task -- -- My_Sporadic_Server.Put_Request(P); with System; with Ada.Real_Time; generic Task_Priority : System.Priority; -- the priority of the server Minimum_Interelease_Time : Millisecond; -- the minimum time between two consecutive releases System_Start_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock; -- the absolute instant in time for the release of the systems as a whole Protocol_Ceiling : System.Any_Priority; -- the ceiling priority of the protected object used to post and fetch -- requests QS : Queue_Size; -- the size of accepted requests type Request_Kind is (<>); -- an enumeration type identificng the possible kinds of request type Request is private; -- the reified request type with procedure Dispatch (Req : Request); -- the procedure invoked by the server to dispatch the fetched request package GNATCOLL.Ravenscar.Multiple_Queue_Sporadic_Server is procedure Put_Request (Req : Request; Kind : Request_Kind); -- Invoked by clients to post reified requests to be fetched and executed -- by the server private type Request_Type_Ref is access all Request; -- pointer type for request type Request_Queue is array (1 .. QS) of aliased Request; -- physical queue for posted requests type All_Queue is array (Request_Kind'Range) of Request_Queue; -- the entire set of queues (one for each possible request) type All_Queue_Index is array (Request_Kind'Range) of Queue_Range; -- type to collect all indexes to access requests Pointer_Queue_Range_Max : constant Integer := QS; -- maximum index value type Pointer_Queue_Item is record Kind : Request_Kind; Req : Request_Type_Ref; end record; -- reified request descriptor saved in a queue type Pointer_Queue_Item_Ref is access all Pointer_Queue_Item; -- pointer type to reified request descriptors type Pointer_Queue is array (Integer range 1 .. Pointer_Queue_Range_Max) of aliased Pointer_Queue_Item; -- logical queue of posted requests protected Protocol is -- the protected object used to post/fetch requests pragma Priority (Protocol_Ceiling); procedure Put (Req : Request; Kind : Request_Kind); entry Get (Req : out Request; Release_Time : out Ada.Real_Time.Time); private Barrier : Boolean := False; Queues : All_Queue; Insert_Index : All_Queue_Index := (others => 1); Pending : Integer := 0; Ptr_Queue : Pointer_Queue := (others => (Request_Kind'First, null)); Pointer_Queue_Insert_Index : Integer := 1; Pointer_Queue_Extract_Index : Integer := 1; Pointer_Queue_Overflow : Boolean := False; end Protocol; task Sporadic_Task is pragma Priority (Task_Priority); end Sporadic_Task; -- the cyclic server end GNATCOLL.Ravenscar.Multiple_Queue_Sporadic_Server; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-simple_cyclic_task.adb000066400000000000000000000050731425465243200272060ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Ravenscar.Simple_Cyclic_Task is task body Simple_Cyclic_Task is use Ada.Real_Time; Next_Time : Time := System_Start_Time + Milliseconds (Phase); begin loop delay until Next_Time; Cyclic_Operation; Next_Time := Next_Time + Milliseconds (Period); end loop; end Simple_Cyclic_Task; end GNATCOLL.Ravenscar.Simple_Cyclic_Task; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-simple_cyclic_task.ads000066400000000000000000000072331425465243200272270ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- A simple archetype of a Ravenscar-compliant cyclic task. The task is meant -- to be released at a constant time interval and to execute at -- a contant priority level (a part when subject to the immediate priority -- ceiling protocol). -- -- The task timing behaviour can be analyzed with the most common timing -- analysis techniques. -- -- A typical example of usage is the following: -- -- procedure Cyclic_Operation; -- package My_Cyclic_Task is new GNATCOLL.Ravenscar.Simple_Cyclic_Task -- (Task_Priority => 10, -- Phase => 1_000, -- Period => 1_000, -- System_Start_Time => System_Properties.Start_UP_Time, -- Cyclic_Operation => Cyclic_Operation); -- -- The instantiation generates a cyclic task which executes at priority 10, -- is released for the first time at System_UP_Time + Phase, executes -- Cyclic_Operation, and suspends itself until Period milliseconds have passed -- from the previous release. with System; with Ada.Real_Time; generic Task_Priority : System.Priority; -- the task priority Phase : Millisecond; -- the task phse Period : Millisecond; -- the task period System_Start_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock; -- system-wide release instant with procedure Cyclic_Operation; -- the nominal operation package GNATCOLL.Ravenscar.Simple_Cyclic_Task is private task Simple_Cyclic_Task is pragma Priority (Task_Priority); end Simple_Cyclic_Task; end GNATCOLL.Ravenscar.Simple_Cyclic_Task; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-simple_sporadic_task.adb000066400000000000000000000065021425465243200275420ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Ravenscar.Simple_Sporadic_Task is procedure Release is begin Protocol.Release; end Release; protected body Protocol is procedure Update_Barrier is begin Barrier := Pending > 0; end Update_Barrier; pragma Inline (Update_Barrier); procedure Release is begin Pending := Pending + 1; Update_Barrier; end Release; entry Wait (Release_Time : out Ada.Real_Time.Time) when Barrier is begin -- keep track of the release instant to guarantee a faithful -- interelease time Release_Time := Ada.Real_Time.Clock; Pending := Pending - 1; Update_Barrier; end Wait; end Protocol; task body Simple_Sporadic_Task is use Ada.Real_Time; Next_Time : Time := System_Start_Time; Release_Time : Time; begin loop delay until Next_Time; Protocol.Wait (Release_Time); Sporadic_Operation; Next_Time := Release_Time + Milliseconds (Minimum_Interelease_Time); end loop; end Simple_Sporadic_Task; end GNATCOLL.Ravenscar.Simple_Sporadic_Task; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-simple_sporadic_task.ads000066400000000000000000000114561425465243200275670ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- A simple archetype of a Ravenscar-compliant sporadic task. The task is -- meant to enforce a minimum interelease interval and to execute at a contant -- priority level (a part when subject to the immediate priority ceiling -- protocol). The suspension/release mechanism is managed by a protected -- object. In the worst case, the task behaviour is identical to the behaviour -- of a cyclic task (GNAT.Ravenscar.Simple_Cyclic_Task) with Period = -- Minimum_Interelease_Time. -- -- The task timing behaviour can be analyzed with the most common timing -- analysis techniques. -- -- A typical example of usage is the following: -- -- procedure Sporadic_Operation; -- package My_Sporadic_Task is new GNATCOLL.Ravenscar.Simple_Sporadic_Task -- (Task_Priority => 10, -- Minimum_Interelease_Time => 1_000, -- Protocol_Ceiling => 15, -- System_Start_Time => System_Properties.Start_UP_Time, -- Sporadic_Operation => Sporadic_Operation); -- -- [...] -- -- Release the task -- -- My_Sporadic_Task.Release; -- [...] -- -- The instantiation generates a sporadic task which executes at priority 10, -- is ready to executed starting from System_UP_Time + Phase, executes -- Sporadic_Operation, and enforce a minimum interelease time of 1000 -- milliseconds. Protocol_Ceiling is the ceiling priority of the protected -- object managing the suspension/release mechanism of the task: the protected -- object is accessed by both the clients (via Release) and the sporadic task -- itself. Protocol_Ceiling must be equal to the priority of the client with -- the highest priority, including the task itself (Task_Priority). with Ada.Real_Time; with System; generic Task_Priority : System.Priority; -- The priority of the task Minimum_Interelease_Time : Millisecond; -- The minimum time between two consecutive releases System_Start_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock; -- the system-wide relase time Protocol_Ceiling : System.Any_Priority; -- the ceiling priority of the protected object used to post and fetch -- requests with procedure Sporadic_Operation; -- the nominal operation package GNATCOLL.Ravenscar.Simple_Sporadic_Task is procedure Release; -- used by client to trigger the task private protected Protocol is pragma Priority (Protocol_Ceiling); procedure Release; entry Wait (Release_Time : out Ada.Real_Time.Time); private Barrier : Boolean := False; Pending : Integer := 0; end Protocol; task Simple_Sporadic_Task is pragma Priority (Task_Priority); end Simple_Sporadic_Task; end GNATCOLL.Ravenscar.Simple_Sporadic_Task; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-sporadic_server.adb000066400000000000000000000107741425465243200265430ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Ravenscar.Utils; package body GNATCOLL.Ravenscar.Sporadic_Server is use GNATCOLL.Ravenscar.Utils; procedure Put_Request (Par : Param) is begin -- just a delegation Protocol.Put_Request (Par); end Put_Request; protected body Protocol is procedure Update_Barrier is begin Barrier := Pending > 0; end Update_Barrier; pragma Inline (Update_Barrier); procedure Put_Request (Par : Param) is begin Buffer (Insert_Index) := Par; Increase_Counter (Insert_Index, QS); -- Check if with the posting of this message, the Insert_Index is -- greater of the extract index: if so, increase also the extract -- index to avoid fetching a newer request when older ones are -- pending if Buffer_Overflow then Increase_Counter (Extract_Index, QS); end if; -- increase the number of pending request but do not overcome the -- maximum if Pending < QS then Pending := Pending + 1; end if; -- If Insert_Index = Extract_Index, then at the next posting an -- overflow may occour if Insert_Index = Extract_Index then Buffer_Overflow := True; end if; Update_Barrier; end Put_Request; entry Get_Request (Release_Time : out Ada.Real_Time.Time; Par : out Param) when Barrier is begin -- get the real release time Release_Time := Ada.Real_Time.Clock; -- cancel the overflow if fetching request if Extract_Index = Insert_Index then Buffer_Overflow := False; end if; Par := Buffer (Extract_Index); Increase_Counter (Extract_Index, QS); Pending := Pending - 1; Update_Barrier; end Get_Request; end Protocol; task body Sporadic_Task is use Ada.Real_Time; Next_Time : Time := System_Start_Time; Release_Time : Time; Par : Param; begin loop delay until Next_Time; Protocol.Get_Request (Release_Time, Par); Sporadic_Operation (Par); Next_Time := Release_Time + Milliseconds (Minimum_Interelease_Time); end loop; end Sporadic_Task; end GNATCOLL.Ravenscar.Sporadic_Server; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-sporadic_server.ads000066400000000000000000000115241425465243200265560ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- A simple archetype of a Ravenscar-compliant sporadic server: it extends the -- sporadic task archetype (GNAT.RAVENSCAR.Simple_Sporadic_Task) by permitting -- to carry parameters for the release of the task. The sporadic operation is -- of course called in a deferred way, so parameters are always IN by -- construction. -- -- A typical example of usage is the following: -- -- type Par is ... -- procedure Sporadic_Operation(P : Par); -- package My_Sporadic_Server is new GNATCOLL.Ravenscar.Sporadic_Server -- (Task_Priority => 10, -- Minimum_Interelease_Time => 1_000, -- Protocol_Ceiling => 15, -- System_Start_Time => System_Properties.Start_UP_Time, -- QS => 4, -- Param => Par, -- Sporadic_Operation => Sporadic_Operation); -- -- [...] -- declare -- P : Par; -- begin -- -- Release the task -- -- My_Sporadic_Server.Put_Request(P); -- -- -- Explanations for GNAT.Ravenscar.Sporadic_Task still hold; QS is the -- maximium numbered of buffered requests, which are executed following a FIFO -- policy. with System; with Ada.Real_Time; generic Task_Priority : System.Priority; -- The priority of the task Minimum_Interelease_Time : Millisecond; -- The minimum time between two consecutive releases System_Start_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock; -- the system-wide relase time Protocol_Ceiling : System.Any_Priority; -- the ceiling priority of the protected object used to post and fetch -- requests QS : Queue_Size; -- the maximum number of buffered requests type Param is private; -- the descriptor of the request to be fulfilled by the server with procedure Sporadic_Operation (Par : Param); -- the procedure to be executed by the server package GNATCOLL.Ravenscar.Sporadic_Server is procedure Put_Request (Par : Param); -- Invoked by the client to post as request and trigger the server private type Queue is array (1 .. QS) of Param; -- the queue containing reified requests protected Protocol is -- the protected object containing the request queue pragma Priority (Protocol_Ceiling); procedure Put_Request (Par : Param); entry Get_Request (Release_Time : out Ada.Real_Time.Time; Par : out Param); private Barrier : Boolean := False; Pending : Integer := 0; Insert_Index : Integer := 1; Extract_Index : Integer := 1; Buffer : Queue; Buffer_Overflow : Boolean := False; end Protocol; task Sporadic_Task is pragma Priority (Task_Priority); end Sporadic_Task; -- the sporadic server end GNATCOLL.Ravenscar.Sporadic_Server; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-sporadic_server_with_callback.adb000066400000000000000000000053371425465243200314110ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Ravenscar.Sporadic_Server_With_Callback is procedure Put_Request (In_Par : In_Param; CB : Callback) is begin -- a simple delegation My_Sporadic_Task.Put_Request ((In_Par, CB)); end Put_Request; procedure Dispatch (Req : Queue_Item) is Out_Par : Out_Param; begin -- first execute the nominal operation Sporadic_Operation (Req.In_Par, Out_Par); -- then the callback Req.CB.all (Out_Par); end Dispatch; end GNATCOLL.Ravenscar.Sporadic_Server_With_Callback; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-sporadic_server_with_callback.ads000066400000000000000000000126051425465243200314260ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- Ravenscar tasks always communicate via messages or shared resources. It is -- thus not possible to have a deferred operation (an operation executed by a -- dedicated task) which carries OUT parameters. This archetype shows a -- solution to this expressive limit by extending -- GNAT.Ravenscar.Sporadic_Server. Clients release the server passing IN -- parameters and a pointer to a procedure: the latter is automatically -- called passing the computed value of OUT parameters of the deferred -- operation executed by the sporadic server. -- -- A tipical example of usage is the following: -- -- type IN_Param is ... -- type OUT_Param is ... -- procedure Sporadic_Operation(In_P : IN_Param; OUT_P : out OUT_Param); -- procedure CallBack (P : OUT_Param); -- package My_Sporadic_Server is -- new GNATCOLL.Ravenscar.Sporadic_Server_With_Callback -- Task_Priority => 10, -- Minimum_Interelease_Time => 1_000, -- Protocol_Ceiling => 15, -- System_Start_Time => System_Properties.Start_UP_Time, -- QS => 4, -- IN_Param_Type => IN_Param, -- OUT_Param_Type => IOUT_Param, -- Sporadic_Operation => Sporadic_Operation); -- -- [...] -- declare -- P : IN_Param; -- begin -- -- Release the task -- -- My_Sporadic_Server.Put_Request(P, Callback'access); -- -- BEHAVIOUR: -- My_Sporadic_Server executes Sporadic_Operation and Callback passing as -- parameters the values computed by Sporadic_Operation. -- -- Additional explanations for GNAT.Ravenscar.Sporadic_Server still hold. with System; with Ada.Real_Time; with GNATCOLL.Ravenscar.Sporadic_Server; generic Task_Priority : System.Priority; -- the task priority Minimum_Interelease_Time : Millisecond; -- the minimum time between two consecutive releases System_Start_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock; -- the system-wide release instant Protocol_Ceiling : System.Any_Priority; -- the ceiling priority of the protected object used to post and fetch -- requests QS : Queue_Size; -- the maximum amount of saved requests type In_Param is private; -- the descriptor of IN parameters type Out_Param is private; -- the descriptor of OUT parameters with procedure Sporadic_Operation (In_Par : In_Param; Out_par : out Out_Param); -- the nominal operation package GNATCOLL.Ravenscar.Sporadic_Server_With_Callback is type Callback is access procedure (Out_Par : Out_Param); -- the type of the callback procedure Put_Request (In_Par : In_Param; CB : Callback); -- invoked by clients to put requests (and corresponding callback) private type Queue_Item is record In_Par : In_Param; CB : Callback; end record; -- a reifed request descriptor containing IN parameters and callback procedure Dispatch (Req : Queue_Item); -- the dispatch procedure first executes the posted request and then -- the callback package My_Sporadic_Task is new GNATCOLL.Ravenscar.Sporadic_Server (Task_Priority, Minimum_Interelease_Time, System_Start_Time, Protocol_Ceiling, QS, Queue_Item, Dispatch); -- a sporadic server to execute reqeusts end GNATCOLL.Ravenscar.Sporadic_Server_With_Callback; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-timed_out_sporadic_server.adb000066400000000000000000000071521425465243200306100ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Ravenscar.Timed_Out_Sporadic_Server is procedure Put_Request (Par : Param) renames Timed_Out_Sporadic_Server.Put_Request; procedure Handler is begin Ada.Synchronous_Task_Control.Set_True (Timer_Server_Suspender); end Handler; task body Timer_Server is use Ada.Real_Time; begin loop -- set to False the suspension object Ada.Synchronous_Task_Control.Set_False (Timer_Server_Suspender); -- wait on the suspension object to be set to true by the timing -- event Ada.Synchronous_Task_Control.Suspend_Until_True (Timer_Server_Suspender); -- when triggered, execute the handler Time_Out_Handler; -- and set the next release instant for the timer to Clock + -- Maximum_Interelease_Time My_Timer.Set (Clock + Milliseconds (Maximum_Interelease_Time), Handler_Access); end loop; end Timer_Server; procedure Timed_Out_Sporadic_Operation (Par : Param) is use Ada.Real_Time; Next_Time_Out_Instant : constant Ada.Real_Time.Time := Clock + Milliseconds (Maximum_Interelease_Time); begin -- Set the timer to the next instant My_Timer.Set (Next_Time_Out_Instant, Handler_Access); -- execute the operation Sporadic_Operation (Par); end Timed_Out_Sporadic_Operation; end GNATCOLL.Ravenscar.Timed_Out_Sporadic_Server; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-timed_out_sporadic_server.ads000066400000000000000000000142751425465243200306350ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- Ravenscar constraints prohibit the use of language-level timeout facilities -- (via the select statement). This archetype manage to mimic the semantics of -- a timeout within Ravenscar constraints: if the server is not released -- (via Put_Request) within Maximum_Interelase_Time, it is automatically -- released by the run-time and invokes an appropriate, user-specified handler -- -- A typical example of usage is the following: -- -- type Par is ... -- procedure Sporadic_Operation(P : Par); -- procedure Handler; -- package My_Sporadic_Server is new Ravenscar.Timed_Out_Sporadic_Server -- (Task_Priority => 10, -- Minimum_Interelease_Time => 1_000, -- Maximum_Interelease_Time => 2_000, -- wait at most 2 seconds -- Protocol_Ceiling => 15, -- System_Start_Time => System_Properties.Start_UP_Time, -- QS => 4, -- Param => Par, -- Sporadic_Operation => Sporadic_Operation, -- Time_Out_Handler => Handler); -- -- [...] -- declare -- P : Par; -- begin -- -- Release the task -- -- My_Sporadic_Server.Put_Request(P); -- -- BEHAVIOUR -- If the time elapsed between two consecutive releases of the server is -- greater then Maximimum_Interelease_Time, then Handler is invoked. -- -- Explanations for GNAT.Ravenscar.Sporadic_Server still hold. -- -- NOTE FOR THE ANALYSIS: the pattern is implemented as follows: -- (1) A Timer is set to expires at each Maximum_Interelease_Time -- (a) I can be deleted and re-set if the server is released -- (b) If it expires, it release an additional task (see point 2) -- (2) An additional sporadic task with minimum_interarrival_time = -- maximum_interarrival_time is suspended waiting to be released by the -- timer at point (1): this task executes the handler. It suspends on a -- Suspension_Object. with Ada.Real_Time; with System; with Ada.Synchronous_Task_Control; with GNATCOLL.Ravenscar.Sporadic_Server; with GNATCOLL.Ravenscar.Timers.One_Shot_Timer; generic Task_Priority : System.Priority; -- The priority of the task Minimum_Interelease_Time : Millisecond; -- The minimum time between two consecutive releases Maximum_Interelease_Time : Millisecond; -- the maximum interrelease time which trigger the automatic release -- of the server System_Start_Time : Ada.Real_Time.Time := Ada.Real_Time.Clock; -- the system-wide relase time Protocol_Ceiling : System.Any_Priority; -- the ceiling priority of the protected object used to post and fetch -- requests QS : Queue_Size; -- the maximum number of saved requests type Param is private; -- the request descriptor with procedure Sporadic_Operation (Par : Param); -- the procedure invoked when the server is released by the client with procedure Time_Out_Handler; -- the handler executed by the server when non released the maximum -- interrelease time package GNATCOLL.Ravenscar.Timed_Out_Sporadic_Server is procedure Put_Request (Par : Param); -- invoked by the clients private procedure Timed_Out_Sporadic_Operation (Par : Param); package Timed_Out_Sporadic_Server is new Sporadic_Server (Task_Priority, Minimum_Interelease_Time, System_Start_Time, Protocol_Ceiling, QS, Param, Timed_Out_Sporadic_Operation); -- The sporadic server Timer_Server_Suspender : Ada.Synchronous_Task_Control.Suspension_Object; -- A suspension object for the timer server (see below) task Timer_Server is pragma Priority (Task_Priority); end Timer_Server; -- The task which is triggered by the timer. We have an additional task -- to avoid having the timer itself to execute (it runs at interrupt -- priority). package My_Timer is new GNATCOLL.Ravenscar.Timers.One_Shot_Timer; -- the timer triggering the task if no request is posted within -- the maximum interrelease time procedure Handler; Handler_Access : constant GNATCOLL.Ravenscar.Timers.Timer_Action := Handler'Access; end GNATCOLL.Ravenscar.Timed_Out_Sporadic_Server; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-timers-one_shot_timer.adb000066400000000000000000000064751425465243200276730ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Ravenscar.Timers.One_Shot_Timer is --------- -- Set -- --------- procedure Set (Instant : Ada.Real_Time.Time; Action : Timer_Action) is begin -- Set the timer Events.Set_Action (Instant, Action); end Set; ------------ -- Cancel -- ------------ procedure Cancel (Success : out Boolean) is begin -- cancel the timer Ada.Real_Time.Timing_Events.Cancel_Handler (The_Event, Success); end Cancel; protected body Events is ------------- -- Handler -- ------------- procedure Handler (Event : in out Ada.Real_Time.Timing_Events.Timing_Event) is pragma Unreferenced (Event); begin The_Action.all; end Handler; ---------------- -- Set_Action -- ---------------- procedure Set_Action (Instant : Ada.Real_Time.Time; Action : Timer_Action) is begin The_Action := Action; Ada.Real_Time.Timing_Events.Set_Handler (The_Event, Instant, Events_Handler); end Set_Action; end Events; end GNATCOLL.Ravenscar.Timers.One_Shot_Timer; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-timers-one_shot_timer.ads000066400000000000000000000064151425465243200277060ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- A Ravenscar-compliant one-shot timer with System; with Ada.Real_Time; with Ada.Real_Time.Timing_Events; generic package GNATCOLL.Ravenscar.Timers.One_Shot_Timer is procedure Set (Instant : Ada.Real_Time.Time; Action : Timer_Action); -- Set the timer to an absolute instant in time to execute a specific -- action. procedure Cancel (Success : out Boolean); -- cancel the timer private The_Event : Ada.Real_Time.Timing_Events.Timing_Event; -- the timing event protected Events is -- the handler used to invoke the user-provided action (see procedure -- Set). pragma Priority (System.Any_Priority'Last); procedure Handler (Event : in out Ada.Real_Time.Timing_Events.Timing_Event); procedure Set_Action (Instant : Ada.Real_Time.Time; Action : Timer_Action); private The_Action : GNATCOLL.Ravenscar.Timers.Timer_Action; end Events; Events_Handler : constant Ada.Real_Time.Timing_Events.Timing_Event_Handler := Events.Handler'Access; end GNATCOLL.Ravenscar.Timers.One_Shot_Timer; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-timers.ads000066400000000000000000000044761425465243200246770ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- Contains types for Ravenscar timers package GNATCOLL.Ravenscar.Timers is type Timer_Action is access procedure; end GNATCOLL.Ravenscar.Timers; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-utils.adb000066400000000000000000000047721425465243200245120ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Ravenscar.Utils is procedure Increase_Counter (Counter : in out Integer; Max : Integer; Min : Integer := 1) is begin if Counter = Max then Counter := Min; else Counter := Counter + 1; end if; end Increase_Counter; end GNATCOLL.Ravenscar.Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar-utils.ads000066400000000000000000000047301425465243200245250ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- A collection of untilities used in GNATCOLL.Ravenscar package GNATCOLL.Ravenscar.Utils is procedure Increase_Counter (Counter : in out Integer; Max : Integer; Min : Integer := 1); -- A procedure to increase a counter up to a maximum limit end GNATCOLL.Ravenscar.Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-ravenscar.ads000066400000000000000000000051561425465243200233720ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with GNAT; see file COPYING. If not, write -- -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, -- -- Boston, MA 02110-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- This package contains a set of archetypes and patterns for concurrent -- programming using Ravenscar-compliant semantics only. The patterns are thus -- meant to be compiled with pragma Profile(Ravenscar) and run on Ravenscar -- run-time. package GNATCOLL.Ravenscar is subtype Millisecond is Integer range 0 .. Integer'Last; subtype Queue_Size is Integer range 2 .. Integer'Last; subtype Queue_Range is Positive; end GNATCOLL.Ravenscar; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-refcount-weakref.adb000066400000000000000000000107031425465243200246260ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Atomic; use GNATCOLL.Atomic; package body GNATCOLL.Refcount.Weakref is use Proxy_Pointers; ---------- -- Free -- ---------- overriding procedure Free (Self : in out Weak_Refcounted) is begin if Self.Proxy /= Proxy_Pointers.Null_Ref then Proxy (Get (Self.Proxy).all).Proxied := null; Self.Proxy := Proxy_Pointers.Null_Ref; end if; Free (Refcounted (Self)); -- ??? static call to a "null" procedure end Free; ---------------------- -- Weakref_Pointers -- ---------------------- package body Weakref_Pointers is use Pointers; ------------------ -- Get_Weak_Ref -- ------------------ function Get_Weak_Ref (Self : Ref'Class) return Weak_Ref is Data : constant Encapsulated_Access := Self.Get; P : Proxy_Pointers.Ref; D : Proxy_Pointers.Encapsulated_Access; begin if Data = null then return Null_Weak_Ref; end if; P := GNATCOLL.Refcount.Weakref.Weak_Refcounted'Class (Data.all).Proxy; if P = Proxy_Pointers.Null_Ref then D := new Proxy'(GNATCOLL.Refcount.Refcounted with Proxied => Refcounted_Access (Data)); Set (P, D); -- now owns a reference to D Weak_Refcounted'Class (Data.all).Proxy := P; end if; return Weak_Ref (P); end Get_Weak_Ref; --------------- -- Was_Freed -- --------------- function Was_Freed (Self : Weak_Ref'Class) return Boolean is P : constant access Proxy := Proxy_Pointers.Get (Proxy_Pointers.Ref (Self)); begin return P = null or else P.Proxied = null; end Was_Freed; --------- -- Get -- --------- procedure Get (Self : Weak_Ref'Class; R : out Ref'Class) is P : constant access Proxy := Proxy_Pointers.Get (Proxy_Pointers.Ref (Self)); begin if Was_Freed (Self) then R.Set (null); else -- A subtetly here: it is possible that the element is actually -- being freed, and Free() is calling Get on one of the weakref. -- In such a case, we do not want to resuscitate the element if P.Proxied.Refcount = 0 then R.Set (null); else -- Adds a reference to P.Proxied R.Set (Encapsulated_Access (P.Proxied)); end if; end if; end Get; --------- -- Get -- --------- function Get (Self : Weak_Ref'Class) return Ref is Result : Ref; begin Get (Self, Result); return Result; end Get; end Weakref_Pointers; end GNATCOLL.Refcount.Weakref; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-refcount-weakref.ads000066400000000000000000000160771425465243200246610ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- By definition, an object can never be freed while there are references -- to it. -- However, this simple scheme fails in some cases. For instance, imagine -- you want to cache some refcounted type into a map. The map would then -- own a reference to the object, which is thus never freed while the map -- exists (presumably for the life of your application). -- A solution to this problem is the notion of "weak reference": these act -- as containers that point to the element, without owning a reference to -- them. When the element is destroyed (because its refcount can now reach -- 0), the container is set to a special state that indicates the element -- no longer exists. -- With this scheme, the cache will still contain entries for the elements, -- but those entries will return a Null_Ref when accessed. package GNATCOLL.Refcount.Weakref is pragma Obsolescent (Weakref, "Use GNATCOLL.Refcount.Shared_Pointers"); type Weak_Refcounted is abstract new GNATCOLL.Refcount.Refcounted with private; -- A special refcounted type, which can manipulate weak references overriding procedure Free (Self : in out Weak_Refcounted); -- If you need to override this procedure in your own code, you need to -- make sure you correctly call this inherited procedure. type Proxy is new GNATCOLL.Refcount.Refcounted with record Proxied : Refcounted_Access; end record; package Proxy_Pointers is new Smart_Pointers (Proxy); -- An internal, implementation type. -- -- A weak ref acts as a smart pointed with two level of indirection: -- type My_Type is new GNATCOLL.Refcount.Weakref.Refcounted with ...; -- package P is new Weakref_Pointers (My_Type); -- R : P.Ref; -- WR : P.Weak_Ref; -- R now takes care of the reference counting for R.Data. -- R.Data is an access to My_Type, freed automatically. -- -- WR now takes care of the reference counting for a Proxy, whose Proxied -- is set to R.Data. This does not hold a reference to R.Data. However, -- R.Data holds a reference to the proxy. -- As a result, the proxy is never freed while R.Data exists. But the -- latter can be destroyed even when the proxy exists. generic type Encapsulated is abstract new Weak_Refcounted with private; package Weakref_Pointers is package Pointers is new Smart_Pointers (Encapsulated); subtype Encapsulated_Access is Pointers.Encapsulated_Access; subtype Ref is Pointers.Ref; Null_Ref : constant Ref := Pointers.Null_Ref; procedure Set (Self : in out Ref; Data : Encapsulated'Class) renames Pointers.Set; procedure Set (Self : in out Ref; Data : access Encapsulated'Class) renames Pointers.Set; function Get (P : Ref) return Encapsulated_Access renames Pointers.Get; function "=" (P1, P2 : Ref) return Boolean renames Pointers."="; function "=" (P1, P2 : Pointers.Encapsulated_Access) return Boolean renames Pointers."="; -- The manipulation of the smart pointers subtype Weak_Ref is Proxy_Pointers.Ref; Null_Weak_Ref : constant Weak_Ref := Weak_Ref (Proxy_Pointers.Null_Ref); function "=" (P1, P2 : Weak_Ref) return Boolean renames Proxy_Pointers."="; function Get_Weak_Ref (Self : Ref'Class) return Weak_Ref; -- Return a weak reference to Self. -- It does not hold a reference to Self, which means that Self could be -- destroyed while the weak reference exists. However, this will not -- result -- in a Storage_Error when you access the reference. function Was_Freed (Self : Weak_Ref'Class) return Boolean; -- True if the weakly referenced element was freed (thus Get would -- return Null_Ref). It is more efficient to use this function than -- compare the result of Get with Null_Ref, since the latter will need -- to play with refcounting. function Get (Self : Weak_Ref'Class) return Ref; procedure Get (Self : Weak_Ref'Class; R : out Ref'Class); -- Return the weakly referenced object. This will return Null_Ref -- if the object has already been destroyed. -- The procedure version can be used if you have subclassed Ref. -- The code should look like: -- -- -- Create the smart pointer -- Tmp : Refcounted_Access := new My_Refcounted_Type; -- R : Ref := Allocate (Tmp); -- Hold a ref to Tmp -- -- WRef := Get_Weak_Ref (R); -- Does not hold a ref to Tmp -- -- R := Null_Ref; -- Releases ref to Tmp, and free Tmp -- we now have Get (WRef) = null -- -- In the case of a multitasking application, you must write your code -- so that the referenced type is not freed while you are using it. For -- instance: -- declare -- R : constant Ref := Get (WRef); -- hold a ref to Tmp -- begin -- if R /= Null_Ref then -- ... manipulate R -- Tmp cannot be freed while in the declare block, since we -- own a reference to it -- end if; -- end; end Weakref_Pointers; private type Weak_Refcounted is abstract new GNATCOLL.Refcount.Refcounted with record Proxy : Proxy_Pointers.Ref; -- Hold a reference to a proxy end record; end GNATCOLL.Refcount.Weakref; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-refcount.adb000066400000000000000000000307111425465243200232050ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Notes on the implementation of weak pointers: -- There are several ways in which a weak pointer can be implemented: -- - Using two counters (one for full references, one for weak). When both -- reach 0, the memory blocks is freed; when only the first reaches 0, -- the element is released, and the block can be resized. -- This is hard to make task safe without using critical section though. -- - store a doubly-linked list of weak pointers along with the counter. -- When the counter reaches 0, change each of the weak pointers to null. -- This requires more memory. -- - (our choice) make the weak pointer a smart pointer pointing to the -- same data: -- smart_ptr ---> chunk1: counter + element + pointer to chunk2 -- weak_ptr ---> chunk2: weak_counter + pointer to chunk1 pragma Ada_2012; with Ada.Finalization; use Ada.Finalization; with Ada.Unchecked_Conversion; with Ada.Unchecked_Deallocation; with GNATCOLL.Atomic; use GNATCOLL.Atomic; with System.Memory; use System, System.Memory; package body GNATCOLL.Refcount is procedure Inc_Ref (R : access Counters; Atomic : Boolean) with Inline => True; procedure Inc_Ref (R : access Weak_Data; Atomic : Boolean) with Inline => True; -- Increase/Decrease the refcount, and return the new value procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Weak_Data, Weak_Data_Access); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Refcounted'Class, Refcounted_Access); procedure Finalize (Data : in out Weak_Data_Access; Atomic : Boolean); -- Decrease refcount, and free memory if needed function Sync_Bool_Compare_And_Swap is new GNATCOLL.Atomic.Sync_Bool_Compare_And_Swap (Weak_Data, Weak_Data_Access); ------------- -- Inc_Ref -- ------------- procedure Inc_Ref (R : access Counters; Atomic : Boolean) is begin if Atomic then Increment (R.Refcount); else Unsafe_Increment (R.Refcount); end if; end Inc_Ref; procedure Inc_Ref (R : access Weak_Data; Atomic : Boolean) is begin if Atomic then Increment (R.Refcount); else Unsafe_Increment (R.Refcount); end if; end Inc_Ref; -------------- -- Finalize -- -------------- procedure Finalize (Data : in out Weak_Data_Access; Atomic : Boolean) is begin if Atomic then if Decrement (Data.Refcount) then Unchecked_Free (Data); end if; else if Unsafe_Decrement (Data.Refcount) then Unchecked_Free (Data); end if; end if; Data := null; end Finalize; --------------------- -- Shared_Pointers -- --------------------- package body Shared_Pointers is use type Pools.Element_Access; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Element_Type, Pools.Element_Access); pragma Warnings (Off, "*possible aliasing problem*"); function Convert is new Ada.Unchecked_Conversion (Pools.Element_Access, System.Address); function Convert is new Ada.Unchecked_Conversion (System.Address, Pools.Element_Access); pragma Warnings (On, "*possible aliasing problem*"); --------- -- Set -- --------- procedure Set (Self : in out Ref'Class; Data : Element_Type) is R : access Counters; begin Finalize (Self); Self.Data := new Element_Type'(Data); -- uses storage pool R := Pools.Header_Of (Self.Data); R.Refcount := 1; R.Weak_Data := null; end Set; ------------------- -- Unchecked_Get -- ------------------- function Unchecked_Get (Self : Ref'Class) return Element_Access is begin return Self.Data; end Unchecked_Get; ------------- -- Process -- ------------- procedure Process (Self : Ref'Class; Process : not null access procedure (E : Element_Type)) is begin Process (Self.Data.all); end Process; ------------- -- Is_Null -- ------------- function Is_Null (Self : Ref'Class) return Boolean is begin return Self.Data = null; end Is_Null; ---------- -- Weak -- ---------- function Weak (Self : Ref'Class) return Weak_Ref is R : access Counters; V : Weak_Data_Access; begin if Self.Data = null then return Null_Weak_Ref; end if; R := Pools.Header_Of (Self.Data); if R.Weak_Data = null then V := new Weak_Data' (Refcount => 2, -- hold by Self and the result Element => Convert (Self.Data)); if not Sync_Bool_Compare_And_Swap (R.Weak_Data'Access, Oldval => null, Newval => V) then -- Was set by another thread concurrently Unchecked_Free (V); -- Need to increase refcount for the old weak ref Inc_Ref (R.Weak_Data, Atomic_Counters); end if; else Inc_Ref (R.Weak_Data, Atomic_Counters); end if; return (Controlled with Data => R.Weak_Data); end Weak; --------- -- Set -- --------- procedure Set (Self : in out Ref'Class; Weak : Weak_Ref'Class) is begin Finalize (Self); if not Weak.Was_Freed then Self.Data := Convert (Weak.Data.Element); Inc_Ref (Pools.Header_Of (Self.Data), Atomic_Counters); end if; end Set; --------------- -- Was_Freed -- --------------- function Was_Freed (Self : Weak_Ref'Class) return Boolean is begin return Self.Data = null or else Self.Data.Element = System.Null_Address; end Was_Freed; --------- -- "=" -- --------- overriding function "=" (P1, P2 : Ref) return Boolean is begin return P1.Data = P2.Data; end "="; ------------ -- Adjust -- ------------ overriding procedure Adjust (Self : in out Ref) is begin if Self.Data /= null then Inc_Ref (Pools.Header_Of (Self.Data), Atomic_Counters); end if; end Adjust; ------------ -- Adjust -- ------------ overriding procedure Adjust (Self : in out Weak_Ref) is begin if Self.Data /= null then Inc_Ref (Self.Data, Atomic_Counters); end if; end Adjust; -------------- -- Finalize -- -------------- overriding procedure Finalize (Self : in out Weak_Ref) is Data : Weak_Data_Access := Self.Data; begin if Data /= null then Self.Data := null; Finalize (Data, Atomic_Counters); end if; end Finalize; -------------- -- Finalize -- -------------- overriding procedure Finalize (Self : in out Ref) is R : access Counters; Data : Pools.Element_Access := Self.Data; Tmp : Boolean; begin if Data /= null then Self.Data := null; R := Pools.Header_Of (Data); if Atomic_Counters then Tmp := Decrement (R.Refcount); else Tmp := Unsafe_Decrement (R.Refcount); end if; if Tmp then if R.Weak_Data /= null then R.Weak_Data.Element := System.Null_Address; Finalize (R.Weak_Data, Atomic_Counters); end if; Release (Data.all); Unchecked_Free (Data); -- using storage_pool end if; end if; end Finalize; ------------------ -- Get_Refcount -- ------------------ function Get_Refcount (Self : Ref'Class) return Natural is begin if Self.Data = null then return 0; else return Natural (Pools.Header_Of (Self.Data).Refcount); end if; end Get_Refcount; ------------------ -- From_Element -- ------------------ procedure From_Element (Self : out Ref'Class; Element : Element_Access) is begin if Self.Data /= Element then Finalize (Self); Self.Data := Element; Adjust (Self); end if; end From_Element; end Shared_Pointers; -------------------- -- Smart_Pointers -- -------------------- package body Smart_Pointers is --------- -- Set -- --------- procedure Set (Self : in out Ref; Data : access Encapsulated'Class) is begin if Self.Data = Refcounted_Access (Data) then -- Avoid finalizing Self.Data if we are going to reuse it return; end if; Finalize (Self); -- decrement reference count Self.Data := Refcounted_Access (Data); Adjust (Self); -- increment reference count if needed end Set; --------- -- Set -- --------- procedure Set (Self : in out Ref; Data : Encapsulated'Class) is Tmp : constant Encapsulated_Access := new Encapsulated'Class'(Data); begin Set (Self, Tmp); end Set; --------- -- Get -- --------- function Get (P : Ref) return Encapsulated_Access is begin return Encapsulated_Access (P.Data); end Get; --------- -- "=" -- --------- overriding function "=" (P1, P2 : Ref) return Boolean is begin return P1.Data = P2.Data; end "="; -------------- -- Finalize -- -------------- overriding procedure Finalize (P : in out Ref) is Data : Refcounted_Access := P.Data; begin -- Make Finalize idempotent, since it could be called several -- times for the same instance (RM 7.6.1(24)). P.Data := null; -- Test if refcount is > 0, in case we are already freeing this -- element. if Data /= null then if Decrement (Data.Refcount) then Free (Data.all); Unchecked_Free (Data); end if; end if; end Finalize; ------------ -- Adjust -- ------------ overriding procedure Adjust (P : in out Ref) is begin if P.Data /= null then Sync_Add_And_Fetch (P.Data.Refcount'Access, 1); end if; end Adjust; ------------------ -- Get_Refcount -- ------------------ function Get_Refcount (Self : Ref) return Natural is begin if Self.Data = null then return 0; else return Natural (Self.Data.Refcount); end if; end Get_Refcount; end Smart_Pointers; end GNATCOLL.Refcount; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-refcount.ads000066400000000000000000000432461425465243200232350ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides support for reference counting. A Smart_Pointer -- plays the role of an access type (although it is not an access type), and -- keeps a reference to the designated entity. When a smart pointer goes out -- of scope, the designated entity's reference count is automatically -- decremented. -- When the reference count reaches 0, the corresponding entity is freed. -- -- This package also provides support for weak pointers. These do not prevent -- the freeing of the object they point to. However, when that object is -- freed, the weak pointer is safely reset to null. -- -- Cycles of references will prevent the freeing of the memory, since the -- objects' refcounts will never reach 0. For instance, if you consider a -- tree, the parent could hold a reference (via a smart_pointer) to each of -- its children. Thus the children will exist for at least as long as their -- parents. However, if the children also point to their parents with a -- smart_pointer, the parent can never be freed in the first place. The -- solution is that the children should point to their parents through a weak -- pointer instead. -- -- This package provides two versions of such pointers: -- * Smart_Pointers is the older version (obsolescent). It is less -- efficient, and the element_type must derive from the Refcounted -- type. -- * Shared_Pointers is a more flexible API, where the element_type -- can be any unconstrained type. The implementation is also faster. pragma Ada_2012; private with Ada.Finalization; with System; with GNATCOLL.Atomic; with GNATCOLL.Storage_Pools.Headers; use GNATCOLL.Storage_Pools.Headers; pragma Warnings (Off, "* is an internal GNAT unit"); with System.Soft_Links; use System.Soft_Links; pragma Warnings (On, "* is an internal GNAT unit"); package GNATCOLL.Refcount is ------------------- -- Internal data -- ------------------- -- This section provides several types that are used in the implementation -- of this package. They are not useful for applications. type Weak_Data is record Element : System.Address := System.Null_Address; Refcount : aliased GNATCOLL.Atomic.Atomic_Counter; pragma Volatile (Refcount); end record; type Weak_Data_Access is access all Weak_Data; type Counters is record Refcount : aliased GNATCOLL.Atomic.Atomic_Counter := 1; pragma Volatile (Refcount); Weak_Data : aliased Weak_Data_Access := null; -- A pointer to the weak pointers'data. This data is created the -- first time we create a weak pointer. We hold a reference to that -- data, so that it can never be freed while at least one reference -- exists. end record; package Headers is new Header_Pools (Counters); Application_Uses_Tasks : constant Boolean := System.Soft_Links.Lock_Task /= System.Soft_Links.Task_Lock_NT'Access; -- Whether the tasking run time has been initialized. --------------------- -- Shared_Pointers -- --------------------- generic type Element_Type (<>) is private; -- The element that will be encapsulated within a smart pointer. -- We need to be able to copy it as part of Set. with procedure Release (Self : in out Element_Type) is null; -- This procedure should be used if you need to perform actions when -- the last reference to an element is removed. Typically, this is -- used to free element_type and its contents, when it is not a -- controlled type. Atomic_Counters : Boolean := Application_Uses_Tasks; -- Whether to use atomic (and thus thread-safe) counters. If set to -- True, the smart pointer is task safe. Of course, that does not -- mean that the Element_Type itself is task safe. -- This has a small impact on performance. package Shared_Pointers is pragma Suppress (All_Checks); Is_Task_Safe : constant Boolean := Atomic_Counters; -- Make the formal parameter visible to users of this package type Ref is tagged private; Null_Ref : constant Ref; -- This type acts like a pointer, but holds a reference to the object, -- which will thus never be freed while there exists at least one -- reference to it. type Weak_Ref is tagged private; Null_Weak_Ref : constant Weak_Ref; -- A weak reference to an object. The value returned by Get will be -- reset to null when the object is freed (because its last reference -- expired). Holding a weak reference does not prevent the deallocation -- of the object. package Pools is new Headers.Typed (Element_Type); subtype Element_Access is Pools.Element_Access; procedure Set (Self : in out Ref'Class; Data : Element_Type); pragma Inline (Set); -- A copy of Data will be put under control of Self, and freed when -- the last reference to it is removed. procedure From_Element (Self : out Ref'Class; Element : Element_Access); pragma Inline (From_Element); -- Given an element that is already under control of a -- shared pointer, returns the corresponding shared pointer. -- This is especially useful when the element_type is a tagged -- type. This element might be used for dynamic dispatching, but -- it might be necessary to retrieve the smart pointer: -- -- type Object is tagged private; -- package Pointers is new Shared_Pointers (Object'Class); -- use Pointers; -- -- procedure Method (Self : Object'Class) is -- R : Ref; -- begin -- From_Element (R, Self); -- end Method; -- -- R : Ref; -- R.Set (Obj); -- Method (R.Get); -- -- Warning: this must only be called when Element comes from a -- shared pointer, otherwise an invalid memory access will result. type Reference_Type (Element : access Element_Type) is limited null record with Implicit_Dereference => Element; -- A reference to an element_type. -- This type is used as the return value for Get, instead of an -- Element_Access, because it is safer: -- * applications cannot free the returned value (and -- they should never do it !) -- * the Element discriminant cannot be stored in a variable, -- so that prevents keeping a reference when it could be freed at -- any time. -- * since the type is limited, it is in general difficult to -- store it in records. This is intended, since the shared -- pointer itself should be stored instead (at the access type -- might be freed at any time). -- This type is often mostly transparent for the application. Assuming -- the Element_Type is defined as: -- -- type Element_Type is tagged record -- Field : Integer; -- end record; -- procedure Primitive (Self : Element_Type); -- procedure Primitive2 (Self : access Element_Type); -- -- then a shared pointer SP can be used as: -- -- SP.Get.Field := 1; -- SP.Get.Primitive1; -- SP.Get.Element.Primitive2; -- -- WARNING: -- The use of a reference_type ensures that Get can return an access to -- the object (more efficient than a copy when the objects are large), -- while preventing users from freeing the returned value. But this -- does not prevent all invalid cases. Using 'renames', for instance, -- can lead to invalid code, as in: -- -- package IP is new Shared_Pointers (Integer); -- use IP; -- R : Ref; -- R.Set (99); -- declare -- Int : Integer renames R.Get.Element.all; -- begin -- R := Null_Ref; -- Frees Int ! -- Put_Line (I'Img); -- Invalid memory access -- end; -- -- Another dangerous use is to have a procedure that receives the -- result of Get and modifies the shared pointer, as in: -- -- package OP is new Shared_Pointers (Object'Class); -- use OP; -- R : Ref; -- procedure Foo (Obj : Object'Class) is -- begin -- R := Null_Ref; -- freezes Obj ! -- end Foo; -- Foo (R.Get); -- -- The proper solution here is that Foo should receive the smart -- pointer itself, not the encapsulated value. function Unchecked_Get (Self : Ref'Class) return Element_Access with Inline_Always; -- A version that returns directly the element access. This is meant -- for easy conversion of existing code, but its use is discouraged -- in new code, where Get should be used instead. -- The resulting access must not be deallocated. Passing it to -- Set might also be dangerous if the Element_Type contains data -- that might be freed when other smart pointers are freed. -- It also must not be stored in a record (store Self instead). function Get (Self : Ref'Class) return Reference_Type is ((Element => Unchecked_Get (Self))) with Inline_Always; -- A safer version of Unchecked_Get. -- There is no performance penalty, since the compiler knows that a -- Reference_Type is in fact always of the same size and can be -- returned on the stack. -- It is safer because the associated access type cannot be converted -- to a non-local access type, nor freed. procedure Process (Self : Ref'Class; Process : not null access procedure (E : Element_Type)) with Inline; -- This procedure is similar to the function Get, but doesn't expose -- the access type to the user. -- This is safer than Get, since it avoids the multiple issues -- highlighted in the comments for Reference_Type (namely that Self -- might become null while the application holds a reference, which -- then references invalid memory). -- On the other hand, it is more awkward to use, and does not work if -- you need to pass multiple smart pointers. There is however nothing -- tricky in this procedure, since it simply calls -- Process (Self.Get) -- and the simple fact that Self is a parameter ensures it retains at -- least one reference during the execution of Process. -- -- If you want to always be on the safe side and prevevent users from -- using Get, you could add the following configuration pragma to your -- compilation: -- pragma Restrictions -- (No_Use_Of_Entity => GNATCOLL.Refcount.Shared_Pointers.Get); function Is_Null (Self : Ref'Class) return Boolean with Inline; -- Whether the data is unset. Using this function might avoid the -- need for a "use type Element_Access" in your code. overriding function "=" (P1, P2 : Ref) return Boolean with Inline; -- This operator checks whether P1 and P2 share the same pointer. -- When the pointers differ, this operator returns False even if the -- two pointed elements are equal. function Weak (Self : Ref'Class) return Weak_Ref; procedure Set (Self : in out Ref'Class; Weak : Weak_Ref'Class); -- Set returns a reference to the object. Otherwise, it would be -- possible for a procedure to retrieve a pointer from the weak -- reference, and then reference it throughout the procedure, even -- though the pointer might be freed in between. -- -- If Weak is Null_Weak_Ref, then the element pointed by Self simply -- loses a reference, and Self points to nothing on exit. function Was_Freed (Self : Weak_Ref'Class) return Boolean; -- True if the object referenced by Self was freed. function Get_Refcount (Self : Ref'Class) return Natural; -- Return the current reference count. -- This is mostly intended for debug purposes. private type Ref is new Ada.Finalization.Controlled with record Data : Element_Access; end record; pragma Finalize_Storage_Only (Ref); overriding procedure Adjust (Self : in out Ref); pragma Inline (Adjust); overriding procedure Finalize (Self : in out Ref); type Weak_Ref is new Ada.Finalization.Controlled with record Data : Weak_Data_Access; end record; pragma Finalize_Storage_Only (Weak_Ref); overriding procedure Adjust (Self : in out Weak_Ref); pragma Inline (Adjust); overriding procedure Finalize (Self : in out Weak_Ref); Null_Ref : constant Ref := (Ada.Finalization.Controlled with Data => null); Null_Weak_Ref : constant Weak_Ref := (Ada.Finalization.Controlled with Data => null); end Shared_Pointers; -------------------- -- Smart_Pointers -- -------------------- -- For backward compatibility only. The above package is more flexible -- and more efficient. type Refcounted is abstract tagged private; type Refcounted_Access is access all Refcounted'Class; -- The common ancestor for all refcounted types. -- This ancestor adds a refcount field, which keeps track of how many -- references exist to a particular instance of Refcounted. -- -- The refcounting is task safe (that is you can use the smart pointer from -- multiple tasks concurrently, and the refcounting will always be -- accurate). But the task-safety of Refcounted itself depends on your -- application. procedure Free (Self : in out Refcounted) is null; -- Free the memory associated with Self, when Self is no longer referenced. generic type Encapsulated is abstract new Refcounted with private; package Smart_Pointers is pragma Obsolescent (Smart_Pointers, "Use Shared_Pointers instead"); type Encapsulated_Access is access all Encapsulated'Class; type Ref is tagged private; Null_Ref : constant Ref; procedure Set (Self : in out Ref; Data : Encapsulated'Class); procedure Set (Self : in out Ref; Data : access Encapsulated'Class); -- Replace the current contents of Self. -- Data is adopted by the smart pointer, and should no longer be -- referenced directly elsewhere. The reference count of Data is -- incremented by 1. -- Typical code looks like: -- Tmp := new Encapsulated; -- Set (Ptr, Tmp); -- (You can't do -- Set (Ptr, new Encapsulated); -- for visibility reasons) function Get (P : Ref) return Encapsulated_Access; pragma Inline (Get); -- Return a pointer the data pointed to by P. -- We return an access type for efficiency reasons. However, the -- returned value must not be freed by the caller. overriding function "=" (P1, P2 : Ref) return Boolean; -- Whether the two pointers point to the same data function Get_Refcount (Self : Ref) return Natural; -- Return the current reference count. -- This is mostly intended for debug purposes. private type Ref is new Ada.Finalization.Controlled with record Data : Refcounted_Access; end record; overriding procedure Finalize (P : in out Ref); overriding procedure Adjust (P : in out Ref); -- Take care of reference counting Null_Ref : constant Ref := (Ada.Finalization.Controlled with Data => null); end Smart_Pointers; private type Refcounted is abstract tagged record Refcount : aliased GNATCOLL.Atomic.Atomic_Counter := 0; end record; -- This requires, as a result, that all refcounted types also be tagged -- types (thus adding the size of a tag and the size of an integer to each -- instance). This approach was chosen over storing the refcounting -- independently of the refcounted type. The chosen approach provides a -- tighter integration between the two. end GNATCOLL.Refcount; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-remote-db.adb000066400000000000000000000075101425465243200232370ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Remote.Db is Global_Conf : access Remote_Db_Interface'Class := null; --------------------------------- -- Define_Remote_Configuration -- --------------------------------- procedure Define_Remote_Configuration (Config : access Remote_Db_Interface'Class) is begin Global_Conf := Config; end Define_Remote_Configuration; ------------------- -- Is_Configured -- ------------------- function Is_Configured (Nickname : String) return Boolean is begin if Global_Conf = null then raise Invalid_Remote_Configuration; end if; return Global_Conf.Is_Configured (Nickname); end Is_Configured; ------------ -- Server -- ------------ function Get_Server (Nickname : String) return Server_Access is begin if Global_Conf = null then raise Invalid_Remote_Configuration; end if; return Global_Conf.Get_Server (Nickname); end Get_Server; --------------------- -- Nb_Mount_Points -- --------------------- function Nb_Mount_Points (Nickname : String) return Natural is begin if Global_Conf = null then raise Invalid_Remote_Configuration; end if; return Global_Conf.Nb_Mount_Points (Nickname); end Nb_Mount_Points; -------------------------------- -- Get_Mount_Point_Local_Root -- -------------------------------- function Get_Mount_Point_Local_Root (Nickname : String; Index : Natural) return FS_String is begin if Global_Conf = null then raise Invalid_Remote_Configuration; end if; return Global_Conf.Get_Mount_Point_Local_Root (Nickname, Index); end Get_Mount_Point_Local_Root; ------------------------------- -- Get_Mount_Point_Host_Root -- ------------------------------- function Get_Mount_Point_Host_Root (Nickname : String; Index : Natural) return FS_String is begin if Global_Conf = null then raise Invalid_Remote_Configuration; end if; return Global_Conf.Get_Mount_Point_Host_Root (Nickname, Index); end Get_Mount_Point_Host_Root; end GNATCOLL.Remote.Db; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-remote-db.ads000066400000000000000000000114631425465243200232620ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package is used to keep a global configuration of servers. -- There are two almost identical parts: one defining static methods that -- can be used by other GNATCOLL packages (such as GNATCOLL.IO.Remote), -- and the second part that defines the actual configuration class, that -- needs to be implemented and registered by the user code. package GNATCOLL.Remote.Db is Invalid_Remote_Configuration : exception; --------------------------------------------------- -- The remote configuration interface definition -- --------------------------------------------------- type Remote_Db_Interface is interface; function Is_Configured (Config : Remote_Db_Interface; Nickname : String) return Boolean is abstract; -- Tell if a server with this name exists in the global configuration function Get_Server (Config : Remote_Db_Interface; Nickname : String) return Server_Access is abstract; -- Get the server from its nickname. function Nb_Mount_Points (Config : Remote_Db_Interface; Nickname : String) return Natural is abstract; -- Get the number of mount points defined for the server function Get_Mount_Point_Local_Root (Config : Remote_Db_Interface; Nickname : String; Index : Natural) return FS_String is abstract; -- Get the local mount point function Get_Mount_Point_Host_Root (Config : Remote_Db_Interface; Nickname : String; Index : Natural) return FS_String is abstract; -- Get the remote point. --------------------------------------------------------- -- Needs to be called before any of the static methods -- --------------------------------------------------------- procedure Define_Remote_Configuration (Config : access Remote_Db_Interface'Class); -- Defines the remote configuration that will be used for all remote access -- performed by GNATCOLL. ------------------------------------------------- -- Static methods used by GNATCOLL internally -- ------------------------------------------------- function Is_Configured (Nickname : String) return Boolean; -- Tell if a server with this name exists in the global configuration -- Raise Invalid_Remote_Config if no global configuration has been defined. function Get_Server (Nickname : String) return Server_Access; -- Get the server from its nickname. -- Raise Invalid_Remote_Config if no global configuration has been defined. function Nb_Mount_Points (Nickname : String) return Natural; -- Get the number of mount points defined for the server -- Raise Invalid_Remote_Config if no global configuration has been defined. function Get_Mount_Point_Local_Root (Nickname : String; Index : Natural) return FS_String; -- Get the local mount point -- Raise Invalid_Remote_Config if no global configuration has been defined. function Get_Mount_Point_Host_Root (Nickname : String; Index : Natural) return FS_String; -- Get the remote point. -- Raise Invalid_Remote_Config if no global configuration has been defined. end GNATCOLL.Remote.Db; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-remote.ads000066400000000000000000000076771425465243200227130ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package describes the transport layer used by remote filesystems to -- communicate with a remote host. -- Actual implementation is left to the user application, since it requires -- external knowledge of the environment. -- Spawning commands might require various application-specific info, -- such as the protocol to use (ssh, rsh,...) and possibly require the -- running of commands to setup the environment correctly. These are both -- specific to your application, and this package does not try to perform -- this operation as a result. with GNAT.Expect; with GNAT.Strings; with GNATCOLL.VFS_Types; use GNATCOLL.VFS_Types; package GNATCOLL.Remote is -- Server definition type Server_Record is interface; type Server_Access is access all Server_Record'Class; function Nickname (Server : Server_Record) return String is abstract; function Shell_FS (Server : Server_Record) return FS_Type is abstract; procedure Execute_Remotely (Server : access Server_Record; Args : GNAT.Strings.String_List; Status : out Boolean; Execution_Directory : FS_String := "") is abstract; procedure Execute_Remotely (Server : access Server_Record; Args : GNAT.Strings.String_List; Result : out GNAT.Strings.String_Access; Status : out Boolean; Execution_Directory : FS_String := "") is abstract; -- You must override this subprogram to do the actual spawn of a command on -- the specified remote host. -- Execution_Directory is the directory in which the command must be run. -- The command to execute is passed as the first parameter in Args. Args -- must not be freed by these procedure. procedure Spawn_Remotely (Server : access Server_Record; Descriptor : out GNAT.Expect.Process_Descriptor_Access; Args : GNAT.Strings.String_List) is abstract; -- Spawn a process on the remote machine. -- As opposed to Execute_Remotely, this one does not wait until the -- process as terminated. Instead, it allows users to interact with the -- process by sending commands to it and fetching its output. end GNATCOLL.Remote; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-scripts-impl.adb000066400000000000000000000244511425465243200240120ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNATCOLL.Traces; use GNATCOLL.Traces; with System.Assertions; package body GNATCOLL.Scripts.Impl is procedure Console_Command_Handler (Data : in out Callback_Data'Class; Command : String); -- Handles command related to Console class procedure Logger_Handler (Data : in out Callback_Data'Class; Command : String); -- Handles command related to Logger class type Logger_Properties_Record is new Instance_Property_Record with record Handle : Trace_Handle; end record; type Logger_Properties is access all Logger_Properties_Record'Class; ----------------- -- Insert_Text -- ----------------- procedure Insert_Text (Script : access Scripting_Language_Record'Class; Console : Virtual_Console := null; Txt : String) is begin if (Console /= null and then Console.Hide_Output) or else (Script.Console /= null and then Script.Console.Hide_Output) then null; elsif Console /= null then Insert_Text (Console, Txt); elsif Script.Console /= null then Insert_Text (Script.Console, Txt); end if; end Insert_Text; ------------------ -- Insert_Error -- ------------------ procedure Insert_Error (Script : access Scripting_Language_Record'Class; Console : Virtual_Console := null; Txt : String) is begin if Console /= null then Insert_Error (Console, Txt); elsif Script.Console /= null then Insert_Error (Script.Console, Txt); end if; end Insert_Error; ------------------- -- Insert_Prompt -- ------------------- procedure Insert_Prompt (Script : access Scripting_Language_Record'Class; Console : Virtual_Console := null; Txt : String) is begin if Console /= null then Insert_Prompt (Console, Txt); elsif Script.Console /= null then Insert_Prompt (Script.Console, Txt); end if; end Insert_Prompt; ----------------------------- -- Console_Command_Handler -- ----------------------------- procedure Console_Command_Handler (Data : in out Callback_Data'Class; Command : String) is type Mode_Kinds is (Text, Log, Error); Inst : constant Class_Instance := Nth_Arg (Data, 1, Any_Class); Console : Virtual_Console; Mode : Mode_Kinds := Text; begin if Command = "write" then if Number_Of_Arguments (Data) = 3 then begin Mode := Mode_Kinds'Value (Nth_Arg (Data, 3)); exception when Constraint_Error => Set_Error_Msg (Data, "Wrong value for ""mode"" parameter"); return; end; end if; Console := Get_Data (Inst); if Console /= null then case Mode is when Text => Insert_Text (Console, Nth_Arg (Data, 2)); when Log => Insert_Log (Console, Nth_Arg (Data, 2)); when Error => Insert_Error (Console, Nth_Arg (Data, 2)); end case; else Set_Error_Msg (Data, "Console was closed by user"); end if; elsif Command = "clear" then Console := Get_Data (Inst); if Console /= null then Clear (Console); else Set_Error_Msg (Data, "Console was closed by user"); end if; elsif Command = "flush" then null; -- Do nothing, only needed for compatibility with Python's -- stdout stream elsif Command = "isatty" then Set_Return_Value (Data, False); elsif Command = "read" then Console := Get_Data (Inst); if Console /= null then Set_Return_Value (Data, Read (Console, Size => Nth_Arg (Data, 2, Integer'Last), Whole_Line => False)); else Set_Error_Msg (Data, "Console was closed by user"); end if; elsif Command = "readline" then Console := Get_Data (Inst); if Console /= null then Set_Return_Value (Data, Read (Console, Size => Nth_Arg (Data, 2, Integer'Last), Whole_Line => True)); else Set_Error_Msg (Data, "Console was closed by user"); end if; end if; end Console_Command_Handler; -------------------- -- Logger_Handler -- -------------------- procedure Logger_Handler (Data : in out Callback_Data'Class; Command : String) is Logger_Data : constant String := "Logger"; Inst : constant Class_Instance := Nth_Arg (Data, 1); Prop : Instance_Property; begin if Command = Constructor_Method then Set_Data (Inst, Logger_Data, Logger_Properties_Record' (Handle => Create (Nth_Arg (Data, 2)))); elsif Command = "log" then Prop := Get_Data (Inst, Logger_Data); Trace (Logger_Properties (Prop).Handle, Nth_Arg (Data, 2)); elsif Command = "set_active" then Prop := Get_Data (Inst, Logger_Data); Set_Active (Logger_Properties (Prop).Handle, Nth_Arg (Data, 2)); elsif Command = "active" then Prop := Get_Data (Inst, Logger_Data); Set_Return_Value (Data, Active (Logger_Properties (Prop).Handle)); elsif Command = "check" then begin Prop := Get_Data (Inst, Logger_Data); Assert (Logger_Properties (Prop).Handle, Condition => Nth_Arg (Data, 2), Error_Message => Nth_Arg (Data, 3), Message_If_Success => Nth_Arg (Data, 4, "")); exception when System.Assertions.Assert_Failure => Set_Error_Msg (Data, "Assertion error: " & Nth_Arg (Data, 3)); end; elsif Command = "count" then Prop := Get_Data (Inst, Logger_Data); Set_Return_Value (Data, Count (Logger_Properties (Prop).Handle)); end if; end Logger_Handler; ---------------------------- -- Register_Console_Class -- ---------------------------- procedure Register_Console_Class (Repo : access Scripts_Repository_Record'Class; Class : Class_Type) is begin Register_Command (Repo, "write", Params => (Param ("text"), Param ("mode", Optional => True)), Class => Class, Handler => Console_Command_Handler'Access); Register_Command (Repo, "clear", Class => Class, Handler => Console_Command_Handler'Access); Register_Command (Repo, "flush", Class => Class, Handler => Console_Command_Handler'Access); Register_Command (Repo, "isatty", Class => Class, Handler => Console_Command_Handler'Access); Register_Command (Repo, "read", Params => (1 => Param ("size", Optional => True)), Class => Class, Handler => Console_Command_Handler'Access); Register_Command (Repo, "readline", Params => (1 => Param ("size", Optional => True)), Class => Class, Handler => Console_Command_Handler'Access); end Register_Console_Class; --------------------------- -- Register_Logger_Class -- --------------------------- procedure Register_Logger_Class (Repo : access Scripts_Repository_Record'Class; Class : Class_Type) is begin Register_Command (Repo, Constructor_Method, Params => (1 => Param ("name")), Class => Class, Handler => Logger_Handler'Access); Register_Command (Repo, "log", Params => (1 => Param ("message")), Class => Class, Handler => Logger_Handler'Access); Register_Command (Repo, "set_active", Params => (1 => Param ("active")), Class => Class, Handler => Logger_Handler'Access); Register_Property (Repo, "active", Class => Class, Getter => Logger_Handler'Access); Register_Command (Repo, "check", Params => (1 => Param ("condition"), 2 => Param ("error_message"), 3 => Param ("success_message", Optional => True)), Class => Class, Handler => Logger_Handler'Access); Register_Property (Repo, "count", Class => Class, Getter => Logger_Handler'Access); end Register_Logger_Class; end GNATCOLL.Scripts.Impl; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-scripts-impl.ads000066400000000000000000000061131425465243200240260ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides subprograms that are used when adding support for -- new scripting languages. Applications should not typically have a need for -- these types or subprograms. package GNATCOLL.Scripts.Impl is procedure Insert_Text (Script : access Scripting_Language_Record'Class; Console : Virtual_Console := null; Txt : String); procedure Insert_Error (Script : access Scripting_Language_Record'Class; Console : Virtual_Console := null; Txt : String); procedure Insert_Prompt (Script : access Scripting_Language_Record'Class; Console : Virtual_Console := null; Txt : String); -- Display txt either on the specified console or on the scripts' default -- console if Console is set to null. -- If Hide is set to True, the text is not displayed on the console after -- all, although it will be displayed in the log instead. procedure Register_Console_Class (Repo : access Scripts_Repository_Record'Class; Class : Class_Type); -- Register the console class, which is used to redirect output of script -- languages to a specific Virtual_Console procedure Register_Logger_Class (Repo : access Scripts_Repository_Record'Class; Class : Class_Type); -- Register the logger class, used to interfaces with GNATCOLL.Traces from -- python. end GNATCOLL.Scripts.Impl; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-scripts-shell.adb000066400000000000000000001770041425465243200241630ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Containers.Indefinite_Vectors; with Ada.Exceptions; use Ada.Exceptions; with Ada.IO_Exceptions; use Ada.IO_Exceptions; with Ada.Strings.Fixed; use Ada.Strings.Fixed; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Unchecked_Deallocation; with System.Address_Image; with System; use System; with GNAT.Debug_Utilities; use GNAT.Debug_Utilities; with GNATCOLL.Mmap; use GNATCOLL.Mmap; with GNAT.OS_Lib; use GNAT.OS_Lib; with GNATCOLL.Scripts.Impl; use GNATCOLL.Scripts.Impl; with GNATCOLL.Traces; use GNATCOLL.Traces; with GNATCOLL.Utils; use GNATCOLL.Utils; package body GNATCOLL.Scripts.Shell is Me : constant Trace_Handle := Create ("SHELL_SCRIPT", Off); Me_Log : constant Trace_Handle := Create ("SCRIPTS.LOG", Off); Cst_Prefix : constant String := "@cst@"; -- Prefix used to store the name of constants in class instances use Instances_List, Command_Hash; procedure Free_Internal_Data (Script : access Shell_Scripting_Record'Class); -- Free the internal memory used to store the results of previous commands -- and class instances. ---------- -- Misc -- ---------- function Name_From_Instance (Instance : access Class_Instance_Record'Class) return String; -- Return the string to display to report the instance in the shell function Instance_From_Name (Script : access Shell_Scripting_Record'Class; Name : String) return Class_Instance; -- Opposite of Name_From_Instance function Instance_From_Address (Script : access Shell_Scripting_Record'Class; Add : System.Address) return Class_Instance; -- Return an instance from its address function Execute_GPS_Shell_Command (Script : access Shell_Scripting_Record'Class; Command : String; Errors : access Boolean) return String; -- Execute a command in the GPS shell and returns its result. -- Command might be a series of commands, separated by semicolons or -- newlines. The return value is the result of the last command. -- If Errors is set to True on exit, then the return value is an error msg function Execute_GPS_Shell_Command (Script : access Shell_Scripting_Record'Class; CL : Arg_List; Errors : access Boolean) return String; -- Execute a command in the GPS shell and returns its result. -- Command must be a single command (no semicolon-separated list). procedure Module_Command_Handler (Data : in out Callback_Data'Class; Command : String); -- Handles functions specific to the shell language ------------------------ -- Internals Nth_Arg -- ------------------------ function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Success : access Boolean) return String; function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Success : access Boolean) return Unbounded_String; function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Success : access Boolean) return Subprogram_Type; function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Class : Class_Type; Allow_Null : Boolean; Success : access Boolean) return Class_Instance; -- These functions are called by the overridden Nth_Arg functions. They try -- to return the parameter at the location N. If no parameter is found, -- Success is false, true otherwise. It's the responsibility of the -- enclosing Nth_Arg to either raise a No_Such_Parameter exception or to -- return a default value. -------------------- -- Block_Commands -- -------------------- procedure Block_Commands (Script : access Shell_Scripting_Record; Block : Boolean) is begin Script.Blocked := Block; end Block_Commands; ------------------------ -- Name_From_Instance -- ------------------------ function Name_From_Instance (Instance : access Class_Instance_Record'Class) return String is begin return '<' & Get_Name (Shell_Class_Instance (Instance).Class) & "_0x" & System.Address_Image (Instance.all'Address) & '>'; end Name_From_Instance; ------------------------ -- Instance_From_Name -- ------------------------ function Instance_From_Name (Script : access Shell_Scripting_Record'Class; Name : String) return Class_Instance is Index : Natural := Name'First; begin if Name = "null" then return No_Class_Instance; end if; while Index <= Name'Last - 3 and then Name (Index .. Index + 2) /= "_0x" loop Index := Index + 1; end loop; return Instance_From_Address (Script, Value ("16#" & Name (Index + 3 .. Name'Last - 1) & "#")); exception when others => -- Invalid instance return No_Class_Instance; end Instance_From_Name; --------------------------- -- Instance_From_Address -- --------------------------- function Instance_From_Address (Script : access Shell_Scripting_Record'Class; Add : System.Address) return Class_Instance is L : Instances_List.Cursor := First (Script.Instances); begin while Has_Element (L) loop if Get_CIR (Element (L)).all'Address = Add then return Element (L); end if; Next (L); end loop; return No_Class_Instance; end Instance_From_Address; ----------------- -- Is_Subclass -- ----------------- function Is_Subclass (Instance : access Shell_Class_Instance_Record; Base : String) return Boolean is pragma Unreferenced (Instance, Base); begin -- ??? Not checked return True; end Is_Subclass; ------------------ -- Set_Property -- ------------------ overriding procedure Set_Property (Instance : access Shell_Class_Instance_Record; Name : String; Value : Integer) is begin -- We can only retrieve string constants later on, so convert here Set_Data (Instance, Cst_Prefix & Name, Create_Property (Image (Value, 0))); end Set_Property; overriding procedure Set_Property (Instance : access Shell_Class_Instance_Record; Name : String; Value : Float) is begin -- We can only retrieve string constants later on, so convert here Set_Data (Instance, Cst_Prefix & Name, Create_Property (Float'Image (Value))); end Set_Property; overriding procedure Set_Property (Instance : access Shell_Class_Instance_Record; Name : String; Value : Boolean) is begin Set_Data (Instance, Cst_Prefix & Name, Create_Property (Boolean'Image (Value))); end Set_Property; overriding procedure Set_Property (Instance : access Shell_Class_Instance_Record; Name : String; Value : String) is begin Set_Data (Instance, Cst_Prefix & Name, Create_Property (Value)); end Set_Property; --------------------- -- Name_Parameters -- --------------------- procedure Name_Parameters (Data : in out Shell_Callback_Data; Names : Cst_Argument_List) is pragma Unreferenced (Data, Names); begin null; end Name_Parameters; ---------------------------- -- Module_Command_Handler -- ---------------------------- procedure Module_Command_Handler (Data : in out Callback_Data'Class; Command : String) is begin if Command = "load" then declare Filename : constant String := Nth_Arg (Data, 1); File : Mapped_File; Errors : aliased Boolean; begin File := Open_Read (Filename); Read (File); declare Ignored : constant String := Execute_GPS_Shell_Command (Shell_Scripting (Get_Script (Data)), String (GNATCOLL.Mmap.Data (File)(1 .. Last (File))), Errors'Access); pragma Unreferenced (Ignored); begin null; end; exception when Name_Error => Set_Error_Msg (Data, "File not found: """ & Filename & '"'); end; elsif Command = "echo" or else Command = "echo_error" then declare Result : Unbounded_String; begin for A in 1 .. Number_Of_Arguments (Data) loop Append (Result, String'(Nth_Arg (Data, A))); if A /= Number_Of_Arguments (Data) then Append (Result, ' '); end if; end loop; if Command = "echo" then Insert_Text (Get_Script (Data), Txt => To_String (Result) & ASCII.LF); else Insert_Error (Get_Script (Data), Txt => To_String (Result) & ASCII.LF); end if; end; elsif Command = "clear_cache" then Free_Internal_Data (Shell_Scripting (Get_Script (Data))); end if; end Module_Command_Handler; ---------------- -- Initialize -- ---------------- procedure Initialize (Data : in out Shell_Callback_Data'Class; Script : access Shell_Scripting_Record'Class) is begin Data.Script := Shell_Scripting (Script); Data.Return_Value := null; Data.Return_Dict := null; Data.Return_As_List := False; Data.Return_As_Error := False; end Initialize; ------------------------------ -- Register_Shell_Scripting -- ------------------------------ procedure Register_Shell_Scripting (Repo : Scripts_Repository; Script : Shell_Scripting := null) is S : Shell_Scripting; begin if Script /= null then S := Script; else S := new Shell_Scripting_Record; end if; S.Repo := Repo; Register_Scripting_Language (Repo, S); Register_Command (Repo, "load", Minimum_Args => 1, Maximum_Args => 1, Handler => Module_Command_Handler'Access, Language => Shell_Name); Register_Command (Repo, "echo", Minimum_Args => 0, Maximum_Args => Natural'Last, Handler => Module_Command_Handler'Access, Language => Shell_Name); Register_Command (Repo, "echo_error", Minimum_Args => 0, Maximum_Args => Natural'Last, Handler => Module_Command_Handler'Access, Language => Shell_Name); Register_Command (Repo, "clear_cache", Handler => Module_Command_Handler'Access, Language => Shell_Name); end Register_Shell_Scripting; ------------------- -- List_Commands -- ------------------- procedure List_Commands (Script : access Shell_Scripting_Record'Class; Console : Virtual_Console := null) is package Command_List is new Ada.Containers.Indefinite_Vectors (Positive, String); package Ascending is new Command_List.Generic_Sorting ("<"); V : Command_List.Vector; begin -- Put all commands into V declare C : Command_Hash.Cursor := Script.Commands_List.First; begin while Has_Element (C) loop V.Append (Element (C).Command.all); Next (C); end loop; end; -- Sort commands Ascending.Sort (V); -- Output them declare C : Command_List.Cursor := V.First; begin while Command_List.Has_Element (C) loop Insert_Text (Script, Console, Command_List.Element (C) & ASCII.LF); Command_List.Next (C); end loop; end; end List_Commands; ----------------------- -- Register_Property -- ----------------------- overriding procedure Register_Property (Script : access Shell_Scripting_Record; Prop : Property_Descr_Access) is pragma Unreferenced (Script, Prop); begin -- All the work is done in Execute_Command null; end Register_Property; ---------------------- -- Register_Command -- ---------------------- overriding procedure Register_Command (Script : access Shell_Scripting_Record; Command : Command_Descr_Access) is Cmd : GNAT.Strings.String_Access; Info_C : Command_Hash.Cursor; Info : Command_Information_Access; begin if Command.Command = "" then return; end if; if Command.Class /= No_Class then if Command.Command = Constructor_Method then Cmd := new String'(Get_Name (Command.Class)); elsif Command.Command = Destructor_Method then Cmd := new String'(Get_Name (Command.Class) & ".__delete"); else Cmd := new String' (Get_Name (Command.Class) & "." & Command.Command); -- First parameter is always the instance end if; else Cmd := new String'(Command.Command); end if; Info_C := Find (Script.Commands_List, Cmd.all); -- Check that the command is not already registered if Has_Element (Info_C) then raise Program_Error with "Command already registered " & Cmd.all; else Info := new Command_Information' (Command => Cmd, Cmd => Command); Include (Script.Commands_List, Cmd.all, Info); end if; end Register_Command; -------------------- -- Register_Class -- -------------------- overriding procedure Register_Class (Script : access Shell_Scripting_Record; Name : String; Base : Class_Type := No_Class; Module : Module_Type := Default_Module) is pragma Unreferenced (Script, Name, Base, Module); begin -- Classes not supported in the shell module null; end Register_Class; -------------------- -- Display_Prompt -- -------------------- overriding procedure Display_Prompt (Script : access Shell_Scripting_Record; Console : Virtual_Console := null) is begin Insert_Prompt (Script, Console, Script.Prompt.all); end Display_Prompt; ---------------- -- Get_Prompt -- ---------------- overriding function Get_Prompt (Script : access Shell_Scripting_Record) return String is begin return Script.Prompt.all; end Get_Prompt; -------------- -- Complete -- -------------- procedure Complete (Script : access Shell_Scripting_Record; Input : String; Completions : out String_Lists.List) is Current : Command_Hash.Cursor; Info : Command_Information_Access; begin Completions := String_Lists.Empty_List; Current := First (Script.Commands_List); while Has_Element (Current) loop Info := Element (Current); declare S : constant String := Info.Command.all; begin if S'Length >= Input'Length and then S (S'First .. S'First + Input'Length - 1) = Input then String_Lists.Append (Completions, S); end if; end; Next (Current); end loop; String_Lists_Sort.Sort (Completions); end Complete; --------------------- -- Execute_Command -- --------------------- procedure Execute_Command (Script : access Shell_Scripting_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : out Boolean) is pragma Unreferenced (Show_Command); Old_Console : constant Virtual_Console := Script.Console; Err : aliased Boolean; begin if Console /= null then Script.Console := Console; end if; declare S : constant String := Execute_GPS_Shell_Command (Script, CL, Err'Unchecked_Access); begin Errors := Err; if S /= "" then Insert_Text (Script, Console, S & ASCII.LF); end if; Script.Console := Old_Console; -- Do not display the prompt in the shell console if we did not -- output to it if not Hide_Output and then (Console = null or else Console = Old_Console) then Display_Prompt (Script, Script.Console); end if; end; end Execute_Command; ------------------------------- -- Execute_Command_With_Args -- ------------------------------- function Execute_Command_With_Args (Script : access Shell_Scripting_Record; CL : Arg_List) return String is Errors : aliased Boolean; begin return Execute_GPS_Shell_Command (Script, CL, Errors'Unchecked_Access); end Execute_Command_With_Args; ------------------ -- Execute_File -- ------------------ procedure Execute_File (Script : access Shell_Scripting_Record; Filename : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : out Boolean) is Old_Console : constant Virtual_Console := Script.Console; Err : aliased Boolean; CL : Arg_List; begin if Console /= null then Script.Console := Console; end if; CL := Create ("load"); Append_Argument (CL, Filename, One_Arg); if Show_Command then Insert_Text (Script, Console, To_Display_String (CL)); end if; declare S : constant String := Execute_GPS_Shell_Command (Script, CL, Err'Unchecked_Access); begin Errors := Err; if S /= "" and then not Hide_Output then Insert_Text (Script, Console, S & ASCII.LF); end if; Script.Console := Old_Console; if not Hide_Output then Display_Prompt (Script, Script.Console); end if; end; end Execute_File; -------------- -- Get_Name -- -------------- function Get_Name (Script : access Shell_Scripting_Record) return String is pragma Unreferenced (Script); begin return Shell_Name; end Get_Name; ---------- -- Free -- ---------- procedure Free (Com : in out Command_Information_Access) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Command_Information, Command_Information_Access); begin Free (Com.Command); Unchecked_Free (Com); end Free; ------------------------ -- Free_Internal_Data -- ------------------------ procedure Free_Internal_Data (Script : access Shell_Scripting_Record'Class) is begin for R in Script.Returns'Range loop Free (Script.Returns (R)); end loop; Script.Instances.Clear; end Free_Internal_Data; ------------- -- Destroy -- ------------- procedure Destroy (Script : access Shell_Scripting_Record) is C : Command_Hash.Cursor; Com : Command_Information_Access; begin Free_Internal_Data (Script); Free (Script.Prompt); Free (Script.Returns); C := First (Script.Commands_List); while Has_Element (C) loop Com := Element (C); Free (Com); Next (C); end loop; Script.Finalized := True; end Destroy; ---------------- -- Set_Prompt -- ---------------- procedure Set_Prompt (Script : access Shell_Scripting_Record'Class; Prompt : String) is begin Free (Script.Prompt); Script.Prompt := new String'(Prompt); end Set_Prompt; --------------------- -- Execute_Command -- --------------------- function Execute_Command (Script : access Shell_Scripting_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : access Boolean) return String is pragma Unreferenced (Show_Command); Err : aliased Boolean; Old_Console : constant Virtual_Console := Script.Console; begin if Console /= null then Script.Console := Console; end if; declare Result : constant String := Execute_GPS_Shell_Command (Script, CL, Err'Unchecked_Access); begin Errors.all := Err; if Result /= "" and then not Hide_Output then Insert_Text (Script, Console, Result & ASCII.LF); end if; Script.Console := Old_Console; if not Hide_Output then Display_Prompt (Script, Script.Console); end if; return Result; end; end Execute_Command; --------------------- -- Execute_Command -- --------------------- function Execute_Command (Script : access Shell_Scripting_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Errors : access Boolean) return Boolean is Old_Console : constant Virtual_Console := Script.Console; Err : aliased Boolean; begin if Console /= null then Script.Console := Console; end if; declare Result : constant String := Trim (Execute_GPS_Shell_Command (Script, CL, Err'Unchecked_Access), Ada.Strings.Both); begin Errors.all := Err; if not Hide_Output then Insert_Text (Script, Console, Result & ASCII.LF); end if; Script.Console := Old_Console; if not Hide_Output then Display_Prompt (Script, Script.Console); end if; return Result = "1" or else To_Lower (Result) = "true"; end; end Execute_Command; ------------------------------- -- Execute_GPS_Shell_Command -- ------------------------------- function Execute_GPS_Shell_Command (Script : access Shell_Scripting_Record'Class; CL : Arg_List; Errors : access Boolean) return String is Data_C : Command_Hash.Cursor; Data : Command_Information_Access; Instance : Class_Instance; Min, Max : Natural; Found : Boolean; Count : Natural; Command : constant String := Get_Command (CL); begin Errors.all := False; if Script.Finalized then return ""; end if; if Command = "" then return ""; end if; if Active (Me) then Trace (Me, "Executing " & To_Display_String (CL) & " blocked=" & Script.Blocked'Img); end if; if Script.Blocked then Errors.all := True; return "A command is already executing"; end if; if Active (Me_Log) then Trace (Me_Log, "Executing " & To_Display_String (CL, Max_Arg_Length => 100)); end if; -- Special case: access to instance constants if Command (Command'First) = '@' then Min := 1; Max := 2; Found := True; else Data_C := Find (Script.Commands_List, Command); Found := Has_Element (Data_C); if Found then Data := Element (Data_C); Min := Data.Cmd.Minimum_Args; Max := Data.Cmd.Maximum_Args; if Data.Cmd.Class /= No_Class and then not Data.Cmd.Static_Method and then Data.Cmd.Command /= Constructor_Method and then Data.Cmd.Command /= Destructor_Method then Min := Min + 1; if Max /= Natural'Last then Max := Max + 1; end if; end if; end if; end if; if Found then if Min <= Args_Length (CL) and then Args_Length (CL) <= Max then Count := Args_Length (CL); if Data /= null and then Data.Cmd.Command = Constructor_Method then Count := Count + 1; end if; declare Callback : Shell_Callback_Data'Class := Shell_Callback_Data'Class (Create (Script, Count)); -- The call above allocates Callback.Args, no need to do that -- below begin Callback.Script := Shell_Scripting (Script); Callback.CL := Create (""); if Data /= null and then Data.Cmd.Command = Constructor_Method then Instance := New_Instance (Callback.Script, Data.Cmd.Class); Append_Argument (Callback.CL, Name_From_Instance (Get_CIR (Instance)), One_Arg); end if; for A in 1 .. Args_Length (CL) loop declare Args_A : constant String := Nth_Arg (CL, A); begin if Args_A'Length > 0 and then Args_A (Args_A'First) = '%' then declare Num : Integer; begin Num := Integer'Value (Args_A (Args_A'First + 1 .. Args_A'Last)); Append_Argument (Callback.CL, Script.Returns (Num + Script.Returns'First - 1).all, One_Arg); exception when Constraint_Error => Append_Argument (Callback.CL, Args_A, One_Arg); end; else Append_Argument (Callback.CL, Args_A, One_Arg); end if; end; end loop; if Data = null then -- Accessing a field Instance := Nth_Arg (Callback, 1, Any_Class); -- To match python, we first check for simple properties declare Prop : constant Instance_Property := Get_Data (Instance, Cst_Prefix & Command (Command'First + 1 .. Command'Last)); P : Property_Descr_Access; begin if Prop /= null then Trace (Me, "A simple property"); if Number_Of_Arguments (Callback) = 2 then Errors.all := True; return "Property is read-only: " & Command (Command'First + 1 .. Command'Last); end if; Set_Return_Value (Callback, As_String (Prop.all)); else Trace (Me, "A setter/getter property args=" & Number_Of_Arguments (Callback)'Img); -- Does this correspond to a setter/getter property ? P := Script.Repo.Properties; while P /= null loop exit when P.Class = Shell_Class_Instance (Get_CIR (Instance)).Class and then P.Name = Command (Command'First + 1 .. Command'Last); P := P.Next; end loop; if P = null then Errors.all := True; return "Command not recognized: " & Command; end if; if Number_Of_Arguments (Callback) = 1 then if P.Getter = null then Trace (Me, "Property is read-only"); Errors.all := True; return "Property is write-only: " & Command (Command'First + 1 .. Command'Last); end if; P.Getter (Callback, P.Name); -- Already set the return value, nothing else to do else if P.Setter = null then Errors.all := True; return "Property is read-only: " & Command (Command'First + 1 .. Command'Last); end if; P.Setter (Callback, P.Name); -- Already set the value, nothing else to do end if; end if; end; else Data.Cmd.Handler (Callback, Data.Cmd.Command); if Callback.Return_As_Error then Errors.all := True; Free (Callback.Return_Dict); declare R : constant String := Callback.Return_Value.all; begin Free (Callback.Return_Value); return R; end; end if; if Data.Cmd.Command = Constructor_Method then Set_Return_Value (Callback, Instance); end if; if Callback.Return_Dict /= null then Free (Callback.Return_Value); Callback.Return_Value := Callback.Return_Dict; Callback.Return_Dict := null; end if; end if; -- Save the return value for the future Free (Script.Returns (Script.Returns'Last)); Script.Returns (Script.Returns'First + 1 .. Script.Returns'Last) := Script.Returns (Script.Returns'First .. Script.Returns'Last - 1); if Callback.Return_Value = null then Script.Returns (Script.Returns'First) := new String'(""); else Script.Returns (Script.Returns'First) := Callback.Return_Value; end if; if Callback.Return_Value = null then return ""; else -- Do not free Callback.Return_Value, it is stored in the -- list of previous commands return Callback.Return_Value.all; end if; end; else Errors.all := True; return "Incorrect number of arguments for " & Command; end if; end if; Errors.all := True; return "Command not recognized: " & Command; exception when Invalid_Parameter => Errors.all := True; return "Invalid parameter for " & Command; when E : others => Errors.all := True; return Exception_Information (E); end Execute_GPS_Shell_Command; ------------------------------- -- Execute_GPS_Shell_Command -- ------------------------------- function Execute_GPS_Shell_Command (Script : access Shell_Scripting_Record'Class; Command : String; Errors : access Boolean) return String is CL : Arg_List; First, Last : Integer; Quoted : Boolean; Triple_Quoted : Boolean; begin Errors.all := False; if Command /= "" then First := Command'First; while First <= Command'Last loop while First <= Command'Last and then (Command (First) = ' ' or else Command (First) = ASCII.HT) loop First := First + 1; end loop; if First > Command'Last then exit; end if; Last := First; Quoted := False; Triple_Quoted := False; -- Search until the beginning of the next command (separated by -- semicolon or newline). while Last <= Command'Last loop exit when not Quoted and then not Triple_Quoted and then (Command (Last) = ';' or else Command (Last) = ASCII.LF); if Command (Last) = '"' then if Last <= Command'Last - 2 and then Command (Last + 1) = '"' and then Command (Last + 2) = '"' then Triple_Quoted := not Triple_Quoted; Last := Last + 2; elsif not Triple_Quoted then Quoted := not Quoted; end if; elsif Command (Last) = '\' and then Last < Command'Last then Last := Last + 1; end if; Last := Last + 1; end loop; if Last - 1 >= First then CL := Parse_String (Command (First .. Last - 1), Command_Line_Treatment (Script)); if CL = Empty_Command_Line then Errors.all := True; return "Couldn't parse argument string for " & Command (First .. Last - 1); else declare R : constant String := Execute_GPS_Shell_Command (Script, CL => CL, Errors => Errors); begin if Last > Command'Last then return R; end if; end; end if; end if; First := Last + 1; end loop; end if; return ""; end Execute_GPS_Shell_Command; ---------------- -- Get_Script -- ---------------- function Get_Script (Data : Shell_Callback_Data) return Scripting_Language is begin return Scripting_Language (Data.Script); end Get_Script; -------------------- -- Get_Repository -- -------------------- function Get_Repository (Script : access Shell_Scripting_Record) return Scripts_Repository is begin return Script.Repo; end Get_Repository; -------------------- -- Current_Script -- -------------------- function Current_Script (Script : access Shell_Scripting_Record) return String is pragma Unreferenced (Script); begin return ""; end Current_Script; ------------------------- -- Number_Of_Arguments -- ------------------------- function Number_Of_Arguments (Data : Shell_Callback_Data) return Natural is begin return Args_Length (Data.CL); end Number_Of_Arguments; ---------- -- Free -- ---------- procedure Free (Data : in out Shell_Callback_Data) is begin Free (Data.Return_Value); Free (Data.Return_Dict); end Free; ----------- -- Clone -- ----------- function Clone (Data : Shell_Callback_Data) return Callback_Data'Class is New_CL : Arg_List := Create (Get_Command (Data.CL)); begin for A in 1 .. Args_Length (Data.CL) loop Append_Argument (New_CL, Nth_Arg (Data.CL, A), One_Arg); end loop; return Shell_Callback_Data' (Callback_Data with CL => New_CL, Script => Data.Script, Return_Value => null, Return_Dict => null, Return_As_List => False, Return_As_Error => False); end Clone; ------------ -- Create -- ------------ function Create (Script : access Shell_Scripting_Record; Arguments_Count : Natural) return Callback_Data'Class is Data : constant Shell_Callback_Data := (Callback_Data with Script => Shell_Scripting (Script), CL => Empty_Command_Line, Return_Value => null, Return_Dict => null, Return_As_List => False, Return_As_Error => False); pragma Unreferenced (Arguments_Count); begin return Data; end Create; ----------------- -- Set_Nth_Arg -- ----------------- procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Subprogram_Type) is begin Set_Nth_Arg (Data.CL, N, Shell_Subprogram_Record (Value.all).Command.all); end Set_Nth_Arg; ----------------- -- Set_Nth_Arg -- ----------------- procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : String) is begin Set_Nth_Arg (Data.CL, N, Value); end Set_Nth_Arg; ----------------- -- Set_Nth_Arg -- ----------------- procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Integer) is begin Set_Nth_Arg (Data.CL, N, Integer'Image (Value)); end Set_Nth_Arg; ----------------- -- Set_Nth_Arg -- ----------------- procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Float) is begin Set_Nth_Arg (Data.CL, N, Float'Image (Value)); end Set_Nth_Arg; ----------------- -- Set_Nth_Arg -- ----------------- procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Boolean) is begin Set_Nth_Arg (Data.CL, N, Boolean'Image (Value)); end Set_Nth_Arg; ----------------- -- Set_Nth_Arg -- ----------------- procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Class_Instance) is begin Set_Nth_Arg (Data.CL, N, Name_From_Instance (Get_CIR (Value))); end Set_Nth_Arg; ----------------- -- Set_Nth_Arg -- ----------------- overriding procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : List_Instance) is begin Set_Nth_Arg (Data.CL, N, '(' & Get_Command (Shell_Callback_Data (Value).CL) & ')'); end Set_Nth_Arg; -------------- -- New_List -- -------------- overriding function New_List (Script : access Shell_Scripting_Record; Class : Class_Type := No_Class) return List_Instance'Class is pragma Unreferenced (Class); List : Shell_Callback_Data; begin List.Script := Shell_Scripting (Script); List.CL := Empty_Command_Line; return List; end New_List; ------------- -- Nth_Arg -- ------------- overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return List_Instance'Class is List : Shell_Callback_Data; begin List.Script := Data.Script; if N > Args_Length (Data.CL) then List.CL := Empty_Command_Line; -- An empty list else List.CL := Parse_String (Nth_Arg (Data.CL, N), Separate_Args); end if; return List; end Nth_Arg; ------------- -- Nth_Arg -- ------------- overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Dictionary_Instance'Class is begin raise Program_Error with "Dictionary is not supported by language"; return Nth_Arg (Data, N); end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Success : access Boolean) return String is begin if N > Args_Length (Data.CL) then Success.all := False; return ""; else Success.all := True; return Nth_Arg (Data.CL, N); end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Success : access Boolean) return Unbounded_String is begin if N > Args_Length (Data.CL) then Success.all := False; return Null_Unbounded_String; else Success.all := True; return Nth_Arg (Data.CL, N); end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Class : Class_Type; Allow_Null : Boolean; Success : access Boolean) return Class_Instance is Class_Name : constant String := Nth_Arg (Data, N, Success); Ins : Class_Instance; begin if not Success.all then return No_Class_Instance; end if; Ins := Instance_From_Name (Data.Script, Class_Name); if Ins = No_Class_Instance and then Allow_Null then return No_Class_Instance; end if; if Ins = No_Class_Instance or else (Class /= Any_Class and then not Is_Subclass (Ins, Get_Name (Class))) then raise Invalid_Parameter; else return Ins; end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Success : access Boolean) return Subprogram_Type is Name : constant String := Nth_Arg (Data, N, Success); begin if not Success.all then return null; else return new Shell_Subprogram_Record' (Subprogram_Record with Script => Get_Script (Data), Command => new String'(Name)); end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Boolean is Success : aliased Boolean; S : constant String := Nth_Arg (Data, N, Success'Access); begin if Success then return Boolean'Value (S); else raise No_Such_Parameter; end if; exception when Constraint_Error => raise Invalid_Parameter; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Integer is Success : aliased Boolean; S : constant String := Nth_Arg (Data, N, Success'Access); begin if Success then return Integer'Value (S); else raise No_Such_Parameter; end if; exception when Constraint_Error => raise Invalid_Parameter; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Float is Success : aliased Boolean; S : constant String := Nth_Arg (Data, N, Success'Access); begin if Success then return Float'Value (S); else raise No_Such_Parameter; end if; exception when Constraint_Error => raise Invalid_Parameter; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return String is Success : aliased Boolean; Result : constant String := Nth_Arg (Data, N, Success'Access); begin if not Success then raise No_Such_Parameter; else return Result; end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Unbounded_String is Success : aliased Boolean; Result : constant Unbounded_String := Nth_Arg (Data, N, Success'Access); begin if not Success then raise No_Such_Parameter; else return Result; end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Subprogram_Type is Success : aliased Boolean; Result : constant Subprogram_Type := Nth_Arg (Data, N, Success'Access); begin if not Success then raise No_Such_Parameter; else return Result; end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Class : Class_Type; Allow_Null : Boolean := False) return Class_Instance is Success : aliased Boolean; Result : constant Class_Instance := Nth_Arg (Data, N, Class, Allow_Null, Success'Access); begin if not Success then raise No_Such_Parameter; else return Result; end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : String) return String is Success : aliased Boolean; Result : constant String := Nth_Arg (Data, N, Success'Access); begin if not Success then return Default; else return Result; end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : Integer) return Integer is Success : aliased Boolean; Result : constant String := Nth_Arg (Data, N, Success'Access); begin if not Success then return Default; else return Integer'Value (Result); end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : Float) return Float is Success : aliased Boolean; Result : constant String := Nth_Arg (Data, N, Success'Access); begin if not Success then return Default; else return Float'Value (Result); end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : Boolean) return Boolean is Success : aliased Boolean; Result : constant String := Nth_Arg (Data, N, Success'Access); begin if not Success then return Default; else return Boolean'Value (Result); end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Class : Class_Type := Any_Class; Default : Class_Instance; Allow_Null : Boolean := False) return Class_Instance is Success : aliased Boolean; Result : constant Class_Instance := Nth_Arg (Data, N, Class, Allow_Null, Success'Access); begin if not Success then return Default; else return Result; end if; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : Subprogram_Type) return Subprogram_Type is Success : aliased Boolean; Result : constant Subprogram_Type := Nth_Arg (Data, N, Success'Access); begin if not Success then return Default; else return Result; end if; end Nth_Arg; ------------------- -- Set_Error_Msg -- ------------------- procedure Set_Error_Msg (Data : in out Shell_Callback_Data; Msg : String) is begin Free (Data.Return_Value); Data.Return_As_Error := True; Data.Return_Value := new String'(Msg); end Set_Error_Msg; ------------------------------ -- Set_Return_Value_As_List -- ------------------------------ overriding procedure Set_Return_Value_As_List (Data : in out Shell_Callback_Data; Size : Natural := 0; Class : Class_Type := No_Class) is pragma Unreferenced (Size, Class); begin Data.Return_As_List := True; end Set_Return_Value_As_List; -------------------------- -- Set_Return_Value_Key -- -------------------------- procedure Set_Return_Value_Key (Data : in out Shell_Callback_Data; Key : String; Append : Boolean := False) is pragma Unreferenced (Append); Tmp : GNAT.Strings.String_Access; begin if Data.Return_Value = null then if Data.Return_Dict = null then Data.Return_Dict := new String'(Key & " => ()"); else Tmp := Data.Return_Dict; Data.Return_Dict := new String'(Tmp.all & ", " & Key & " => ()"); Free (Tmp); end if; else if Data.Return_Dict = null then Data.Return_Dict := new String' (Key & " => (" & Data.Return_Value.all & ')'); else Tmp := Data.Return_Dict; Data.Return_Dict := new String' (Tmp.all & ", " & Key & " => (" & Data.Return_Value.all & ')'); Free (Tmp); end if; end if; Data.Return_As_List := False; Free (Data.Return_Value); end Set_Return_Value_Key; -------------------------- -- Set_Return_Value_Key -- -------------------------- procedure Set_Return_Value_Key (Data : in out Shell_Callback_Data; Key : Integer; Append : Boolean := False) is begin Set_Return_Value_Key (Data, Integer'Image (Key), Append); end Set_Return_Value_Key; -------------------------- -- Set_Return_Value_Key -- -------------------------- procedure Set_Return_Value_Key (Data : in out Shell_Callback_Data; Key : Class_Instance; Append : Boolean := False) is begin Set_Return_Value_Key (Data, Name_From_Instance (Get_CIR (Key)), Append); end Set_Return_Value_Key; ---------------------- -- Set_Return_Value -- ---------------------- procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : Integer) is begin if not Data.Return_As_List then Free (Data.Return_Value); end if; Set_Return_Value (Data, Integer'Image (Value)); end Set_Return_Value; overriding procedure Set_Address_Return_Value (Data : in out Shell_Callback_Data; Value : System.Address) is begin if not Data.Return_As_List then Free (Data.Return_Value); end if; Set_Return_Value (Data, System.Address_Image (Value)); end Set_Address_Return_Value; ---------------------- -- Set_Return_Value -- ---------------------- procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : Float) is begin if not Data.Return_As_List then Free (Data.Return_Value); end if; Set_Return_Value (Data, Float'Image (Value)); end Set_Return_Value; ---------------------- -- Set_Return_Value -- ---------------------- procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : Boolean) is begin if not Data.Return_As_List then Free (Data.Return_Value); end if; Set_Return_Value (Data, Boolean'Image (Value)); end Set_Return_Value; ---------------------- -- Set_Return_Value -- ---------------------- procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : String) is Tmp : GNAT.Strings.String_Access; begin if Data.Return_As_List and then Data.Return_Value /= null then Tmp := Data.Return_Value; Data.Return_Value := new String (1 .. Tmp'Length + 1 + Value'Length); Data.Return_Value (1 .. Tmp'Length) := Tmp.all; Data.Return_Value (Tmp'Length + 1) := ASCII.LF; Data.Return_Value (Tmp'Length + 2 .. Data.Return_Value'Last) := Value; Free (Tmp); else Free (Data.Return_Value); Data.Return_Value := new String'(Value); end if; end Set_Return_Value; ---------------------- -- Set_Return_Value -- ---------------------- procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : Class_Instance) is begin if Value = No_Class_Instance then Set_Return_Value (Data, String'("null")); else Set_Return_Value (Data, Name_From_Instance (Get_CIR (Value))); end if; end Set_Return_Value; ---------------------- -- Set_Return_Value -- ---------------------- overriding procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : List_Instance) is begin Set_Return_Value (Data, '(' & Get_Command (Shell_Callback_Data (Value).CL) & ')'); end Set_Return_Value; ------------------ -- New_Instance -- ------------------ function New_Instance (Script : access Shell_Scripting_Record; Class : Class_Type) return Class_Instance is Instance : Shell_Class_Instance; begin Instance := new Shell_Class_Instance_Record; Instance.Class := Class; Instance.Script := Script; return R : Class_Instance do CI_Pointers.Set (R.Ref, Instance); Instances_List.Prepend (Script.Instances, R); end return; end New_Instance; ---------------- -- Get_Method -- ---------------- overriding function Get_Method (Instance : access Shell_Class_Instance_Record; Name : String) return Subprogram_Type is Inst_Name : constant String := Name_From_Instance (Instance); begin return new Shell_Subprogram_Record' (Script => Scripting_Language (Instance.Script), Command => new String' (Get_Name (Instance.Class) & "." & Name & " " & Inst_Name)); end Get_Method; -------------------- -- Print_Refcount -- -------------------- function Print_Refcount (Instance : access Shell_Class_Instance_Record) return String is pragma Unreferenced (Instance); begin return ""; end Print_Refcount; ------------------------ -- Execute_Expression -- ------------------------ overriding procedure Execute_Expression (Result : in out Shell_Callback_Data; Expression : String; Hide_Output : Boolean := True) is pragma Unreferenced (Hide_Output); Errors : aliased Boolean; begin Result.Set_Return_Value (String'(Execute_GPS_Shell_Command (Shell_Scripting (Get_Script (Result)), Expression, Errors'Unchecked_Access))); end Execute_Expression; --------------------- -- Execute_Command -- --------------------- function Execute_Command (Script : access Shell_Scripting_Record; Command : String; Args : Callback_Data'Class) return Boolean is Errors : aliased Boolean; CL : Arg_List := Create (Command); begin for J in 1 .. Args_Length (Shell_Callback_Data (Args).CL) loop Append_Argument (CL, Nth_Arg (Shell_Callback_Data (Args).CL, J), One_Arg); end loop; declare Result : constant String := Trim (Execute_GPS_Shell_Command (Script, CL, Errors'Unchecked_Access), Ada.Strings.Both); begin return Result = "1" or else To_Lower (Result) = "true"; end; end Execute_Command; ------------- -- Execute -- ------------- overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Boolean is begin Error.all := False; return To_Lower (Execute (Shell_Subprogram (Subprogram), Args)) = "true"; end Execute; ------------- -- Execute -- ------------- function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return String is D : constant Shell_Callback_Data := Shell_Callback_Data (Args); CL : Arg_List; begin CL := Create (Subprogram.Command.all); for Arg in 1 .. Args_Length (D.CL) loop Append_Argument (CL, Nth_Arg (D.CL, Arg), One_Arg); end loop; return Execute_GPS_Shell_Command (Script => Shell_Scripting (Subprogram.Script), CL => CL, Errors => Error); end Execute; ------------- -- Execute -- ------------- overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Class_Instance is Result : constant String := Execute (Subprogram, Args, Error); begin return Instance_From_Name (Shell_Scripting (Subprogram.Script), Result); end Execute; ------------- -- Execute -- ------------- overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return List_Instance'Class is List : Shell_Callback_Data; begin List.Script := Shell_Scripting (Subprogram.Script); List.CL := Parse_String (Execute (Subprogram, Args, Error), Separate_Args); return List; end Execute; ------------- -- Execute -- ------------- function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return GNAT.Strings.String_List is pragma Unreferenced (Subprogram, Args); begin Error.all := True; -- ??? We are in asynchronous mode, see Execute for String above return (1 .. 0 => null); end Execute; ------------- -- Execute -- ------------- overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Any_Type is pragma Unreferenced (Subprogram, Args); begin Error.all := True; -- Any_Type is not supported for shell scripts raise Program_Error; return Empty_Any_Type; end Execute; -------------- -- Get_Name -- -------------- function Get_Name (Subprogram : access Shell_Subprogram_Record) return String is begin return "command: " & Subprogram.Command.all; end Get_Name; ---------- -- Free -- ---------- procedure Free (Subprogram : in out Shell_Subprogram_Record) is begin Free (Subprogram.Command); end Free; ---------------- -- Get_Script -- ---------------- function Get_Script (Subprogram : Shell_Subprogram_Record) return Scripting_Language is begin return Subprogram.Script; end Get_Script; ----------------- -- Get_Command -- ----------------- function Get_Command (Subprogram : access Shell_Subprogram_Record) return String is begin return Subprogram.Command.all; end Get_Command; ---------------- -- Initialize -- ---------------- procedure Initialize (Subprogram : in out Shell_Subprogram_Record'Class; Script : access Scripting_Language_Record'Class; Command : String) is begin Free (Subprogram.Command); Subprogram.Command := new String'(Command); Subprogram.Script := Scripting_Language (Script); end Initialize; -------------- -- Get_Args -- -------------- function Get_Args (Data : Shell_Callback_Data) return GNAT.OS_Lib.Argument_List is begin return To_List (Data.CL, False); -- ??? There is a memory leak here. Maybe we can get rid of this -- subprogram? end Get_Args; ---------------------------- -- Command_Line_Treatment -- ---------------------------- overriding function Command_Line_Treatment (Script : access Shell_Scripting_Record) return Command_Line_Mode is pragma Unreferenced (Script); begin return Separate_Args; end Command_Line_Treatment; --------------------- -- Execute_Command -- --------------------- overriding procedure Execute_Command (Args : in out Shell_Callback_Data; Command : String; Hide_Output : Boolean := True) is pragma Unreferenced (Hide_Output); Script : constant Shell_Scripting := Shell_Scripting (Get_Script (Args)); Errors : aliased Boolean; CL : Arg_List := Create (Command); begin for J in 1 .. Args_Length (Args.CL) loop Append_Argument (CL, Nth_Arg (Args.CL, J), One_Arg); end loop; declare Result : constant String := Trim (Execute_GPS_Shell_Command (Script, CL, Errors'Unchecked_Access), Ada.Strings.Both); begin Free (Args.Return_Value); Args.Return_Value := new String'(Result); end; end Execute_Command; ------------------ -- Return_Value -- ------------------ overriding function Return_Value (Data : Shell_Callback_Data) return String is begin if Data.Return_Value = null then raise Invalid_Parameter with "No return value"; else return Data.Return_Value.all; end if; end Return_Value; ------------------ -- Return_Value -- ------------------ overriding function Return_Value (Data : Shell_Callback_Data) return Integer is begin return Integer'Value (Return_Value (Data)); end Return_Value; ------------------ -- Return_Value -- ------------------ overriding function Return_Value (Data : Shell_Callback_Data) return Float is begin return Float'Value (Return_Value (Data)); end Return_Value; ------------------ -- Return_Value -- ------------------ overriding function Return_Value (Data : Shell_Callback_Data) return Boolean is begin return Boolean'Value (Return_Value (Data)); end Return_Value; ------------------ -- Return_Value -- ------------------ overriding function Return_Value (Data : Shell_Callback_Data) return Class_Instance is begin return Instance_From_Name (Data.Script, Return_Value (Data)); end Return_Value; ------------------ -- Return_Value -- ------------------ overriding function Return_Value (Data : Shell_Callback_Data) return List_Instance'Class is List : Shell_Callback_Data; begin List.Script := Data.Script; List.CL := Parse_String (Return_Value (Data), Separate_Args); return List; end Return_Value; ------------------- -- Get_User_Data -- ------------------- overriding function Get_User_Data (Self : not null access Shell_Class_Instance_Record) return access User_Data_List is begin return Self.Props'Access; end Get_User_Data; end GNATCOLL.Scripts.Shell; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-scripts-shell.ads000066400000000000000000000435711425465243200242050ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package contains the implementation for a simple scripting language pragma Ada_2012; private with Ada.Containers.Indefinite_Doubly_Linked_Lists; private with Ada.Containers.Indefinite_Hashed_Maps; private with Ada.Strings.Hash; private with GNAT.Strings; package GNATCOLL.Scripts.Shell is Shell_Name : constant String := "shell"; type Shell_Scripting_Record is new Scripting_Language_Record with private; type Shell_Scripting is access all Shell_Scripting_Record'Class; type Shell_Callback_Data is new Callback_Data with private; type Shell_Class_Instance_Record is new Class_Instance_Record with private; type Shell_Subprogram_Record is new Subprogram_Record with private; type Shell_Subprogram is access all Shell_Subprogram_Record'Class; -- This types are declared in the spec rather than in the body, so that -- their subprograms can be overridden again. For instance, GPS uses that -- to make a subprogram_type be a GPS action rather than a simple shell -- command. procedure Register_Shell_Scripting (Repo : Scripts_Repository; Script : Shell_Scripting := null); -- Register the scripting language. -- Script can be specified if you want to specialize some aspects of the -- scripting language procedure Initialize (Data : in out Shell_Callback_Data'Class; Script : access Shell_Scripting_Record'Class); -- Initialize Data to pass Arguments_Count to a callback procedure List_Commands (Script : access Shell_Scripting_Record'Class; Console : Virtual_Console := null); -- Print the list of all commands on Console. By default, print on the -- default console for Script procedure Initialize (Subprogram : in out Shell_Subprogram_Record'Class; Script : access Scripting_Language_Record'Class; Command : String); -- Initialize Subprogram so that it will execute Command function Get_Command (Subprogram : access Shell_Subprogram_Record) return String; -- Return the command that will be executed by Subprogram function Get_Args (Data : Shell_Callback_Data) return GNAT.OS_Lib.Argument_List; -- Return the list of arguments specified by Data. The returned value must -- never be freed by the caller procedure Set_Prompt (Script : access Shell_Scripting_Record'Class; Prompt : String); -- The prompt to use for consoles associated with this language private Num_Previous_Returns : constant := 9; -- Number of parameters %1, %2,... which are used to memorize the result of -- previous commands. type Shell_Class_Instance_Record is new Class_Instance_Record with record Class : Class_Type; Props : aliased User_Data_List; end record; type Shell_Class_Instance is access all Shell_Class_Instance_Record'Class; overriding function Print_Refcount (Instance : access Shell_Class_Instance_Record) return String; overriding function Is_Subclass (Instance : access Shell_Class_Instance_Record; Base : String) return Boolean; overriding procedure Set_Property (Instance : access Shell_Class_Instance_Record; Name : String; Value : Integer); overriding procedure Set_Property (Instance : access Shell_Class_Instance_Record; Name : String; Value : Float); overriding procedure Set_Property (Instance : access Shell_Class_Instance_Record; Name : String; Value : Boolean); overriding procedure Set_Property (Instance : access Shell_Class_Instance_Record; Name : String; Value : String); overriding function Get_Method (Instance : access Shell_Class_Instance_Record; Name : String) return Subprogram_Type; overriding function Get_User_Data (Self : not null access Shell_Class_Instance_Record) return access User_Data_List; -- See doc from inherited subprogram package Instances_List is new Ada.Containers.Indefinite_Doubly_Linked_Lists (Class_Instance); -- ??? Would be faster to use a hash-table... ------------------------- -- Command_Information -- ------------------------- type Command_Information is record Command : GNAT.Strings.String_Access; Cmd : Command_Descr_Access; end record; type Command_Information_Access is access Command_Information; -- Description for each of the registered commands. -- Command is the name that must be typed by the user in the console. -- Short_Command is the name under which the command was registered. It is -- the same as Command, except when the command is a method of a class. In -- this case, Command is equal to "Class.Short_Command" -- The command was set as a constructor if Short_Command is -- Constructor_Method. procedure Free (Com : in out Command_Information_Access); -- Free memory associated with Com package Command_Hash is new Ada.Containers.Indefinite_Hashed_Maps (String, Command_Information_Access, Ada.Strings.Hash, "="); type Shell_Scripting_Record is new Scripting_Language_Record with record Repo : Scripts_Repository; Finalized : Boolean := False; Blocked : Boolean := False; Instances : Instances_List.List; -- All the instances that were created Commands_List : Command_Hash.Map; -- The list of all registered commands Returns : GNAT.Strings.String_List (1 .. Num_Previous_Returns); -- The result of the Num_Previous_Returns previous commands Prompt : GNAT.Strings.String_Access := new String'("[Shell]>"); -- Prompt to use in consoles for this language end record; overriding function Command_Line_Treatment (Script : access Shell_Scripting_Record) return Command_Line_Mode; overriding procedure Destroy (Script : access Shell_Scripting_Record); overriding procedure Register_Command (Script : access Shell_Scripting_Record; Command : Command_Descr_Access); overriding procedure Register_Property (Script : access Shell_Scripting_Record; Prop : Property_Descr_Access); overriding procedure Register_Class (Script : access Shell_Scripting_Record; Name : String; Base : Class_Type := No_Class; Module : Module_Type := Default_Module); overriding procedure Block_Commands (Script : access Shell_Scripting_Record; Block : Boolean); overriding procedure Execute_Command (Script : access Shell_Scripting_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : out Boolean); overriding function Execute_Command (Script : access Shell_Scripting_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : access Boolean) return String; overriding function Execute_Command (Script : access Shell_Scripting_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Errors : access Boolean) return Boolean; overriding function Execute_Command (Script : access Shell_Scripting_Record; Command : String; Args : Callback_Data'Class) return Boolean; overriding function Execute_Command_With_Args (Script : access Shell_Scripting_Record; CL : Arg_List) return String; overriding procedure Execute_File (Script : access Shell_Scripting_Record; Filename : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : out Boolean); overriding function Get_Name (Script : access Shell_Scripting_Record) return String; overriding function Get_Repository (Script : access Shell_Scripting_Record) return Scripts_Repository; overriding function Current_Script (Script : access Shell_Scripting_Record) return String; overriding procedure Display_Prompt (Script : access Shell_Scripting_Record; Console : Virtual_Console := null); overriding function Get_Prompt (Script : access Shell_Scripting_Record) return String; overriding procedure Complete (Script : access Shell_Scripting_Record; Input : String; Completions : out String_Lists.List); overriding function New_Instance (Script : access Shell_Scripting_Record; Class : Class_Type) return Class_Instance; overriding function New_List (Script : access Shell_Scripting_Record; Class : Class_Type := No_Class) return List_Instance'Class; -- See doc from inherited subprograms type Shell_Callback_Data is new Callback_Data with record Script : Shell_Scripting; CL : Arg_List; Return_Value : GNAT.Strings.String_Access; Return_Dict : GNAT.Strings.String_Access; Return_As_List : Boolean := False; Return_As_Error : Boolean := False; end record; overriding function Clone (Data : Shell_Callback_Data) return Callback_Data'Class; overriding function Get_Script (Data : Shell_Callback_Data) return Scripting_Language; overriding function Number_Of_Arguments (Data : Shell_Callback_Data) return Natural; overriding procedure Name_Parameters (Data : in out Shell_Callback_Data; Names : Cst_Argument_List); overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return String; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Unbounded_String; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Integer; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Float; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Boolean; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Subprogram_Type; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Class : Class_Type; Allow_Null : Boolean := False) return Class_Instance; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return List_Instance'Class; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive) return Dictionary_Instance'Class; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : String) return String; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : Integer) return Integer; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : Float) return Float; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : Boolean) return Boolean; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Class : Class_Type := Any_Class; Default : Class_Instance; Allow_Null : Boolean := False) return Class_Instance; overriding function Nth_Arg (Data : Shell_Callback_Data; N : Positive; Default : Subprogram_Type) return Subprogram_Type; overriding procedure Set_Error_Msg (Data : in out Shell_Callback_Data; Msg : String); overriding procedure Set_Return_Value_As_List (Data : in out Shell_Callback_Data; Size : Natural := 0; Class : Class_Type := No_Class); overriding procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : Integer); overriding procedure Set_Address_Return_Value (Data : in out Shell_Callback_Data; Value : System.Address); overriding procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : Float); overriding procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : Boolean); overriding procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : String); overriding procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : Class_Instance); overriding procedure Set_Return_Value (Data : in out Shell_Callback_Data; Value : List_Instance); overriding procedure Set_Return_Value_Key (Data : in out Shell_Callback_Data; Key : String; Append : Boolean := False); overriding procedure Set_Return_Value_Key (Data : in out Shell_Callback_Data; Key : Integer; Append : Boolean := False); overriding procedure Set_Return_Value_Key (Data : in out Shell_Callback_Data; Key : Class_Instance; Append : Boolean := False); overriding procedure Free (Data : in out Shell_Callback_Data); overriding function Create (Script : access Shell_Scripting_Record; Arguments_Count : Natural) return Callback_Data'Class; overriding procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : String); overriding procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Integer); overriding procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Float); overriding procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Boolean); overriding procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Class_Instance); overriding procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : List_Instance); overriding procedure Set_Nth_Arg (Data : in out Shell_Callback_Data; N : Positive; Value : Subprogram_Type); overriding procedure Execute_Command (Args : in out Shell_Callback_Data; Command : String; Hide_Output : Boolean := True); overriding function Return_Value (Data : Shell_Callback_Data) return String; overriding function Return_Value (Data : Shell_Callback_Data) return Integer; overriding function Return_Value (Data : Shell_Callback_Data) return Float; overriding function Return_Value (Data : Shell_Callback_Data) return Boolean; overriding function Return_Value (Data : Shell_Callback_Data) return Class_Instance; overriding function Return_Value (Data : Shell_Callback_Data) return List_Instance'Class; overriding procedure Execute_Expression (Result : in out Shell_Callback_Data; Expression : String; Hide_Output : Boolean := True); -- See doc from inherited subprogram ---------------------- -- Shell_Subprogram -- ---------------------- type Shell_Subprogram_Record is new Subprogram_Record with record Script : Scripting_Language; Command : GNAT.Strings.String_Access; end record; -- subprograms in GPS shell are just GPS actions overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Boolean; overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return String; overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Class_Instance; overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return List_Instance'Class; overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return GNAT.Strings.String_List; overriding function Execute (Subprogram : access Shell_Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Any_Type; overriding procedure Free (Subprogram : in out Shell_Subprogram_Record); overriding function Get_Name (Subprogram : access Shell_Subprogram_Record) return String; overriding function Get_Script (Subprogram : Shell_Subprogram_Record) return Scripting_Language; -- See doc from inherited subprograms end GNATCOLL.Scripts.Shell; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-scripts-utils.adb000066400000000000000000000220761425465243200242120ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Strings.Fixed; use Ada.Strings.Fixed; with Ada.Unchecked_Deallocation; with GNAT.Strings; use GNAT.Strings; package body GNATCOLL.Scripts.Utils is ------------------------------------ -- Argument_List_To_Quoted_String -- ------------------------------------ function Argument_List_To_Quoted_String (Args : GNAT.Strings.String_List; Quote : Character := '"'; Quote_Backslash : Boolean := True) return String is Len : Natural := 1; begin -- Compute the maximum length of the output for J in Args'Range loop -- For each argument we append at most 3 characters, two quotes -- plus an ending space. if Args (J) /= null then Len := Len + Args (J)'Length + 3; for T in Args (J)'Range loop if Args (J)(T) = Quote or else Args (J)(T) = '\' then Len := Len + 1; end if; end loop; end if; end loop; declare Result : String (1 .. Len + 1); Ind : Natural := Result'First; procedure Append (Str : String); -- Append the contents of Str to Result, protecting quote characters ------------ -- Append -- ------------ procedure Append (Str : String) is begin for J in Str'Range loop if Str (J) = Quote or else (Quote_Backslash and then Str (J) = '\') then Result (Ind) := '\'; Result (Ind + 1) := Str (J); Ind := Ind + 2; else Result (Ind) := Str (J); Ind := Ind + 1; end if; end loop; end Append; begin for J in Args'Range loop if Args (J) /= null then if Index (Args (J).all, " ") > 0 then Result (Ind) := Quote; Ind := Ind + 1; Append (Args (J).all); Result (Ind) := Quote; Result (Ind + 1) := ' '; Ind := Ind + 2; else Append (Args (J).all); Result (Ind) := ' '; Ind := Ind + 1; end if; end if; end loop; return Result (1 .. Ind - 1); end; end Argument_List_To_Quoted_String; ------------------------------- -- Argument_To_Quoted_String -- ------------------------------- function Argument_To_Quoted_String (Arg : String; Quote : Character := '"'; Quote_Backslash : Boolean := True) return String is A : aliased String := Arg; L : constant String_List (1 .. 1) := (1 => A'Unchecked_Access); begin return Argument_List_To_Quoted_String (L, Quote, Quote_Backslash); end Argument_To_Quoted_String; ------------------------------------------------ -- Argument_String_To_List_With_Triple_Quotes -- ------------------------------------------------ function Argument_String_To_List_With_Triple_Quotes (Arg_String : String) return String_List_Access is Max_Args : Integer := 128; New_Argv : String_List_Access := new String_List (1 .. Max_Args); New_Argc : Natural := 0; Idx : Integer; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (String_List, String_List_Access); Backslashed : Boolean; Quoted : Boolean; Triple_Quoted : Boolean; Has_Triple : Boolean; Start_Idx : Integer; Start_With_Triple : Boolean; End_With_Triple : Boolean; begin Idx := Arg_String'First; loop exit when Idx > Arg_String'Last; Backslashed := False; Quoted := False; Triple_Quoted := False; Start_Idx := Idx; Start_With_Triple := False; End_With_Triple := False; while Idx <= Arg_String'Last and then (Backslashed or else Quoted or else Triple_Quoted or else Arg_String (Idx) /= ' ') loop End_With_Triple := False; if Backslashed then Backslashed := False; else case Arg_String (Idx) is when '\' => Backslashed := True; when '"' => if Quoted then Quoted := False; else Has_Triple := Idx + 2 <= Arg_String'Last and then Arg_String (Idx) = '"' and then Arg_String (Idx + 1) = '"' and then Arg_String (Idx + 2) = '"'; if Has_Triple then Triple_Quoted := not Triple_Quoted; if Idx = Start_Idx then Start_With_Triple := Triple_Quoted; end if; End_With_Triple := True; Idx := Idx + 2; else Quoted := True; end if; end if; when others => null; end case; end if; Idx := Idx + 1; end loop; New_Argc := New_Argc + 1; -- Resize the table if needed if New_Argc > Max_Args then declare New_New_Argv : String_List (1 .. Max_Args * 2); begin New_New_Argv (1 .. Max_Args) := New_Argv.all; Unchecked_Free (New_Argv); New_Argv := new String_List'(New_New_Argv); end; Max_Args := Max_Args * 2; end if; if Start_With_Triple and End_With_Triple then New_Argv (New_Argc) := new String'(Arg_String (Start_Idx + 3 .. Idx - 4)); else New_Argv (New_Argc) := new String'(Arg_String (Start_Idx .. Idx - 1)); end if; -- Skip extraneous spaces while Idx <= Arg_String'Last and then Arg_String (Idx) = ' ' loop Idx := Idx + 1; end loop; end loop; declare Result : constant String_List := New_Argv (1 .. New_Argc); begin Unchecked_Free (New_Argv); return new String_List'(Result); end; end Argument_String_To_List_With_Triple_Quotes; --------------- -- Unprotect -- --------------- function Unprotect (Str : String) return String is Result : String (Str'Range); Index : Natural := Result'First; N : Natural := Str'First; begin while N <= Str'Last loop if Str (N) = '\' then if N < Str'Last then Result (Index) := Str (N + 1); end if; N := N + 2; else Result (Index) := Str (N); N := N + 1; end if; Index := Index + 1; end loop; if Result'Length > 1 and then Result (Result'First) = '"' and then Result (Index - 1) = '"' then return Result (Result'First + 1 .. Index - 2); else return Result (Result'First .. Index - 1); end if; end Unprotect; end GNATCOLL.Scripts.Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-scripts-utils.ads000066400000000000000000000067141425465243200242340ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.Strings; package GNATCOLL.Scripts.Utils is function Argument_List_To_Quoted_String (Args : GNAT.Strings.String_List; Quote : Character := '"'; Quote_Backslash : Boolean := True) return String; -- Return the arguments as a full string. -- Arguments that contain spaces but do not already contain quotes -- will be put into quotes. -- Backslashes are duplicated if Quote_Baskslash is True. -- The result of this subprogram on the string A simple\ "string" -- is: Quote_Backslash => "A simple\\ \"string\"" -- not Quote_Backslash => "A simple\ \"string\"" function Argument_To_Quoted_String (Arg : String; Quote : Character := '"'; Quote_Backslash : Boolean := True) return String; -- As above but for a single argument function Argument_String_To_List_With_Triple_Quotes (Arg_String : String) return GNAT.Strings.String_List_Access; -- This is similar to GNAT.OS_Lib.Argument_String_To_List, except that -- if part of the string is surrounded by triple quotes, any special -- character is ignored till the closing triple quotes. This is the same -- behavior as in Python, and is needed for easier quoting of string. -- -- Here is the output in some cases: -- "foo" -> "foo" (quotes preserved) -- """foo""" -> foo (quotes removed when at beginning and end) -- ("""foo""") -> ("""foo""") (quotes preserved in middle) -- foo\"foo -> foo\"foo (backslash not removed from output) function Unprotect (Str : String) return String; -- Remove the \ protections in Str -- ??? This seems to also remove the quotes around an argument end GNATCOLL.Scripts.Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-scripts.adb000066400000000000000000001323531425465243200230540ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Calendar; use Ada.Calendar; with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Unchecked_Conversion; with Ada.Unchecked_Deallocation; with GNAT.OS_Lib; use GNAT.OS_Lib; with GNATCOLL.Scripts.Impl; use GNATCOLL.Scripts.Impl; with GNATCOLL.Traces; use GNATCOLL.Traces; with System.Address_Image; package body GNATCOLL.Scripts is Me : constant Trace_Handle := Create ("SCRIPTS"); use Classes_Hash; use CI_Pointers; Timeout_Threshold : constant Duration := 0.2; -- in seconds -- Timeout between two checks of the gtk+ event queue function To_Address is new Ada.Unchecked_Conversion (Class_Instance_Record_Access, System.Address); procedure Internal_Register_Command (Repo : access Scripts_Repository_Record'Class; Command : String; Minimum_Args : Natural := 0; Maximum_Args : Natural := 0; Params : Param_Array_Access := null; Handler : Module_Command_Function; Class : Class_Type := No_Class; Static_Method : Boolean := False; Language : String := ""); -- Internal version of Register_Command function Get_Data (Instance : access Class_Instance_Record'Class; Name : String) return User_Data_List; -- Return the user data with the given name, or null if there is none procedure Unset_Data (Instance : access Class_Instance_Record'Class; Name : String); -- Remove the user data with the given name ----------------------------------- -- Data stored in class_instance -- ----------------------------------- type User_Data_Type is (Strings, Integers, Booleans, Consoles, Floats); type Scalar_Properties_Record (Typ : User_Data_Type) is new Instance_Property_Record with record case Typ is when Strings => Str : GNAT.Strings.String_Access; when Integers => Int : Integer; when Floats => Flt : Float; when Booleans => Bool : Boolean; when Consoles => Console : Virtual_Console; end case; end record; type Scalar_Properties is access all Scalar_Properties_Record'Class; overriding procedure Destroy (Prop : in out Scalar_Properties_Record); -- See inherited documentation ----------------- -- Subprograms -- ----------------- procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Scripting_Language_Array, Scripting_Language_List); procedure Free_User_Data (Data : in out User_Data_List); -- Free the memory used by Data. Data is reset to null, and this doesn't -- free other user data in the list. procedure Free (Param : in out Param_Descr); procedure Free (Params : in out Param_Array_Access); -- Free memory ------------- -- Destroy -- ------------- procedure Destroy (Prop : in out Instance_Property_Record) is pragma Unreferenced (Prop); begin null; end Destroy; ---------- -- Free -- ---------- procedure Free (Param : in out Param_Descr) is begin Free (Param.Name); end Free; ---------- -- Free -- ---------- procedure Free (Params : in out Param_Array_Access) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Param_Array, Param_Array_Access); begin if Params /= null then for P in Params'Range loop Free (Params (P)); end loop; Unchecked_Free (Params); end if; end Free; ------------- -- Destroy -- ------------- procedure Destroy (Repo : in out Scripts_Repository) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Scripts_Repository_Record'Class, Scripts_Repository); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Command_Descr, Command_Descr_Access); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Property_Descr, Property_Descr_Access); C : Classes_Hash.Cursor; Class : Class_Type; D, D_Tmp : Command_Descr_Access; Prop, P_Tmp : Property_Descr_Access; begin Trace (Me, "Destroying scripts repository"); if Repo /= null then D := Repo.Commands; while D /= null loop D_Tmp := D.Next; Free (D.Params); Unchecked_Free (D); D := D_Tmp; end loop; Prop := Repo.Properties; while Prop /= null loop P_Tmp := Prop.Next; Unchecked_Free (Prop); Prop := P_Tmp; end loop; if Repo.Scripting_Languages /= null then for L in Repo.Scripting_Languages'Range loop Destroy (Repo.Scripting_Languages (L)); -- Do not free the language itself, though. Since scripts are -- full of controlled types, it might happen that some of them -- will be freed later on, and they might still have pointers -- to the script itself. -- Unchecked_Free (Repo.Scripting_Languages (L)); end loop; Unchecked_Free (Repo.Scripting_Languages); end if; C := First (Repo.Classes); while Has_Element (C) loop Class := Element (C); Free (Class.Qualified_Name); Next (C); end loop; Unchecked_Free (Repo); end if; end Destroy; ---------- -- Free -- ---------- procedure Free (List : in out Instance_List) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Instance_Array, Instance_Array_Access); begin -- Class_Instance are automatically Finalized by the compiler Unchecked_Free (List.List); end Free; --------- -- Get -- --------- function Get (List : Instance_List; Script : access Scripting_Language_Record'Class) return Class_Instance is begin if List.List /= null then for Idx in List.List'Range loop exit when List.List (Idx) = No_Class_Instance; if Get_Script (List.List (Idx)) = Scripting_Language (Script) then return List.List (Idx); end if; end loop; end if; return No_Class_Instance; end Get; --------- -- Set -- --------- procedure Set (List : in out Instance_List; Inst : Class_Instance) is Idx : Natural; begin if List.List = null then declare Tmp : constant Scripting_Language_Array := Get_Repository (Get_Script (Inst)).Scripting_Languages.all; begin List.List := new Instance_Array (Tmp'Range); List.List.all := (others => No_Class_Instance); end; end if; Idx := List.List'First; while Idx <= List.List'Last loop if List.List (Idx).Ref.Get = null or else Get_Script (List.List (Idx)) = Get_Script (Inst) then List.List (Idx) := Inst; return; end if; Idx := Idx + 1; end loop; end Set; ----------- -- First -- ----------- function First (Self : Instance_List) return Inst_Cursor is begin if Self.List = null or else Self.List (Self.List'First).Ref.Get = null then return (Index => Natural'Last); else return (Index => Self.List'First); end if; end First; ---------- -- Next -- ---------- procedure Next (Self : Instance_List; Pos : in out Inst_Cursor) is begin if Pos.Index >= Self.List'Last or else Self.List (Pos.Index + 1).Ref.Get = null then Pos := (Index => Natural'Last); else Pos := (Index => Pos.Index + 1); end if; end Next; ----------------- -- Has_Element -- ----------------- function Has_Element (Position : Inst_Cursor) return Boolean is begin return Position.Index /= Natural'Last; end Has_Element; ------------- -- Element -- ------------- function Element (Self : Instance_List; Pos : Inst_Cursor) return Class_Instance is begin return Self.List (Pos.Index); end Element; ---------- -- Free -- ---------- procedure Free (List : in out Callback_Data_List) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Callback_Data_Array, Callback_Data_List); begin if List /= null then for L in List'Range loop if List (L) /= null then Free (List (L)); end if; end loop; Unchecked_Free (List); end if; end Free; --------- -- Get -- --------- function Get (Repo : access Scripts_Repository_Record'Class; List : Callback_Data_List; Script : access Scripting_Language_Record'Class) return Callback_Data_Access is Tmp : constant Scripting_Language_Array := Repo.Scripting_Languages.all; begin if List /= null then for T in Tmp'Range loop if Tmp (T) = Scripting_Language (Script) then return List (T); end if; end loop; end if; return null; end Get; --------- -- Set -- --------- procedure Set (Repo : access Scripts_Repository_Record'Class; List : in out Callback_Data_List; Script : access Scripting_Language_Record'Class; Data : Callback_Data_Access) is Tmp : constant Scripting_Language_Array := Repo.Scripting_Languages.all; begin if List = null then List := new Callback_Data_Array (Tmp'Range); end if; for T in Tmp'Range loop if Tmp (T) = Scripting_Language (Script) then if List (T) /= null and then List (T) /= Data then Free (List (T)); end if; List (T) := Data; exit; end if; end loop; end Set; ---------- -- Free -- ---------- procedure Free (Data : in out Callback_Data_Access) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Callback_Data'Class, Callback_Data_Access); begin if Data /= null then Free (Data.all); Unchecked_Free (Data); end if; end Free; --------------------------------- -- Register_Scripting_Language -- --------------------------------- procedure Register_Scripting_Language (Repo : access Scripts_Repository_Record'Class; Script : access Scripting_Language_Record'Class) is Tmp : constant Scripting_Language_Array := Repo.Scripting_Languages.all; begin Unchecked_Free (Repo.Scripting_Languages); Repo.Scripting_Languages := new Scripting_Language_Array'(Tmp & Scripting_Language (Script)); end Register_Scripting_Language; ------------------------------- -- Lookup_Scripting_Language -- ------------------------------- function Lookup_Scripting_Language (Repo : access Scripts_Repository_Record'Class; Name : String) return Scripting_Language is Tmp : constant Scripting_Language_List := Repo.Scripting_Languages; N : constant String := To_Lower (Name); begin for T in Tmp'Range loop if To_Lower (Get_Name (Tmp (T))) = N then return Tmp (T); end if; end loop; return null; end Lookup_Scripting_Language; ----------------------------- -- Get_Scripting_Languages -- ----------------------------- function Get_Scripting_Languages (Repo : access Scripts_Repository_Record'Class) return Scripting_Language_Array is begin return Repo.Scripting_Languages.all; end Get_Scripting_Languages; -------------------- -- Block_Commands -- -------------------- procedure Block_Commands (Repo : access Scripts_Repository_Record'Class; Block : Boolean) is Tmp : constant Scripting_Language_List := Repo.Scripting_Languages; begin for T in Tmp'Range loop Block_Commands (Tmp (T), Block); end loop; end Block_Commands; ----------- -- Param -- ----------- function Param (Name : String; Optional : Boolean := False) return Param_Descr is begin return Param_Descr' (Name => new String'(Name), Optional => Optional); end Param; ---------------------- -- Register_Command -- ---------------------- procedure Register_Command (Repo : access Scripts_Repository_Record'Class; Command : String; Params : Param_Array; Handler : Module_Command_Function; Class : Class_Type := No_Class; Static_Method : Boolean := False; Language : String := "") is Min : Natural := Params'Length; begin for P in Params'Range loop if Params (P).Optional then Min := Min - 1; end if; end loop; Internal_Register_Command (Repo, Command => Command, Minimum_Args => Min, Maximum_Args => Params'Length, Params => new Param_Array'(Params), Handler => Handler, Class => Class, Static_Method => Static_Method, Language => Language); end Register_Command; ------------------------------- -- Internal_Register_Command -- ------------------------------- procedure Internal_Register_Command (Repo : access Scripts_Repository_Record'Class; Command : String; Minimum_Args : Natural := 0; Maximum_Args : Natural := 0; Params : Param_Array_Access := null; Handler : Module_Command_Function; Class : Class_Type := No_Class; Static_Method : Boolean := False; Language : String := "") is Tmp : constant Scripting_Language_List := Repo.Scripting_Languages; Cmd : Command_Descr_Access; begin if Command = Constructor_Method and then Class = No_Class then raise Program_Error with "Constructors can only be specified for classes"; end if; if Static_Method and then Class = No_Class then raise Program_Error with "Static method can only be created for classes"; end if; Cmd := new Command_Descr' (Length => Command'Length, Command => Command, Handler => Handler, Class => Class, Params => Params, Static_Method => Static_Method, Minimum_Args => Minimum_Args, Maximum_Args => Maximum_Args, Next => null); for T in Tmp'Range loop if Language = "" or else Get_Name (Tmp (T)) = Language then Register_Command (Tmp (T), Cmd); end if; end loop; -- Only add it to the list afterward, so that Register_Command is not -- tempted to look at Next Cmd.Next := Repo.Commands; Repo.Commands := Cmd; end Internal_Register_Command; ---------------------- -- Register_Command -- ---------------------- procedure Register_Command (Repo : access Scripts_Repository_Record'Class; Command : String; Minimum_Args : Natural := 0; Maximum_Args : Natural := 0; Handler : Module_Command_Function; Class : Class_Type := No_Class; Static_Method : Boolean := False; Language : String := "") is begin Internal_Register_Command (Repo, Command => Command, Minimum_Args => Minimum_Args, Maximum_Args => Maximum_Args, Params => null, Handler => Handler, Class => Class, Static_Method => Static_Method, Language => Language); end Register_Command; ---------------------- -- Override_Command -- ---------------------- procedure Override_Command (Repo : access Scripts_Repository_Record'Class; Command : String; Handler : Module_Command_Function; Class : Class_Type := No_Class) is Cmd : Command_Descr_Access := Repo.Commands; begin while Cmd /= null loop if Cmd.Command = Command and then Cmd.Class = Class then Cmd.Handler := Handler; return; end if; Cmd := Cmd.Next; end loop; raise Program_Error with "Command " & Command & " not found"; end Override_Command; ----------------------- -- Register_Property -- ----------------------- procedure Register_Property (Repo : access Scripts_Repository_Record'Class; Name : String; Class : Class_Type; Setter : Module_Command_Function := null; Getter : Module_Command_Function := null) is Tmp : constant Scripting_Language_List := Repo.Scripting_Languages; Prop : Property_Descr_Access; begin if Setter = null and then Getter = null then raise Program_Error with "A property must have at least a getter or a setter"; end if; Prop := new Property_Descr' (Length => Name'Length, Name => Name, Class => Class, Getter => Getter, Setter => Setter, Next => null); for T in Tmp'Range loop Register_Property (Tmp (T), Prop); end loop; -- Only add it to the list afterward, so that Register_Command is not -- tempted to look at Next Prop.Next := Repo.Properties; Repo.Properties := Prop; end Register_Property; --------------- -- New_Class -- --------------- function New_Class (Repo : access Scripts_Repository_Record'Class; Name : String; Base : Class_Type := No_Class; Module : Module_Type := Default_Module) return Class_Type is Tmp : constant Scripting_Language_List := Repo.Scripting_Languages; Class : Class_Type; begin if Tmp = null then return No_Class; else Class := Lookup_Class (Repo, Name, Module); if not Class.Exists then Class.Exists := True; Include (Repo.Classes, Class.Qualified_Name.all, Class); for T in Tmp'Range loop Register_Class (Tmp (T), Name, Base, Module); end loop; end if; return Class; end if; end New_Class; ------------------ -- Lookup_Class -- ------------------ function Lookup_Class (Repo : access Scripts_Repository_Record; Name : String; Module : Module_Type := Default_Module) return Class_Type is C : Classes_Hash.Cursor; Class : Class_Type; function Qualified_Name return String; function Qualified_Name return String is begin if Module = Default_Module then return Name; else return To_String (Module.Name) & '.' & Name; end if; end Qualified_Name; N : constant String := Qualified_Name; begin C := Find (Repo.Classes, N); if Has_Element (C) then return Element (C); else Class := Class_Type' (Qualified_Name => new String'(N), Exists => False); Include (Repo.Classes, N, Class); return Class; end if; end Lookup_Class; ------------------- -- Lookup_Module -- ------------------- function Lookup_Module (Repo : access Scripts_Repository_Record; Qualified_Name : String) return Module_Type is pragma Unreferenced (Repo); begin return Module_Type'(Name => To_Unbounded_String (Qualified_Name)); end Lookup_Module; -------------- -- Get_Name -- -------------- function Get_Name (Class : Class_Type) return String is begin if Class.Qualified_Name = null then return ""; elsif Class.Qualified_Name'Length > 2 and then Class.Qualified_Name (Class.Qualified_Name'First .. Class.Qualified_Name'First + 1) = "@." then return Class.Qualified_Name (Class.Qualified_Name'First + 2 .. Class.Qualified_Name'Last); else return Class.Qualified_Name.all; end if; end Get_Name; ------------------------------- -- Register_Standard_Classes -- ------------------------------- procedure Register_Standard_Classes (Repo : access Scripts_Repository_Record'Class; Console_Class_Name : String; Logger_Class_Name : String := "") is begin Repo.Console_Class := New_Class (Repo, Console_Class_Name); Register_Console_Class (Repo, Repo.Console_Class); if Logger_Class_Name /= "" then Repo.Logger_Class := New_Class (Repo, Logger_Class_Name); Register_Logger_Class (Repo, Repo.Logger_Class); end if; end Register_Standard_Classes; ------------------------------- -- Execute_Command_With_Args -- ------------------------------- function Execute_Command_With_Args (Script : access Scripting_Language_Record; CL : Arg_List) return String is pragma Unreferenced (Script, CL); begin raise Program_Error; return ""; end Execute_Command_With_Args; --------------------- -- Execute_Command -- --------------------- function Execute_Command (Script : access Scripting_Language_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : access Boolean) return String is begin Execute_Command (Scripting_Language (Script), CL, Console, Hide_Output, Show_Command, Errors.all); return ""; end Execute_Command; --------------------- -- Execute_Command -- --------------------- procedure Execute_Command (Script : access Scripting_Language_Record; Command : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : out Boolean) is begin Execute_Command (Scripting_Language (Script), Parse_String (Command, Command_Line_Treatment (Scripting_Language (Script))), Console, Hide_Output, Show_Command, Errors); end Execute_Command; --------------------- -- Execute_Command -- --------------------- function Execute_Command (Script : access Scripting_Language_Record; Command : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Errors : access Boolean) return Boolean is begin return Execute_Command (Scripting_Language (Script), Parse_String (Command, Command_Line_Treatment (Scripting_Language (Script))), Console, Hide_Output, Errors); end Execute_Command; --------------------- -- Execute_Command -- --------------------- function Execute_Command (Script : Scripting_Language; Command : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : access Boolean) return String is begin return Execute_Command (Script, Parse_String (Command, Command_Line_Treatment (Script)), Console, Hide_Output, Show_Command, Errors); end Execute_Command; --------------- -- Interrupt -- --------------- function Interrupt (Script : access Scripting_Language_Record) return Boolean is pragma Unreferenced (Script); begin return False; end Interrupt; -------------- -- Complete -- -------------- procedure Complete (Script : access Scripting_Language_Record; Input : String; Completions : out String_Lists.List) is pragma Unreferenced (Script, Input); begin Completions := String_Lists.Empty_List; end Complete; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Callback_Data; N : Positive; Default : Subprogram_Type) return Subprogram_Type is begin return Subprogram_Type'(Nth_Arg (Callback_Data'Class (Data), N)); exception when No_Such_Parameter => return Default; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Callback_Data; N : Positive; Default : String) return String is begin return Nth_Arg (Callback_Data'Class (Data), N); exception when No_Such_Parameter => return Default; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Callback_Data; N : Positive; Default : Filesystem_String) return Filesystem_String is begin return Nth_Arg (Callback_Data'Class (Data), N); exception when No_Such_Parameter => return Default; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Callback_Data; N : Positive; Default : Integer) return Integer is begin return Nth_Arg (Callback_Data'Class (Data), N); exception when No_Such_Parameter => return Default; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Callback_Data; N : Positive; Default : Float) return Float is begin return Nth_Arg (Callback_Data'Class (Data), N); exception when No_Such_Parameter => return Default; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Callback_Data; N : Positive; Default : Boolean) return Boolean is begin return Nth_Arg (Callback_Data'Class (Data), N); exception when No_Such_Parameter => return Default; end Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Callback_Data; N : Positive; Class : Class_Type := Any_Class; Default : Class_Instance; Allow_Null : Boolean := False) return Class_Instance is begin return Nth_Arg (Callback_Data'Class (Data), N, Class, Allow_Null); exception when No_Such_Parameter => return Default; end Nth_Arg; -------------------- -- Get_Repository -- -------------------- function Get_Repository (Data : Callback_Data) return Scripts_Repository is begin return Get_Repository (Get_Script (Callback_Data'Class (Data))); end Get_Repository; ---------- -- Free -- ---------- procedure Free (Subprogram : in out Subprogram_Type) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Subprogram_Record'Class, Subprogram_Type); begin if Subprogram /= null then Free (Subprogram.all); Unchecked_Free (Subprogram); end if; end Free; ------------- -- Execute -- ------------- function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return Boolean is Err : aliased Boolean; begin return Execute (Subprogram, Args, Err'Access); end Execute; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return String is Err : aliased Boolean; begin return Execute (Subprogram, Args, Err'Access); end Execute; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return Class_Instance is Err : aliased Boolean; begin return Execute (Subprogram, Args, Err'Access); end Execute; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return List_Instance'Class is Err : aliased Boolean; begin return Execute (Subprogram, Args, Err'Access); end Execute; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return Any_Type is Err : aliased Boolean; begin return Execute (Subprogram, Args, Err'Access); end Execute; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return GNAT.Strings.String_List is Err : aliased Boolean; begin return Execute (Subprogram, Args, Err'Access); end Execute; -------------------- -- Free_User_Data -- -------------------- procedure Free_User_Data (Data : in out User_Data_List) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (User_Data, User_Data_List); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Instance_Property_Record'Class, Instance_Property); begin if Data /= null then if Data.Prop /= null then Destroy (Data.Prop.all); Unchecked_Free (Data.Prop); end if; Unchecked_Free (Data); end if; end Free_User_Data; ------------------------- -- Free_User_Data_List -- ------------------------- procedure Free_User_Data_List (Data : in out User_Data_List) is D : User_Data_List; begin while Data /= null loop D := Data; Data := Data.Next; Free_User_Data (D); end loop; end Free_User_Data_List; ------------- -- Destroy -- ------------- procedure Destroy (Prop : in out Scalar_Properties_Record) is begin case Prop.Typ is when Strings => Free (Prop.Str); when Integers | Consoles | Booleans | Floats => null; end case; end Destroy; ------------- -- Get_CIR -- ------------- function Get_CIR (Inst : Class_Instance) return Class_Instance_Record_Access is begin return Class_Instance_Record_Access (Inst.Ref.Get); end Get_CIR; -------------------- -- Print_Refcount -- -------------------- function Print_Refcount (Instance : access Class_Instance_Record) return String is begin return "CI=(" & System.Address_Image (To_Address (Class_Instance_Record_Access (Instance))) & ')'; end Print_Refcount; ------------------- -- Get_User_Data -- ------------------- function Get_User_Data (Self : not null access Class_Instance_Record) return access User_Data_List is begin -- We could not make the operation abstract and private raise Program_Error with "Get_User_Data should be overridden"; return null; end Get_User_Data; -------------- -- Get_Data -- -------------- function Get_Data (Instance : access Class_Instance_Record'Class; Name : String) return User_Data_List is U : constant access User_Data_List := Instance.Get_User_Data; D : User_Data_List; begin if U /= null then D := U.all; while D /= null loop if D.Name = Name then return D; end if; D := D.Next; end loop; end if; return null; end Get_Data; -------------- -- Set_Data -- -------------- procedure Set_Data (Instance : Class_Instance; Name : String; Property : Instance_Property_Record'Class) is begin Set_Data (Instance.Ref.Get, Name, Property); end Set_Data; -------------- -- Set_Data -- -------------- procedure Set_Data (Instance : access Class_Instance_Record'Class; Name : String; Property : Instance_Property_Record'Class) is U : constant access User_Data_List := Instance.Get_User_Data; begin if U /= null then Unset_Data (Instance, Name); U.all := new User_Data' (Length => Name'Length, Name => Name, Next => U.all, Prop => new Instance_Property_Record'Class'(Property)); end if; end Set_Data; ---------------- -- Unset_Data -- ---------------- procedure Unset_Data (Instance : Class_Instance; Name : Class_Type) is begin Unset_Data (Instance.Ref.Get, Get_Name (Name)); end Unset_Data; ---------------- -- Unset_Data -- ---------------- procedure Unset_Data (Instance : Class_Instance; Name : String) is begin Unset_Data (Instance.Ref.Get, Name); end Unset_Data; ---------------- -- Unset_Data -- ---------------- procedure Unset_Data (Instance : access Class_Instance_Record'Class; Name : String) is U : constant access User_Data_List := Instance.Get_User_Data; D : User_Data_List; Previous : User_Data_List; begin if U /= null then D := U.all; while D /= null loop if D.Name = Name then if Previous = null then U.all := D.Next; else Previous.Next := D.Next; end if; Free_User_Data (D); return; end if; Previous := D; D := D.Next; end loop; end if; end Unset_Data; -------------- -- Set_Data -- -------------- procedure Set_Data (Instance : Class_Instance; Name : Class_Type; Value : String) is begin Set_Data (Instance, Get_Name (Name), Create_Property (Value)); end Set_Data; -------------- -- Set_Data -- -------------- procedure Set_Data (Instance : Class_Instance; Name : Class_Type; Value : Integer) is begin Set_Data (Instance, Get_Name (Name), Create_Property (Value)); end Set_Data; -------------- -- Set_Data -- -------------- procedure Set_Data (Instance : Class_Instance; Name : Class_Type; Value : Float) is begin Set_Data (Instance, Get_Name (Name), Create_Property (Value)); end Set_Data; -------------- -- Set_Data -- -------------- procedure Set_Data (Instance : Class_Instance; Name : Class_Type; Value : Boolean) is begin Set_Data (Instance, Get_Name (Name), Create_Property (Value)); end Set_Data; --------------------- -- Create_Property -- --------------------- function Create_Property (Val : Boolean) return Instance_Property_Record'Class is begin return Scalar_Properties_Record'(Typ => Booleans, Bool => Val); end Create_Property; --------------------- -- Create_Property -- --------------------- function Create_Property (Val : Integer) return Instance_Property_Record'Class is begin return Scalar_Properties_Record'(Typ => Integers, Int => Val); end Create_Property; --------------------- -- Create_Property -- --------------------- function Create_Property (Val : Float) return Instance_Property_Record'Class is begin return Scalar_Properties_Record'(Typ => Floats, Flt => Val); end Create_Property; --------------------- -- Create_Property -- --------------------- function Create_Property (Val : String) return Instance_Property_Record'Class is begin return Scalar_Properties_Record' (Typ => Strings, Str => new String'(Val)); end Create_Property; --------------- -- As_String -- --------------- function As_String (Prop : Instance_Property_Record'Class) return String is begin return Scalar_Properties_Record (Prop).Str.all; end As_String; ---------------- -- Get_Method -- ---------------- function Get_Method (Instance : Class_Instance; Name : String) return Subprogram_Type is begin return Get_Method (Get_CIR (Instance), Name); end Get_Method; -------------- -- Get_Data -- -------------- function Get_Data (Instance : access Class_Instance_Record'Class; Name : String) return Instance_Property is D : constant User_Data_List := Get_Data (Instance, Name); begin if D = null then return null; else return D.Prop; end if; end Get_Data; -------------- -- Get_Data -- -------------- function Get_Data (Instance : Class_Instance; Name : String) return Instance_Property is U : User_Data_List := null; begin if Instance.Ref.Get /= null then U := Get_Data (Get_CIR (Instance), Name); end if; if U /= null then return U.Prop; else return null; end if; end Get_Data; -------------- -- Get_Data -- -------------- function Get_Data (Instance : Class_Instance; Name : Class_Type) return Integer is Prop : constant Instance_Property := Get_Data (Instance, Get_Name (Name)); begin return Scalar_Properties (Prop).Int; end Get_Data; -------------- -- Get_Data -- -------------- function Get_Data (Instance : Class_Instance; Name : Class_Type) return Float is Prop : constant Instance_Property := Get_Data (Instance, Get_Name (Name)); begin return Scalar_Properties (Prop).Flt; end Get_Data; -------------- -- Get_Data -- -------------- function Get_Data (Instance : Class_Instance; Name : Class_Type) return Boolean is Prop : constant Instance_Property := Get_Data (Instance, Get_Name (Name)); begin return Scalar_Properties (Prop).Bool; end Get_Data; -------------- -- Get_Data -- -------------- function Get_Data (Instance : Class_Instance; Name : Class_Type) return String is Prop : constant Instance_Property := Get_Data (Instance, Get_Name (Name)); begin return Scalar_Properties (Prop).Str.all; end Get_Data; ------------------ -- Set_Property -- ------------------ procedure Set_Property (Instance : Class_Instance; Name : String; Value : Integer) is CIR : constant Class_Instance_Record_Access := Get_CIR (Instance); begin if CIR /= null then Set_Property (CIR, Name, Value); end if; end Set_Property; ------------------ -- Set_Property -- ------------------ procedure Set_Property (Instance : Class_Instance; Name : String; Value : Float) is CIR : constant Class_Instance_Record_Access := Get_CIR (Instance); begin if CIR /= null then Set_Property (CIR, Name, Value); end if; end Set_Property; ------------------ -- Set_Property -- ------------------ procedure Set_Property (Instance : Class_Instance; Name : String; Value : Boolean) is CIR : constant Class_Instance_Record_Access := Get_CIR (Instance); begin if CIR /= null then Set_Property (CIR, Name, Value); end if; end Set_Property; ------------------ -- Set_Property -- ------------------ procedure Set_Property (Instance : Class_Instance; Name : String; Value : String) is CIR : constant Class_Instance_Record_Access := Get_CIR (Instance); begin if CIR /= null then Set_Property (CIR, Name, Value); end if; end Set_Property; ---------------- -- Get_Script -- ---------------- function Get_Script (Instance : Class_Instance) return Scripting_Language is begin return Scripting_Language (Instance.Ref.Get.Script); end Get_Script; ----------------- -- Is_Subclass -- ----------------- function Is_Subclass (Instance : Class_Instance; Base : Class_Type) return Boolean is begin return Is_Subclass (Get_CIR (Instance), Get_Name (Base)); end Is_Subclass; function Is_Subclass (Instance : Class_Instance; Base : String) return Boolean is begin return Is_Subclass (Get_CIR (Instance), Base); end Is_Subclass; ------------------------- -- Set_Default_Console -- ------------------------- procedure Set_Default_Console (Script : access Scripting_Language_Record; Console : Virtual_Console) is begin if Script.Console /= null then Set_As_Default_Console (Script.Console, null); end if; if Console /= null then Set_As_Default_Console (Console, Scripting_Language (Script)); end if; Script.Console := Console; Display_Prompt (Scripting_Language (Script)); end Set_Default_Console; ------------------------- -- Get_Default_Console -- ------------------------- function Get_Default_Console (Script : access Scripting_Language_Record) return Virtual_Console is begin return Script.Console; end Get_Default_Console; -------------- -- Set_Data -- -------------- procedure Set_Data (Instance : Class_Instance; Console : access Virtual_Console_Record'Class) is begin -- Note: even if Console is a widget, the call to Set_Data_Primitive -- below will automatically take care of proper reference counting, so -- that no additional work is needed Set_Data_Primitive (Instance, Console); Set_Data (Instance, "virtualconsole", Scalar_Properties_Record' (Typ => Consoles, Console => Virtual_Console (Console))); end Set_Data; -------------- -- Get_Data -- -------------- function Get_Data (Instance : Class_Instance) return Virtual_Console is D : constant Instance_Property := Get_Data (Instance, "virtualconsole"); begin if D = null or else D.all not in Scalar_Properties_Record'Class or else Scalar_Properties (D).Typ /= Consoles then return null; else return Scalar_Properties (D).Console; end if; end Get_Data; ----------------------- -- Get_Console_Class -- ----------------------- function Get_Console_Class (Repo : access Scripts_Repository_Record'Class) return Class_Type is begin return Repo.Console_Class; end Get_Console_Class; ---------- -- Read -- ---------- function Read (Console : access Virtual_Console_Record; Size : Integer; Whole_Line : Boolean; Prompt : String) return String is begin if Prompt /= "" then Insert_Prompt (Virtual_Console (Console), Prompt); end if; return Read (Virtual_Console (Console), Size, Whole_Line); end Read; ---------- -- Read -- ---------- function Read (Console : access Virtual_Console_Record; Size : Integer; Whole_Line : Boolean) return String is pragma Unreferenced (Console, Size, Whole_Line); begin return ""; end Read; ---------------------------- -- Process_Pending_Events -- ---------------------------- procedure Process_Pending_Events (Console : access Virtual_Console_Record'Class) is begin -- We mustn't do that if the commands are hidden, for some obscur -- reason found in GPS (python-gui.adb:1.25) if not Console.Hide_Output then if Clock - Console.Refresh_Timeout > Timeout_Threshold then Process_Pending_Events_Primitive (Console); Console.Refresh_Timeout := Clock; end if; end if; end Process_Pending_Events; ----------------- -- Set_Nth_Arg -- ----------------- procedure Set_Nth_Arg (Data : in out Callback_Data'Class; N : Positive; Value : Filesystem_String) is begin Set_Nth_Arg (Data, N, +(Value)); end Set_Nth_Arg; ------------- -- Nth_Arg -- ------------- function Nth_Arg (Data : Callback_Data'Class; N : Positive) return Filesystem_String is begin return +Nth_Arg (Data, N); end Nth_Arg; ---------------------- -- Set_Return_Value -- ---------------------- procedure Set_Return_Value (Data : in out Callback_Data'Class; Value : Filesystem_String) is begin Set_Return_Value (Data, +Value); end Set_Return_Value; -------------- -- Load_All -- -------------- function Load_All (File : GNATCOLL.VFS.Virtual_File) return Boolean is pragma Unreferenced (File); begin return True; end Load_All; end GNATCOLL.Scripts; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-scripts.ads000066400000000000000000002106401425465243200230710ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This module provides various types and subprograms to integrate various -- external scripting languages. -- This API was designed so that multiple scripting languages can be used with -- your application, and so that the core of the applicatoin and all the -- various modules remain as independant as possible from the specific -- language. pragma Ada_2012; with Ada.Calendar; with Ada.Containers.Indefinite_Doubly_Linked_Lists; with Ada.Containers.Indefinite_Hashed_Maps; with Ada.Strings.Hash; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with GNAT.OS_Lib; with GNAT.Strings; with GNATCOLL.Arg_Lists; use GNATCOLL.Arg_Lists; with GNATCOLL.Refcount; use GNATCOLL.Refcount; with GNATCOLL.Utils; use GNATCOLL.Utils; with GNATCOLL.VFS; use GNATCOLL.VFS; with GNATCOLL.Any_Types; use GNATCOLL.Any_Types; with System; use System; package GNATCOLL.Scripts is type Scripts_Repository_Record is tagged private; type Scripts_Repository is access all Scripts_Repository_Record'Class; type Scripting_Language_Record is abstract tagged private; type Scripting_Language is access all Scripting_Language_Record'Class; type Cst_Argument_List is array (Natural range <>) of Cst_String_Access; type Callback_Data is abstract tagged private; type Callback_Data_Access is access all Callback_Data'Class; -- Data used to communicate with the scripting language engine, to marshall -- the parameters and return values. type Class_Instance is private; ---------------------- -- Subprogram types -- ---------------------- type Subprogram_Record is abstract tagged private; type Subprogram_Type is access all Subprogram_Record'Class; pragma No_Strict_Aliasing (Subprogram_Type); -- This type represents a subprogram for the language. In Python, this -- is a python object which is a function or method. -- Do not confuse this with a shell command, it has a more general meaning. -- In particular, the user cannot define new shell commands in the GPS -- shell, and thus Subprogram_Record has a broader meaning. procedure Free (Subprogram : in out Subprogram_Type); -- Free the subprogram function Get_Script (Subprogram : Subprogram_Record) return Scripting_Language is abstract; -- Return the language in which the subprogram was written procedure Free (Subprogram : in out Subprogram_Record) is abstract; -- Free the memory occupied by the subprogram instance function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return Boolean; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return String; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return Class_Instance; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return Any_Type; function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return GNAT.Strings.String_List; function Execute (Subprogram : access Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Boolean is abstract; function Execute (Subprogram : access Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return String is abstract; function Execute (Subprogram : access Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Class_Instance is abstract; function Execute (Subprogram : access Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return Any_Type is abstract; function Execute (Subprogram : access Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return GNAT.Strings.String_List is abstract; -- Execute the subprogram with the given arguments, and return its output. -- Returned value must be freed by the caller. -- For a String_List, some items in the result value might be left to null -- if the corresponding element from the shell is not a string. function Get_Name (Subprogram : access Subprogram_Record) return String is abstract; -- Return the name of the subprogram, as a string that can be displayed for -- the user. This is used when analysing the contents of a hook for -- instance ------------------ -- Module types -- ------------------ type Module_Type is private; Default_Module : constant Module_Type; -- A module is equivalent to an Ada package, or a namespace in C++. -- It is a way to group classes and subprograms into their own namespace. -- -- By default, all functions and classes are exported to the module defined -- in a module defined by the scripting language (for python, this default -- module is defined in GNATCOLL.Scripts.Python.Register_Python_Scripting). -- -- But it is possible to export to other modules instead function Lookup_Module (Repo : access Scripts_Repository_Record; Qualified_Name : String) return Module_Type; -- Lookup an existing module or create it if needed. -- The qualified name uses '.' as the separator, and all intermediate -- levels are created as needed. The name of the toplevel module must be -- included, so even if you passed "MyApp" as the Module name to -- Register_Python_Scripting, the qualified name here should look like -- MyApp.Module1.Module2 -- In practice, the module might not be created until you actually add a -- class or a function to it. -- As a special case, Qualified_Name may start with "@." to indicate a -- submodule of the default module, which avoids duplicating the name of -- that default module in several places of the application. ----------------- -- Class types -- ----------------- type Class_Type is private; No_Class : constant Class_Type; -- A class type, which can be used to create new instances. Primitive -- operations (aka methods) can be associated with the class. This is the -- primary way to make new subprograms available to the user, while -- organizing them into namespaces. Any_Class : constant Class_Type; -- Constant that can be used in the call to Nth_Arg below to indicate -- that the nth parameter is an instance, but its actual class is -- undefined No_Class_Instance : constant Class_Instance; -- The instance of a class, which embeds some Ada data. This type is -- reference counted, and will automatically take care of memory management -- issues. function Lookup_Class (Repo : access Scripts_Repository_Record; Name : String; Module : Module_Type := Default_Module) return Class_Type; -- Return a Class_Type for Name. -- If the given class does not exist, a dummy version is created (but is -- not exported to the scripting languages). This is for instance -- convenient to represent one of the builtin classes for the languages, -- although it might be dangerous since not all languages have the same -- builtins. -- If you use a dummy version as a base class in New_Class, and it doesn't -- exist in the language, then this is equivalent to not having a base -- class. function New_Class (Repo : access Scripts_Repository_Record'Class; Name : String; Base : Class_Type := No_Class; Module : Module_Type := Default_Module) return Class_Type; -- For some languages, this notion is not supported, and the class will not -- be visible by the user in the shell. Methods created for the class will -- then simply be made available directly in the shell. -- If a class with the same name was created, it is returned, and no class -- is created anew. -- Base is the base class, or parent class. It only needs to be specified -- the first time the class is created (typically just before the matching -- calls to Register_Command), and can be left to its default value -- afterward. -- Description of the new class must be put in the file shell_commands.xml, -- which is read dynamically when generating the documentation. function Get_Name (Class : Class_Type) return String; -- Return the name of the class (module.name) ------------------- -- Callback_Data -- ------------------- Invalid_Parameter : exception; No_Such_Parameter : exception; function Create (Script : access Scripting_Language_Record; Arguments_Count : Natural) return Callback_Data'Class is abstract; -- Create a new empty list of arguments. You must call Set_Nth_Arg for -- each of these arguments before using the return value. function Command_Line_Treatment (Script : access Scripting_Language_Record) return Command_Line_Mode is abstract; -- Indicates how command lines should be treated by GPS. -- If the returned type is Separate_Args, then GPS should handle the -- parsing and separating of arguments. -- Otherwise GPS should just manipulate the command lines as raw strings. procedure Free (Data : in out Callback_Data) is abstract; procedure Free (Data : in out Callback_Data_Access); -- Free the memory occupied by Data. This needs to be called only if Data -- was created through Create function Clone (Data : Callback_Data) return Callback_Data'Class is abstract; -- Clone Data. The result value must be freed by the caller procedure Set_Nth_Arg (Data : in out Callback_Data; N : Positive; Value : String) is abstract; procedure Set_Nth_Arg (Data : in out Callback_Data; N : Positive; Value : Integer) is abstract; procedure Set_Nth_Arg (Data : in out Callback_Data; N : Positive; Value : Float) is abstract; procedure Set_Nth_Arg (Data : in out Callback_Data; N : Positive; Value : Boolean) is abstract; procedure Set_Nth_Arg (Data : in out Callback_Data; N : Positive; Value : Class_Instance) is abstract; procedure Set_Nth_Arg (Data : in out Callback_Data; N : Positive; Value : Subprogram_Type) is abstract; procedure Set_Nth_Arg (Data : in out Callback_Data'Class; N : Positive; Value : Filesystem_String); -- Set the nth argument of Data function Number_Of_Arguments (Data : Callback_Data) return Natural is abstract; -- Return the number of arguments passed to that callback. The number of -- arguments has already been check before the transfer to your own -- subprogram. procedure Name_Parameters (Data : in out Callback_Data; Names : Cst_Argument_List) is abstract; -- Name the parameters, for languages which support it. -- For instance, the following call: -- Name_Parameters (Data, (1 => new String'("a"), -- 2 => new String'("b"), -- 3 => new String'("c"))); -- will provide support for the following python calls: -- func (1, 2, 3) -- func (1, c=3, b=2) -- This call has no effect for languages which do not support name -- parameters. -- After calling this procedure, the parameters are reordered so that no -- matter what order the user specified them in, calling Nth_Arg (2) will -- always return the value for b. -- You should pass a default value to Nth_Arg, since otherwise if a -- parameter was not given on the command line, even if later parameters -- were given, Nth_Arg will raise Invalid_Parameter. -- -- It is recommended that Names be a global constant, which you can also -- use when registering the command, through Parameter_Names_To_Usage, so -- that the documentation remains up-to-date. -- -- Names should not include "self" in the case of methods. This is an -- implicit parameter in most languages. function Get_Script (Data : Callback_Data) return Scripting_Language is abstract; -- Return the scripting language that created Data function Get_Repository (Data : Callback_Data) return Scripts_Repository; -- Return the kernel associated with Data function Nth_Arg (Data : Callback_Data; N : Positive) return String is abstract; function Nth_Arg (Data : Callback_Data; N : Positive) return Unbounded_String is abstract; function Nth_Arg (Data : Callback_Data'Class; N : Positive) return Filesystem_String; function Nth_Arg (Data : Callback_Data; N : Positive) return Integer is abstract; function Nth_Arg (Data : Callback_Data; N : Positive) return Float is abstract; function Nth_Arg (Data : Callback_Data; N : Positive) return Boolean is abstract; -- Get the nth argument to the function, starting from 1. -- If there is not enough parameters, No_Such_Parameter is raised -- If the parameters doesn't have the right type, Invalid_Parameter is -- raised. function Nth_Arg (Data : Callback_Data; N : Positive) return Subprogram_Type is abstract; -- Same as above, for a subprogram. The returned value must be freed function Nth_Arg (Data : Callback_Data; N : Positive; Class : Class_Type := Any_Class; Allow_Null : Boolean := False) return Class_Instance is abstract; -- The class_instance must belong to Class or its children, or -- Invalid_Parameter is also raised. -- The return value must be freed by the caller. -- If Allow_Null is true, then a null instance might be passed as a -- parameter. If it is false, passing a null instance will raise -- Invalid_Parameter. -- Class can be set to Any_Class to indicate that the instance can be -- of any class. function Nth_Arg (Data : Callback_Data; N : Positive; Default : String) return String; function Nth_Arg (Data : Callback_Data; N : Positive; Default : Filesystem_String) return Filesystem_String; function Nth_Arg (Data : Callback_Data; N : Positive; Default : Integer) return Integer; function Nth_Arg (Data : Callback_Data; N : Positive; Default : Float) return Float; function Nth_Arg (Data : Callback_Data; N : Positive; Default : Boolean) return Boolean; function Nth_Arg (Data : Callback_Data; N : Positive; Class : Class_Type := Any_Class; Default : Class_Instance; Allow_Null : Boolean := False) return Class_Instance; function Nth_Arg (Data : Callback_Data; N : Positive; Default : Subprogram_Type) return Subprogram_Type; -- Same as above, except that if there are not enough parameters, Default -- is returned. Returned value must be freed. procedure Set_Error_Msg (Data : in out Callback_Data; Msg : String) is abstract; -- Set an error message. -- The return value for this callback will be ignored. On most languages -- (python,...) this is equivalent to raising an exception. -- If Msg is set to the empty string, an exception will still be raised procedure Set_Return_Value_As_List (Data : in out Callback_Data; Size : Natural := 0; Class : Class_Type := No_Class) is abstract; -- Setup the return value as an empty list. New values can be appended to -- the list with Set_Return_Value. -- It is possible to override the exact returned type by setting Class. -- This should however be a subclass of the builtin "list" for language -- in which it makes sense. This is often risky if one of the scripting -- languages your application cannot create subclasses of lists. -- If Size is not 0, then the list has a fixed size. Depending on the -- language, this could be a different type, such as a tuple in python. -- -- See also the documentation for List_Instance for a full example -- returning a list to the scripting language. procedure Set_Return_Value (Data : in out Callback_Data; Value : Integer) is abstract; procedure Set_Return_Value (Data : in out Callback_Data; Value : Float) is abstract; procedure Set_Return_Value (Data : in out Callback_Data; Value : String) is abstract; procedure Set_Return_Value (Data : in out Callback_Data; Value : Boolean) is abstract; procedure Set_Return_Value (Data : in out Callback_Data; Value : Class_Instance) is abstract; procedure Set_Return_Value (Data : in out Callback_Data'Class; Value : Filesystem_String); -- Set the return value of Data. -- If the return value was set as a list, Value is appended to the -- list. For languages that do not support lists, the append is only -- performed for strings (newline-separated). Other data types simply -- replace the current return value. procedure Set_Address_Return_Value (Data : in out Callback_Data; Value : System.Address) is abstract; -- Set the return value of Data to Value. The address will be represented -- as an integer on the python side, and a string in Shell. -- -- NOTE: This is a low level primitive, and is not meant to be used as-is, -- as there is no appropriate representation of an address object on the -- python side. Rather, this is meant to be used in tandem with ctypes: -- -- On the Ada side: -- -- Set_Address_Return_Value (Data, My_Integer'Address); -- -- On the python side: -- -- import ctypes -- int_ptr = ctypes.POINTER(ctypes.int) -- -- # This is the result of the above Set_Address_Return_Value -- ada_address = AdaClass.ada_exposed_function() -- -- # We then convert it to a ctypes pointer -- c_int = ctypes.cast(int_ptr, ada_address) -- -- WARNING: This is a low level primitive dealing with memory, and as such, -- it is unsafe ! Make sure that the life time of the object you pass -- corresponds to the way it is used on the python side procedure Set_Return_Value_Key (Data : in out Callback_Data; Key : String; Append : Boolean := False) is abstract; procedure Set_Return_Value_Key (Data : in out Callback_Data; Key : Integer; Append : Boolean := False) is abstract; procedure Set_Return_Value_Key (Data : in out Callback_Data; Key : Class_Instance; Append : Boolean := False) is abstract; -- Move the current value of Data, as set by Set_Return_Value into a -- htable. -- Typical usage would be: -- Set_Return_Value (Data, 12); -- Set_Return_Value_Key (Data, "key1"); -- -- Set_Return_Value_As_List (Data); -- Set_Return_Value (Data, 1); -- Set_Return_Value (Data, 2); -- Set_Return_Value_Key (Data, "key2"); -- will create a htable containing (key1 => 12, key2 => (1, 2)) -- -- If Append is true and there is already a value set for Key, then the new -- value is append to it (a list is created if necessary). This might not -- be supported for languages that do not explicitly support htables like -- the GPS shell. -- -- No provision is made for creating htables of htables, although htables -- of lists are supported, or for getting the currently set value for Key. function Return_Value (Data : Callback_Data) return String is abstract; function Return_Value (Data : Callback_Data) return Integer is abstract; function Return_Value (Data : Callback_Data) return Float is abstract; function Return_Value (Data : Callback_Data) return Boolean is abstract; function Return_Value (Data : Callback_Data) return Class_Instance is abstract; -- Return the value returned by a script function, via a call to -- Execute_Command below. -- If the type you are requesting is not compatible with the actual -- returned value, Invalid_Parameter is raised. -- See also Return_Value below, which returns a List_Instance'Class. ----------- -- Lists -- ----------- subtype List_Instance is Callback_Data'Class; -- Represents a list passed as parameter. -- In the context of a list, Set_Nth_Arg will always append to the list if -- the given index is outside of the current range of the list. -- -- To return a list to the scripting language, you can therefore do the -- following: -- -- procedure Handler (Data : in out Callback_Data'Class; Cmd : String) is -- List : List_Instance := New_List (Get_Script (Data)); -- begin -- Set_Nth_Arg (List, Natural'Last, 12); -- Set_Nth_Arg (List, Natural'Last, "value"); -- Set_Return_Value (Data, List); -- end; -- -- The handling of the list can be made transparent by using the following -- construct: -- -- procedure Handler (Data : in out Callback_Data'Class; Cmd : String) is -- begin -- Set_Return_Value_As_List (Data); -- Set_Return_Value (Data, 12); -- Set_Return_Value (Data, "value"); -- end; -- -- However, this second approach does not let you return lists of list, -- for instance, which is doable with the first approach. function New_List (Script : access Scripting_Language_Record; Class : Class_Type := No_Class) return List_Instance'Class is abstract; -- Creates a new empty list -- It is possible to override the exact returned type by setting Class. -- This should however be a subclass of the builtin "list" for language -- in which it makes sense. This is often risky if one of the scripting -- languages your application cannot create subclasses of lists. function Nth_Arg (Data : Callback_Data; N : Positive) return List_Instance'Class is abstract; -- Get a list parameter. The default value is always the empty list, but -- you can still get an Invalid_Parameter exception if the corresponding -- parameter is not a list. -- In the case of python, this function will accept any iterable type (a -- list, a tuple, a user-defined type with a __iter__ method, even a -- dictionary or a string). function Execute (Subprogram : access Subprogram_Record'Class; Args : Callback_Data'Class) return List_Instance; function Execute (Subprogram : access Subprogram_Record; Args : Callback_Data'Class; Error : not null access Boolean) return List_Instance'Class is abstract; -- Execute a subprogram and assumes it returns a list. -- The resulting List must be freed by the caller. function Return_Value (Data : Callback_Data) return List_Instance'Class is abstract; -- Returns the list returned by a command (see Execute_Command). procedure Set_Nth_Arg (Data : in out Callback_Data; N : Positive; Value : List_Instance) is abstract; -- Override the nth arg in Data procedure Set_Return_Value (Data : in out Callback_Data; Value : List_Instance) is abstract; -- Set the value returned to the shell ------------------ -- Dictionaries -- ------------------ type Dictionary_Instance is abstract tagged null record; type Dictionary_Iterator is abstract tagged null record; function Nth_Arg (Data : Callback_Data; N : Positive) return Dictionary_Instance'Class is abstract; -- Get a dictionary parameter. The default value is always the empty -- dictionary, but you can still get an Invalid_Parameter exception if the -- corresponding parameter is not a list. function Iterator (Self : Dictionary_Instance) return Dictionary_Iterator'Class is abstract; -- Returns an iterator for the given dictionary. The returned iterator -- doesn't point to any pair in dictionary until the first call to Next function Has_Key (Self : Dictionary_Instance; Key : String) return Boolean is abstract; function Has_Key (Self : Dictionary_Instance; Key : Integer) return Boolean is abstract; function Has_Key (Self : Dictionary_Instance; Key : Float) return Boolean is abstract; function Has_Key (Self : Dictionary_Instance; Key : Boolean) return Boolean is abstract; -- Returns True when dictionary has value for given key function Value (Self : Dictionary_Instance; Key : String) return String is abstract; function Value (Self : Dictionary_Instance; Key : Integer) return String is abstract; function Value (Self : Dictionary_Instance; Key : Float) return String is abstract; function Value (Self : Dictionary_Instance; Key : Boolean) return String is abstract; function Value (Self : Dictionary_Instance; Key : String) return Integer is abstract; function Value (Self : Dictionary_Instance; Key : Integer) return Integer is abstract; function Value (Self : Dictionary_Instance; Key : Float) return Integer is abstract; function Value (Self : Dictionary_Instance; Key : Boolean) return Integer is abstract; function Value (Self : Dictionary_Instance; Key : String) return Float is abstract; function Value (Self : Dictionary_Instance; Key : Integer) return Float is abstract; function Value (Self : Dictionary_Instance; Key : Float) return Float is abstract; function Value (Self : Dictionary_Instance; Key : Boolean) return Float is abstract; function Value (Self : Dictionary_Instance; Key : String) return Boolean is abstract; function Value (Self : Dictionary_Instance; Key : Integer) return Boolean is abstract; function Value (Self : Dictionary_Instance; Key : Float) return Boolean is abstract; function Value (Self : Dictionary_Instance; Key : Boolean) return Boolean is abstract; -- Returns value of given key function Next (Self : not null access Dictionary_Iterator) return Boolean is abstract; -- Moves iterator to the next pair in dictionary. Returns False when there -- are no more pairs available. This allows to minimize code to iterator -- over dictionaries: -- -- declare -- Iter : aliased Dictionary_Iterator'Class := Dict.Iterator; -- begin -- while Next (Iter) loop -- ... -- end loop; -- end; function Key (Self : Dictionary_Iterator) return String is abstract; function Key (Self : Dictionary_Iterator) return Integer is abstract; function Key (Self : Dictionary_Iterator) return Float is abstract; function Key (Self : Dictionary_Iterator) return Boolean is abstract; -- Returns value of current pair in dictionary function Value (Self : Dictionary_Iterator) return String is abstract; function Value (Self : Dictionary_Iterator) return Integer is abstract; function Value (Self : Dictionary_Iterator) return Float is abstract; function Value (Self : Dictionary_Iterator) return Boolean is abstract; -- Returns value of current pair in dictionary --------------------- -- Class instances -- --------------------- Invalid_Data : exception; function New_Instance (Script : access Scripting_Language_Record; Class : Class_Type) return Class_Instance is abstract; -- Create a new instance of the class. -- No data is stored in the object. -- This call should generally be the result of the user calling a -- function, which acts as a constructor for the class. -- The instance constructor (Constructor_Method) is not called, even -- though the instance has been properly initialized. You should therefore -- perform any initialization manually just after calling New_Instance. function Get_Method (Instance : Class_Instance; Name : String) return Subprogram_Type; -- Return the method of instance Instance. Returned value must be freed by -- the caller. -- Parameters passed to the return value must not specify the instance as -- first parameter. function Is_Subclass (Instance : Class_Instance; Base : Class_Type) return Boolean; function Is_Subclass (Instance : Class_Instance; Base : String) return Boolean; -- Whether Instance is a Base or from a subclass of Base function Get_Script (Instance : Class_Instance) return Scripting_Language; -- Return the scripting language that created this instance function Get_Data (Instance : Class_Instance; Name : Class_Type) return Integer; function Get_Data (Instance : Class_Instance; Name : Class_Type) return Float; function Get_Data (Instance : Class_Instance; Name : Class_Type) return String; function Get_Data (Instance : Class_Instance; Name : Class_Type) return Boolean; -- Get the data embedded in the class. -- These are specialized cases of Get_Data below. -- Invalid_Data is raised if no such data was stored in the instance. -- Constraint_Error is raised if the data is not of the appropriate type. -- Class is used to differentiate the data for instances that inherit from -- several GPS classes, as in: -- class Foo (GPS.Console, GPS.Process): -- def __init__ (self): -- GPS.Console.__init__ (self,..) -- GPS.Process.__init__ (self,...) -- since both internal classes expect different data stored internally procedure Unset_Data (Instance : Class_Instance; Name : Class_Type); procedure Unset_Data (Instance : Class_Instance; Name : String); -- Unset all data stored for the given name procedure Set_Data (Instance : Class_Instance; Name : Class_Type; Value : String); procedure Set_Data (Instance : Class_Instance; Name : Class_Type; Value : Integer); procedure Set_Data (Instance : Class_Instance; Name : Class_Type; Value : Float); procedure Set_Data (Instance : Class_Instance; Name : Class_Type; Value : Boolean); -- Associate some data with the instance. -- These are specialized cases of Set_Data below. -- The class name is required to handle multiple inheritance: if we were -- always using the same internal identifier to associated data with the -- instance, then we couldn't have a class with multiple ancestors, each -- expecting its own user data set in the constructor. procedure Set_Property (Instance : Class_Instance; Name : String; Value : Integer); procedure Set_Property (Instance : Class_Instance; Name : String; Value : Float); procedure Set_Property (Instance : Class_Instance; Name : String; Value : String); procedure Set_Property (Instance : Class_Instance; Name : String; Value : Boolean); -- Export a field stored in the instance. -- The way to access it depends on the language: -- - in the GPS shell, you need to prefix its name with "@", as in: -- > Console "foo" # Create new instance -- > @id %1 # Access its "id" property -- - in Python, this is used with the usual python conventions: -- > c = Console ("foo") -- > c.id -- The value of the field can be overridden in the scripting language, but -- this change will not be reflected in Ada. For instance, in python: -- c.id = 2 -- is valid, but will have no effect on the Ada side. -- -- If you want true read-only properties, you need to use Register_Property -- through getters and setters. -- -- In Python, this procedure doesn't go through the class's __setattr_ -- function. -------------------- -- Instance lists -- -------------------- -- Most internal objects, when exported to a shell, should reuse the same -- class instance whenever the same physical object is referenced. This is -- so that the user can store user data within the instance, and get it -- back easily the next time the same object is referenced. -- For types derived from GObject_Record, we provide appropriate Set_Data -- and Get_Data subprograms. For other types, the instance_list type can -- be used to store the instances (of which there is one per scripting -- language). type Instance_List is private; Null_Instance_List : constant Instance_List; -- Stores the instance created for some GPS internal data, so that the same -- script instance is reused every time we reference the same Ada object. type Inst_Cursor is private; function First (Self : Instance_List) return Inst_Cursor; procedure Next (Self : Instance_List; Pos : in out Inst_Cursor); function Has_Element (Position : Inst_Cursor) return Boolean; function Element (Self : Instance_List; Pos : Inst_Cursor) return Class_Instance; -- Iterate on the list of instances stored in a list. Only valid -- instances are returned (never a No_Class_Instance) procedure Free (List : in out Instance_List); -- Free the instances stored in the list function Get (List : Instance_List; Script : access Scripting_Language_Record'Class) return Class_Instance; -- Return the instance for a given script procedure Set (List : in out Instance_List; Inst : Class_Instance); -- Set the instance for a specific language ------------------------- -- Instance properties -- ------------------------- type Instance_Property_Record is abstract tagged null record; type Instance_Property is access all Instance_Property_Record'Class; procedure Destroy (Prop : in out Instance_Property_Record); -- Type of data that can be associated with a class_instance. This is a -- general type, but simpler types are provided already function Create_Property (Val : Boolean) return Instance_Property_Record'Class; function Create_Property (Val : Integer) return Instance_Property_Record'Class; function Create_Property (Val : Float) return Instance_Property_Record'Class; function Create_Property (Val : String) return Instance_Property_Record'Class; -- Return an instance of Instance_Property that wraps one of the basic -- types. The returned value must be Destroyed, unless you store it -- through Set_Data, in which case GNATCOLL will take care of that. function As_String (Prop : Instance_Property_Record'Class) return String; -- Assuming Prop was created with Create_Property, return its value procedure Set_Data (Instance : Class_Instance; Name : String; Property : Instance_Property_Record'Class); -- Associate user data with Instance. Multiple data can be stored in a -- given instance, each associated with a different Name. Typically, GPS -- classes use the class name as the property name to avoid conflicts. -- When the property is no longer needed (either because it is replaced by -- another one with the same name, or because Instance is destroyed), the -- Destroy operation is called on Property. -- Note that a copy of Property is stored, not Property itself. -- -- A simplified interface for some scalar types is also defined, see -- Set_Data above function Get_Data (Instance : Class_Instance; Name : String) return Instance_Property; -- Return a general property associated with the widget. -- Return null if there is no such property. --------------------------- -- Class_Instance_Record -- --------------------------- -- This type encapsulate some language specific data. It is overridden by -- each of the scripting languages. Do not use directly unless you are -- implementing a new scripting language type Class_Instance_Record is abstract tagged private; type Class_Instance_Record_Access is access all Class_Instance_Record'Class; -- A type overridden by each of the scripting languages function Is_Subclass (Instance : access Class_Instance_Record; Base : String) return Boolean is abstract; -- Whether Instance is a Base or from a subclass of Base. Do not use -- directly, use the version that takes a Class_Instance instead function Get_CIR (Inst : Class_Instance) return Class_Instance_Record_Access; -- For internal use only function Get_Method (Inst : access Class_Instance_Record; Name : String) return Subprogram_Type is abstract; function Print_Refcount (Instance : access Class_Instance_Record) return String; -- Debug only: print the reference counting for this instance. -- Implementations are encourage to concatenate with the inherited -- method's result procedure Set_Property (Instance : access Class_Instance_Record; Name : String; Value : Integer) is abstract; procedure Set_Property (Instance : access Class_Instance_Record; Name : String; Value : Float) is abstract; procedure Set_Property (Instance : access Class_Instance_Record; Name : String; Value : Boolean) is abstract; procedure Set_Property (Instance : access Class_Instance_Record; Name : String; Value : String) is abstract; -- See definition of Set_Constant (Class_Instance) procedure Set_Data (Instance : access Class_Instance_Record'Class; Name : String; Property : Instance_Property_Record'Class); function Get_Data (Instance : access Class_Instance_Record'Class; Name : String) return Instance_Property; -- Internal version of Set_Data/Get_Data. -- For internal use only ------------------------- -- Callback_Data lists -- ------------------------- -- This type's goal is similar to the one for the instance lists, since the -- callback_data are also language-specific type Callback_Data_List is private; -- Stores a list of callback_data, each associated with a different -- scripting language procedure Free (List : in out Callback_Data_List); -- Free the instances stored in the list function Get (Repo : access Scripts_Repository_Record'Class; List : Callback_Data_List; Script : access Scripting_Language_Record'Class) return Callback_Data_Access; -- Return the data for a given script. -- The returned value should not be freed by the caller, it is the -- responsability of the callback_data_list to do so. procedure Set (Repo : access Scripts_Repository_Record'Class; List : in out Callback_Data_List; Script : access Scripting_Language_Record'Class; Data : Callback_Data_Access); -- Set the data for a specific language. Data should not be freed by the -- caller. --------------- -- Consoles -- --------------- -- When executing script commands, they will very often produce some -- output, including possibly error or log messages. The following class -- acts as a small wrapper around more advanced types of console, like a -- text-mode console, or a GtkAda console. This type is used so that the -- subprograms below can be used both in graphical and textual mode type Virtual_Console_Record is abstract tagged private; type Virtual_Console is access all Virtual_Console_Record'Class; procedure Insert_Text (Console : access Virtual_Console_Record; Txt : String) is abstract; -- Prints some output in the console procedure Insert_Log (Console : access Virtual_Console_Record; Txt : String) is null; pragma Obsolescent (Insert_Log); -- ignored, kept for backward compatibility only procedure Insert_Error (Console : access Virtual_Console_Record; Txt : String) is abstract; -- Prints an error message resulting from the wrong execution of a script procedure Insert_Prompt (Console : access Virtual_Console_Record; Txt : String) is abstract; -- Display Txt as a new prompt in the console procedure Ref (Console : access Virtual_Console_Record) is null; procedure Unref (Console : access Virtual_Console_Record) is null; -- Increment or decrement the reference counting for the console, if that -- notion makes sense for that particular console. -- The idea is that when we are temporary using a different console for the -- output, we do not want the default console to be destroyed -- automatically, in case its only reference was hold by the scripting -- language. procedure Grab_Events (Console : access Virtual_Console_Record; Grab : Boolean) is null; -- Make sure all graphical events go to the console instead of the rest of -- the application. -- This is mostly used to avoid recursive re-entrant calls to the script -- interpreter. procedure Set_As_Default_Console (Console : access Virtual_Console_Record; Script : Scripting_Language := null) is null; -- Called when Console becomes the default console for the scripting -- language Script. -- Script might be null when the Console is no longer the default console -- for that script. procedure Set_Data_Primitive (Instance : Class_Instance; Console : access Virtual_Console_Record) is abstract; function Get_Instance (Script : access Scripting_Language_Record'Class; Console : access Virtual_Console_Record) return Class_Instance is abstract; -- Associate a console and class instances, so that a given instance is -- always associated with the same class instance. -- Typical example of implementation would be: -- type My_Console is new Virtual_Console_Record with record -- Instances : Instance_List; -- end record; -- -- procedure Set_Data_Primitive (...) is -- begin -- Set (Console.Instances, Get_Script (Instance), Instance); -- end Set_Data_Primitive; -- -- function Get_Instance (...) is -- begin -- return Get (Console.Instances, Script); -- end Get_Instance; procedure Set_Data (Instance : Class_Instance; Console : access Virtual_Console_Record'Class); function Get_Data (Instance : Class_Instance) return Virtual_Console; -- Return the virtual console stored in Instance procedure Process_Pending_Events_Primitive (Console : access Virtual_Console_Record) is null; procedure Process_Pending_Events (Console : access Virtual_Console_Record'Class); -- Process all pending graphical events, so that the application is -- properly refreshed while a script is running. -- This package will properly make sure this function is not called too -- often, so you don't need to do additional work for that procedure Clear (Console : access Virtual_Console_Record) is null; -- Clear the contents of the console function Read (Console : access Virtual_Console_Record; Size : Integer; Whole_Line : Boolean; Prompt : String) return String; function Read (Console : access Virtual_Console_Record; Size : Integer; Whole_Line : Boolean) return String; -- Return at most Size characters from the console. -- If Whole_Line is true, the returned value stops at the first newline -- character seen in any case. -- If Prompt is specified, it is displayed first (via Insert_Prompt). ------------------------- -- Scripting languages -- ------------------------- type Module_Command_Function is access procedure (Data : in out Callback_Data'Class; Command : String); -- The callback handler for a command. -- The first argument is always the instance to which the method applies, -- if Command is a method. -- Should raise Invalid_Parameters if one of the parameters is incorrect. -- The number of parameters has been checked before this procedure is -- called. procedure Destroy (Script : access Scripting_Language_Record) is null; -- Destroy the scripting language and the memory it occupies type Param_Descr is private; type Param_Array is array (Natural range <>) of Param_Descr; type Param_Array_Access is access all Param_Array; No_Params : constant Param_Array; -- Description of a parameter function Param (Name : String; Optional : Boolean := False) return Param_Descr; -- Describe one of the parameters of a script function type Command_Descr; type Command_Descr_Access is access all Command_Descr; type Command_Descr (Length : Natural) is record Command : String (1 .. Length); Handler : Module_Command_Function; Class : Class_Type := No_Class; Params : Param_Array_Access; Static_Method : Boolean := False; Minimum_Args : Natural := 0; Maximum_Args : Natural := 0; Next : Command_Descr_Access; end record; -- Params is left to null if the user did not specify the name of -- parameters in the call to Register_Command (this is different from -- having a non-null but empty Params, which indicates there are no -- parameters). procedure Register_Command (Script : access Scripting_Language_Record; Command : Command_Descr_Access) is abstract; -- Register a new callback for a command. -- Command will exist as long as Script, so it is safe (and recommended) -- that script points to Command instead of duplicating the data. This -- saves memory by sharing storage among all the scripting languages. -- See also Register_Command applied to the script_repository for more -- information. type Property_Descr; type Property_Descr_Access is access all Property_Descr; type Property_Descr (Length : Natural) is record Name : String (1 .. Length); Class : Class_Type; Setter : Module_Command_Function; Getter : Module_Command_Function; Next : Property_Descr_Access; end record; -- The setter passes two parameters: first one is the instance, second one -- is the value of the property. Note that the property is untyped: you -- might have to try the various Nth_Arg to find out which type the user -- has passed. You can use Set_Error_Message if the property does not have -- the expected type. -- -- The getter passes one parameter in Callback, which is the instance on -- which the property applies. -- It should call Set_Return_Value to return the value of the property. -- -- You can potentially use the same callback in both cases, and count the -- number of arguments to find out whether the user is querying or setting -- the property. procedure Register_Property (Script : access Scripting_Language_Record; Prop : Property_Descr_Access) is abstract; -- See documentation of Register_Property applied on the Scripts_Repository procedure Register_Class (Script : access Scripting_Language_Record; Name : String; Base : Class_Type := No_Class; Module : Module_Type := Default_Module) is abstract; -- Create a new class in the interpreter. -- This is a low-level procedure, use New_Class instead procedure Block_Commands (Script : access Scripting_Language_Record; Block : Boolean) is abstract; -- If Block is true, no command can be executed for this scripting language procedure Set_Default_Console (Script : access Scripting_Language_Record; Console : Virtual_Console); -- Defines the console to use to display output, when none is specified -- to Execute_Command below function Get_Default_Console (Script : access Scripting_Language_Record) return Virtual_Console; -- Return the default console used for all outputs by this scripting -- language procedure Display_Prompt (Script : access Scripting_Language_Record; Console : Virtual_Console := null) is null; -- Display the prompt on the script's default console. It uses -- Display_Prompt to compute the prompt to display. function Get_Prompt (Script : access Scripting_Language_Record) return String is abstract; -- Return the prompt to display procedure Execute_Command (Script : access Scripting_Language_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : out Boolean) is abstract; -- Execute a command in the script language. -- It isn't possible to retrieve the result of that command, this command -- is only used for its side effect. -- Depending on the language, Command might be a list of commands to -- execute, often semicolon or newline separated. -- Errors is set to True if there was any error executing the script. -- -- The result of the command, as well as the text of the command itself, -- are not visible to the user if Hide_Output is True. Otherwise, the text -- is sent to Console. Any output done by the command, however (via "print" -- or "sys.stdout.write" statements for instance in python) will be -- displayed. -- -- If Show_Command is True and Hide_Output is False, then the command -- itself is also printed in the console function Execute_Command (Script : access Scripting_Language_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : access Boolean) return String; -- Execute a command, and return its output as a displayable string. -- Note: some languages might simply return an empty string if they cannot -- capture the output of their interpreter. This command is mostly useful -- for the GPS shell, but also supported by python. -- Command can never be a list of commands (no semicolon or newline -- separated). function Execute_Command (Script : access Scripting_Language_Record; CL : Arg_List; Console : Virtual_Console := null; Hide_Output : Boolean := False; Errors : access Boolean) return Boolean is abstract; -- Execute a command and evaluate its return value (*not* its output) as a -- boolean. This is different from the version returning a string, in that -- only the return value is considered, not the full output. procedure Execute_Command (Script : access Scripting_Language_Record; Command : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : out Boolean); function Execute_Command (Script : access Scripting_Language_Record; Command : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Errors : access Boolean) return Boolean; function Execute_Command (Script : Scripting_Language; Command : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : access Boolean) return String; -- Same as above, working direcly on a String. This String is interpreted -- as a command line using the mechanism described in -- GNATCOLL.Command_Lines. -- These are only provided for backward compatibility and you should use -- directly the version that takes a Command_Line whenever possible. function Execute_Command (Script : access Scripting_Language_Record; Command : String; Args : Callback_Data'Class) return Boolean is abstract; -- Execute a command, the argument of which are specified separately in -- Args. -- Return the value returned by the command itself. Error_In_Command : exception; procedure Execute_Expression (Result : in out Callback_Data; Expression : String; Hide_Output : Boolean := True) is abstract; -- Execute any expression, and store the result in Result. -- Resulted must have been Created, all its arguments are ignored. -- It must be freed by the caller. procedure Execute_Command (Args : in out Callback_Data; Command : String; Hide_Output : Boolean := True) is abstract; -- Execute the given function passing one or more arguments via Args. -- On exit, Args is modified to contain the value returned by the command. -- If you know the expected result type, you can then use the Return_Value -- functions above to retrieve the values. -- declare -- C : Callback_Data'Class := Create (Script, 1); -- begin -- Set_Nth_Arg (C, 1, "some value"); -- Execute_Command (C, "somefunction"); -- Put_Line (Return_Value (C)); -- If returned a string -- Put_Line (Integer'Image (Return_Value (C))); -- If an integer -- -- declare -- L : List_Instance'Class := Return_Value (C); -- If a list -- begin -- for Item in 1 .. Number_Of_Arguments (L) loop -- Put_Line (Nth_Arg (L, Item)); -- A list of strings ? -- end loop; -- end; -- end; -- -- If the command returns an error (or raised an exception), an Ada -- exception is raised in turn (Error_In_Command). The exception is also -- printed on the current console for the language. -- -- This procedure expects Command to be the name of a function. To -- execute any expression, see Execute_Expression instead function Execute_Command_With_Args (Script : access Scripting_Language_Record; CL : Arg_List) return String; -- Execute a command. -- This procedure needs only be implemented for the GPS shell, in all other -- language you should keep the default which raises Program_Error, since -- this function is not used anywhere but for shell commands. -- All output is hidden procedure Execute_File (Script : access Scripting_Language_Record; Filename : String; Console : Virtual_Console := null; Hide_Output : Boolean := False; Show_Command : Boolean := True; Errors : out Boolean) is abstract; -- Execute a script contained in an external file type Script_Loader is access function (File : GNATCOLL.VFS.Virtual_File) return Boolean; function Load_All (File : GNATCOLL.VFS.Virtual_File) return Boolean; -- Given the name of a script, returns True if the script should be loaded procedure Load_Directory (Script : access Scripting_Language_Record; Directory : GNATCOLL.VFS.Virtual_File; To_Load : Script_Loader := Load_All'Access) is null; -- Load all scripts found in the given directory, and for which To_Load -- returns True. function Interrupt (Script : access Scripting_Language_Record) return Boolean; -- Interrupt the command currently executed. -- The interrupt need not be synchronous, but should occur as soon as -- possible. -- Returns True if the execution could be interrupt, False if there is no -- command being executed, or it can't be interrupted package String_Lists is new Ada.Containers.Indefinite_Doubly_Linked_Lists (String); package String_Lists_Sort is new String_Lists.Generic_Sorting; procedure Complete (Script : access Scripting_Language_Record; Input : String; Completions : out String_Lists.List); -- Provide the list of possible completion when the user has typed Input in -- a console. This completion can be as smart as possible, but can also -- return an empty list if that scripting language doesn't support -- completion. function Get_Name (Script : access Scripting_Language_Record) return String is abstract; -- The name of the scripting language function Get_Repository (Script : access Scripting_Language_Record) return Scripts_Repository is abstract; -- Return the kernel in which Script is registered function Current_Script (Script : access Scripting_Language_Record) return String is abstract; -- Return the name of the current script (file or inline script) that we -- are executing. When unknown, the empty string should be returned. -------------------------- -- Commands and methods -- -------------------------- Constructor_Method : constant String; Addition_Method : constant String; Substraction_Method : constant String; Destructor_Method : constant String; Comparison_Method : constant String; -- Should return -1, 0 or 1 depending on whether AB Equal_Method : constant String; -- Should return a boolean, testing for equality. -- Note that in python, at least, definining this will not automatically -- define the inequality, so it might be better to use Comparison_Method -- instead. procedure Destroy (Repo : in out Scripts_Repository); -- Free all memory associated with the repository procedure Register_Standard_Classes (Repo : access Scripts_Repository_Record'Class; Console_Class_Name : String; Logger_Class_Name : String := ""); -- Register predefined classes that are needed for support of consoles. -- If Logger_Class_Name, this also creates a new class to interface with -- the GNATCOLL.Traces mechanism. This is especially useful if your own -- application is also uses the same mechanism. function Get_Console_Class (Repo : access Scripts_Repository_Record'Class) return Class_Type; -- Return the class to use for Console input/output. -- This is only initialized when Register_Standard_Classes is called procedure Register_Command (Repo : access Scripts_Repository_Record'Class; Command : String; Params : Param_Array; Handler : Module_Command_Function; Class : Class_Type := No_Class; Static_Method : Boolean := False; Language : String := ""); procedure Register_Command (Repo : access Scripts_Repository_Record'Class; Command : String; Minimum_Args : Natural := 0; Maximum_Args : Natural := 0; Handler : Module_Command_Function; Class : Class_Type := No_Class; Static_Method : Boolean := False; Language : String := ""); -- Add a new function to all currently registered script languages. -- -- The first version is recommended. By contrast, you will need to call -- Name_Parameters yourself in the Handler for the second version. -- -- Params should not be freed by the caller. -- -- If Class is not No_Class, then this procedure creates a method for this -- class, for the languages for which this is appropriate. An extra -- parameter is automatically added to the command, in first position, -- which is the instance to which this applies. In some shells, the user -- must provide this himself (GPS shell for instance), since the language -- is not object oriented. This first parameter must not be counted in -- Minimum_args and Maximum_Args -- Otherwise, it creates a global function in the script language. -- -- If Static_Method is True, then Class must be different from No_Class. -- The resulting method doesn't take an instance as its first -- parameter. Instead, it behaves like a global function, except it is in a -- specific namespace corresponding to the class name. -- This is similar to C++'s static methods. -- -- If Command is Constructor_Method, then the function is setup as the -- constructor for Class, which must not be No_Class. For compatibility -- with the greater number of languages, only one such constructor can be -- defined per class. -- A constructor receives an already built instance of the object, and -- should initialize the fields. Its first parameter is the instance, the -- second, third,... are the parameters passed to the constructor. -- The constructor shouldn't return any value through Set_Return_Value. -- -- If Command is Addition_Method, this is a function that should take one -- argument in addition to the instance, and return a new instance. This -- handles statements like "inst + 1", although the second argument can be -- of any type (you can even handle multiple types in your implementation) -- -- Subscription_Method is similar to Addition_Method. -- -- Comparison_Method is a function that takes a second parameter, and -- returns -1 if the first is less than the second, 0 if they are equal, -- and 1 if the first is greater than the second. -- -- Destructor_Method is called just before the instance is destroyed -- -- Description of the new command must be put in the file -- shell_commands.xml, which is read dynamically when generating the -- documentation. -- -- If the command has some graphical output (dialog,...), it must run in -- a separate main loop (Gtk.Main.Gtk_Main or modal dialogs). -- -- Language can be specified to restrict the command to a specific -- scripting language. procedure Override_Command (Repo : access Scripts_Repository_Record'Class; Command : String; Handler : Module_Command_Function; Class : Class_Type := No_Class); -- You can change behavior of already registered function providing -- new Handler for it. See Register_Command for parameter descriptions. procedure Register_Property (Repo : access Scripts_Repository_Record'Class; Name : String; Class : Class_Type; Setter : Module_Command_Function := null; Getter : Module_Command_Function := null); -- Defines a property which is accessed through methods. -- If Setter is null, the property is read-only. -- If Getter is null, the property is write-only. -- -- A property is very similar to two functions, but the syntax might be -- different. For instance: -- - In python: -- c = Console() # Create instance -- c.msg = "message" # Calls the setter -- print c.msg # Calls the getter -- A function would have been: -- c.set_msg("message") -- print c.get_msg() -- -- - In shell: -- Console # create instance -- @msg %1 "message" # Calls the setter -- @msg %2 # Calls the getter -- A function would have been: -- Console.set_msg %1 "message" -- Console.get_msg %2 procedure Block_Commands (Repo : access Scripts_Repository_Record'Class; Block : Boolean); -- Block all execution of shell commands if Block is true procedure Register_Scripting_Language (Repo : access Scripts_Repository_Record'Class; Script : access Scripting_Language_Record'Class); -- Register a new scripting language in the kernel. -- Scripting languages are freed when the kernel is destroyed function Lookup_Scripting_Language (Repo : access Scripts_Repository_Record'Class; Name : String) return Scripting_Language; -- Lookup one of the registered languages by name type Scripting_Language_Array is array (Natural range <>) of Scripting_Language; function Get_Scripting_Languages (Repo : access Scripts_Repository_Record'Class) return Scripting_Language_Array; -- Return the list of all registered languages No_Args : constant GNAT.OS_Lib.Argument_List := (1 .. 0 => null); private Constructor_Method : constant String := "<@constructor@>"; Addition_Method : constant String := "+"; Substraction_Method : constant String := "-"; Comparison_Method : constant String := "<=>"; Destructor_Method : constant String := "<@destructor@>"; Equal_Method : constant String := "=="; type Virtual_Console_Record is abstract tagged record Hide_Output : Boolean := False; Refresh_Timeout : Ada.Calendar.Time := Ada.Calendar.Clock; end record; type Class_Type is record Qualified_Name : GNAT.Strings.String_Access; -- Fully qualified name for the class (module.module.name) Exists : Boolean := True; -- Set to False when the class is found using Lookup_Class. This is for -- instance the case for builtin classes. end record; type Module_Type is record Name : Ada.Strings.Unbounded.Unbounded_String; end record; Default_Module : constant Module_Type := (Name => Ada.Strings.Unbounded.To_Unbounded_String ("@")); type User_Data; type User_Data_List is access User_Data; type User_Data (Length : Natural) is record Next : User_Data_List; Name : String (1 .. Length); Prop : Instance_Property; end record; procedure Free_User_Data_List (Data : in out User_Data_List); -- Free the whole contents of the list type Param_Descr is record Name : GNAT.Strings.String_Access; Optional : Boolean := False; end record; No_Params : constant Param_Array := (1 .. 0 => <>); type Class_Instance_Record is abstract new Refcounted with record Script : access Scripting_Language_Record'Class; -- not owned end record; function Get_User_Data (Self : not null access Class_Instance_Record) return access User_Data_List; -- Return the list of user data stored for this instance. Depending on the -- scripting language, this list might be stored in various places (as a -- python attribute, directly in Ada for the shell,...) This list is shared -- amonst the scripting languages. package CI_Pointers is new Smart_Pointers (Class_Instance_Record); type Class_Instance is record Ref : CI_Pointers.Ref; end record; -- A Class_Instance cannot be a visibly tagged type if declared in this -- package, since otherwise we have operations dispatching on multiple -- types. No_Class_Instance : constant Class_Instance := (Ref => CI_Pointers.Null_Ref); No_Class : constant Class_Type := (Qualified_Name => null, Exists => False); Any_Class : constant Class_Type := (Qualified_Name => new String'("@#!-"), Exists => False); type Subprogram_Record is abstract tagged null record; type Callback_Data is abstract tagged null record; type Scripting_Language_Record is abstract tagged record Console : Virtual_Console; end record; type Instance_Array is array (Natural range <>) of Class_Instance; type Instance_Array_Access is access Instance_Array; type Instance_List is record List : Instance_Array_Access; -- instances are stored in no particular order. As soon as a -- No_Class_Instance is found, there will be no further instances -- in the array. end record; Null_Instance_List : constant Instance_List := (List => null); type Inst_Cursor is record Index : Natural := Natural'Last; end record; type Callback_Data_Array is array (Natural range <>) of Callback_Data_Access; type Callback_Data_List is access Callback_Data_Array; type Scripting_Language_List is access Scripting_Language_Array; package Classes_Hash is new Ada.Containers.Indefinite_Hashed_Maps (Key_Type => String, Element_Type => Class_Type, Hash => Ada.Strings.Hash, Equivalent_Keys => "="); type Scripts_Repository_Record is tagged record Scripting_Languages : Scripting_Language_List := new Scripting_Language_Array'(1 .. 0 => null); Commands : Command_Descr_Access; Properties : Property_Descr_Access; Classes : Classes_Hash.Map; Console_Class : Class_Type := No_Class; Logger_Class : Class_Type := No_Class; end record; end GNATCOLL.Scripts; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-storage_pools-alignment.adb000066400000000000000000000125511425465243200262160ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with System.Storage_Pools; use System, System.Storage_Pools; with System.Storage_Elements; use System.Storage_Elements; with Ada.Unchecked_Deallocation; with Ada.Unchecked_Conversion; package body GNATCOLL.Storage_Pools.Alignment is type Storage_Element_Access is access Storage_Element; function Convert is new Ada.Unchecked_Conversion (System.Address, Storage_Element_Access); -------------- -- Allocate -- -------------- procedure Allocate (Pool : in out Unbounded_No_Reclaim_Align_Pool; Address : out System.Address; Storage_Size : Storage_Count; Alignment : Storage_Count) is pragma Unreferenced (Alignment); -- We need to allocate more memory than actually requested, so that -- even if "new" returns an incorrect alignment, we have enough spare -- memory to return the correct alignment. We also always need a buffer -- of at least two Storage_Element to store the offset between the -- address from "new" and the one returned by the use, so that -- Deallocates works appropriately. -- Worst case is when "new" returned a correctly aligned chunk, and we -- then need to offset by Pool.Alignment bytes. Bytes_For_Offset : constant := 3; Align : constant Storage_Count := Pool.Alignment; Size : constant Storage_Offset := Storage_Size + Align + Bytes_For_Offset - 1; subtype Local_Storage_Array is Storage_Array (1 .. Size); type Ptr is access Local_Storage_Array; Allocated : constant Ptr := new Local_Storage_Array; Offset : constant Storage_Count := Align - Allocated.all'Address mod Align; begin Allocated (Offset - 2) := Storage_Element (Offset / 65_536); Allocated (Offset - 1) := Storage_Element ((Offset mod 65_536) / 256); Allocated (Offset) := Storage_Element (Offset mod 256); Address := Allocated.all'Address + Offset; end Allocate; ---------------- -- Deallocate -- ---------------- procedure Deallocate (Pool : in out Unbounded_No_Reclaim_Align_Pool; Address : System.Address; Storage_Size : Storage_Count; Alignment : Storage_Count) is pragma Unreferenced (Alignment); Size : constant Storage_Offset := Storage_Size + Pool.Alignment; subtype Local_Storage_Array is Storage_Array (1 .. Size); type Ptr is access Local_Storage_Array; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Local_Storage_Array, Ptr); function Convert is new Ada.Unchecked_Conversion (System.Address, Ptr); Offset_High2 : constant Storage_Element := Convert (Address - 3).all; Offset_High : constant Storage_Element := Convert (Address - 2).all; Offset_Low : constant Storage_Element := Convert (Address - 1).all; Offset : constant Storage_Count := Storage_Count (Offset_High2) * 65_536 + Storage_Count (Offset_High) * 256 + Storage_Count (Offset_Low); Real_Address : constant System.Address := Address - Offset; Var : Ptr := Convert (Real_Address); begin Unchecked_Free (Var); end Deallocate; ------------------ -- Storage_Size -- ------------------ function Storage_Size (Pool : Unbounded_No_Reclaim_Align_Pool) return Storage_Count is pragma Unreferenced (Pool); begin -- Intuitively, should return System.Memory_Size. But on Sun/Alsys, -- System.Memory_Size > System.Max_Int, which means all you can do with -- it is raise CONSTRAINT_ERROR... return Storage_Count'Last; end Storage_Size; end GNATCOLL.Storage_Pools.Alignment; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-storage_pools-alignment.ads000066400000000000000000000064651425465243200262460ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides a storage pool that allows you to select any -- possible alignment for your data. -- The alignment itself is chosen through discriminant of the pool -- itself. -- -- My_Pool : Unbounded_No_Reclaim_Align_Pool (Alignment => 64); -- type My_Data is ...; -- for My_Data'Storage_Pool use My_Pool; with System.Storage_Pools; with System.Storage_Elements; package GNATCOLL.Storage_Pools.Alignment is pragma Elaborate_Body; -- Needed to ensure that library routines can execute allocators type Unbounded_No_Reclaim_Align_Pool (Alignment : System.Storage_Elements.Storage_Count) is new System.Storage_Pools.Root_Storage_Pool with private; -- A storage pool that uses malloc() internally, but always returns -- addresses aligned on Alignment bytes. private type Unbounded_No_Reclaim_Align_Pool (Alignment : System.Storage_Elements.Storage_Count) is new System.Storage_Pools.Root_Storage_Pool with null record; function Storage_Size (Pool : Unbounded_No_Reclaim_Align_Pool) return System.Storage_Elements.Storage_Count; procedure Allocate (Pool : in out Unbounded_No_Reclaim_Align_Pool; Address : out System.Address; Storage_Size : System.Storage_Elements.Storage_Count; Alignment : System.Storage_Elements.Storage_Count); procedure Deallocate (Pool : in out Unbounded_No_Reclaim_Align_Pool; Address : System.Address; Storage_Size : System.Storage_Elements.Storage_Count; Alignment : System.Storage_Elements.Storage_Count); end GNATCOLL.Storage_Pools.Alignment; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-storage_pools-headers.adb000066400000000000000000000135561425465243200256610ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2015-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with System.Memory; use System, System.Memory; package body GNATCOLL.Storage_Pools.Headers is Default_Align : constant Storage_Count := Standard'System_Allocator_Alignment; ------------------ -- Header_Pools -- ------------------ package body Header_Pools is type Header is record Extra : Extra_Header; end record; type Extra_Header_Access is access all Extra_Header; Extra_Bytes : constant Storage_Offset := (Header'Max_Size_In_Storage_Elements - Header'Object_Size / Storage_Unit); -- If the header is a controlled type, we need to allocate extra size -- for its Previous and Next pointers. This constant computes how -- much such extra size is needed. Header_Size_Bytes : constant Storage_Count := Header'Size / Storage_Unit; Extra_Allocation_Bytes : constant Storage_Count := ((Header_Size_Bytes + Extra_Bytes + Default_Align - 1) / Default_Align) * Default_Align; -- Allocate a multiple of Default_Align bytes, so that the -- alignment of the Element_Type is suitable. function Convert is new Ada.Unchecked_Conversion (System.Address, Extra_Header_Access); function Address_Header_Of (Addr : System.Address) return System.Address is (Addr - Extra_Allocation_Bytes); -- Compute the address of the header. -- Do not call with a null pointer. -------------- -- Allocate -- -------------- overriding procedure Allocate (Self : in out Header_Pool; Addr : out System.Address; Size : System.Storage_Elements.Storage_Count; Alignment : System.Storage_Elements.Storage_Count) is -- The compiler requests a size that include the object size -- plus any extra header like bounds or next/previous for -- controlled types. This size also includes a padding to -- ensure that the element will be properly aligned. -- The computation is done in s-stposu.adb, in -- Header_Size_With_Padding. pragma Unreferenced (Self, Alignment); Aligned_Size : constant Storage_Count := -- bytes Size + Extra_Allocation_Bytes; Allocated : constant System.Address := Alloc (size_t (Aligned_Size)); begin Addr := Allocated + Extra_Allocation_Bytes; end Allocate; ---------------- -- Deallocate -- ---------------- overriding procedure Deallocate (Self : in out Header_Pool; Addr : System.Address; Size : System.Storage_Elements.Storage_Count; Alignment : System.Storage_Elements.Storage_Count) is pragma Unreferenced (Self, Alignment, Size); Header : constant System.Address := Address_Header_Of (Addr); begin System.Memory.Free (Header); end Deallocate; ----------- -- Typed -- ----------- package body Typed is function Header_Of (Element : Element_Access) return access Extra_Header is F : constant Integer := Element.all'Finalization_Size; -- If the element_type is a controlled type, this constant will -- be the number of extra bytes requested by the compiler in -- calls to Allocate and Deallocate (see the memory layout -- description in the specs). -- -- These extra bytes are automatically added and substracted by -- the compiler when calling Deallocate, but not when calling -- Header_Of so we need to take them into account when looking -- for the our own header. H : constant access Extra_Header := (if Element = null then null else Convert (Address_Header_Of (Element.all'Address - Storage_Offset (F) - Element_Type'Descriptor_Size))); begin return H; end Header_Of; end Typed; end Header_Pools; end GNATCOLL.Storage_Pools.Headers; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-storage_pools-headers.ads000066400000000000000000000152201425465243200256700ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2015-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides storage pools that allocate enough memory for their -- element and an extra header. -- This header can be used to store extra information. For instance, it has -- been used to store a reference counter, or pointers to the next element -- in a container. -- The goal is to reduce the number of memory allocations: instead of doing -- one allocation for the element, and a second one for the counter, we can -- do a single allocation, which is much faster. -- -- Usage example: -- type Header is record -- Refcount : Natural; -- end record; -- package Pools is new Header_Pools (Header); -- package String_Pools is new Pools.Typed (String); -- package Integer_Pools is new Pools.Typed (Integer); -- -- Str : String_Pools.Element_Access; -- Str := new String'("foo"); -- uses the storage pool -- -- String_Pools.Header_Of (Str).Refcount := 1; -- String_Pools.Free (Str); -- reclaim memory pragma Ada_2012; with Ada.Unchecked_Conversion; with Ada.Unchecked_Deallocation; with System.Storage_Pools; use System.Storage_Pools; with System.Storage_Elements; use System.Storage_Elements; package GNATCOLL.Storage_Pools.Headers is ------------------ -- Header_Pools -- ------------------ -- The actual memory layout that we need to allocate is described below. In -- all cases, we had a "Pad" (padding) which is used to obey the requested -- alignment for the object. -- Currently, this pool doesn't support alignment clauses (and the generic -- Typed package below doesn't declare any), so the padding is always 0 -- bytes. -- * For a scalar, record, tagged record or constrained array: -- +--------+------+-----------------------+ -- | Header | Pad | Element | -- +--------+------+-----------------------+ -- * For an unconstrained array, whether we use a standard access -- type or a flattened access type (a representation clause gives -- it a size of a standard pointer) -- -- +--------+------+-----------------------+ -- | Header | Pad | First+Last+Element | -- +--------+------+-----------------------+ -- First and Last are the bounds of the array. -- Our pool should return the address of First, and the compiler -- automatically deduces the address of Element to return to the -- user code. -- * For a controlled type: -- -- 1 2 3 -- +--------+------+-----------------------+ -- | Header | Pad | Previous+Next+Element | -- +--------+------+-----------------------+ -- Previous and Next are pointers to other controlled types. -- In code like: -- A := new ...; -- the header pool allocates memory at 1 via malloc, but -- returns 2 to the compiler -- then the compiler stores 3 in A. -- Conversely, when calling Free, the compiler converts A back to -- 2, and our pool converts this back to 1 before calling free() -- The trouble is that when we call "Header_Of" on A, we receive -- the address 3, so it is harder to find 1. -- -- See System.Storage_Pools.Subpools.Allocate_Any_Controlled. generic type Extra_Header is private; -- The header to allocate for each element. The pool will make sure -- to pad its size so that the element's data is properly aligned. package Header_Pools is type Header_Pool is new Root_Storage_Pool with null record; overriding procedure Allocate (Self : in out Header_Pool; Addr : out System.Address; Size : Storage_Count; Alignment : Storage_Count); overriding procedure Deallocate (Self : in out Header_Pool; Addr : System.Address; Size : Storage_Count; Alignment : Storage_Count); overriding function Storage_Size (Self : Header_Pool) return Storage_Count is (Storage_Count'Last) with Inline; Pool : Header_Pool; ----------- -- Typed -- ----------- generic type Element_Type (<>) is limited private; package Typed is type Element_Access is access all Element_Type; for Element_Access'Size use Standard'Address_Size; for Element_Access'Storage_Pool use Pool; -- Force array bounds to be stored before the array's data, rather -- than as a separate dope vector. function Header_Of (Element : Element_Access) return access Extra_Header with Inline; -- Points to the beginning of the header for Element. -- Returns null if Element is null procedure Free is new Ada.Unchecked_Deallocation (Element_Type, Element_Access); -- Free the memory used by Element end Typed; end Header_Pools; end GNATCOLL.Storage_Pools.Headers; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-storage_pools.ads000066400000000000000000000037701425465243200242660ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- The children packages provide various implementation of storage -- pools, that have been found useful over time. -- You might also be interested in GNAT.Debug_Pools, which is provided in -- the GNAT runtime itself. package GNATCOLL.Storage_Pools is pragma Pure; end GNATCOLL.Storage_Pools; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-strings.ads000066400000000000000000000041761425465243200231000ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Optimized strings, with local buffer for performance and optional -- copy-on-write. -- See details in gnatcoll-strings_impl.ads with GNATCOLL.Strings_Impl; with Ada.Characters.Handling; use Ada.Characters.Handling; package GNATCOLL.Strings is new GNATCOLL.Strings_Impl.Strings (SSize => GNATCOLL.Strings_Impl.Optimal_String_Size, Character_Type => Character, Character_String => String); alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-strings_impl.adb000066400000000000000000002201511425465243200240710ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Strings; use Ada.Strings; with Ada.Unchecked_Conversion; with GNATCOLL.Atomic; use GNATCOLL.Atomic; with GNATCOLL.Refcount; with System.Memory; use System.Memory; pragma Warnings (Off, ".*is an internal GNAT unit"); with System.String_Hash; pragma Warnings (On, ".*is an internal GNAT unit"); package body GNATCOLL.Strings_Impl is Page_Size : constant := 4096; -- Memory page size -------------------- -- Default_Growth -- -------------------- function Default_Growth (Current, Min_Size : String_Size) return String_Size is -- Compute minimum new size. -- 1.5 is often considered the best strategy, between efficiency -- and memory usage. New_Size : constant String_Size := String_Size'Max (Current * 3 / 2, Min_Size); begin if New_Size > Page_Size then -- Round up to the nearest page size, since this is what -- the system allocates anyway. This will always lead an even -- number. return (New_Size / Page_Size + 1) * Page_Size; else -- Must be an even number return New_Size + (New_Size and 1); end if; end Default_Growth; ------------- -- Strings -- ------------- package body Strings is function Convert is new Ada.Unchecked_Conversion (System.Address, Char_Array); function Convert is new Ada.Unchecked_Conversion (System.Address, Big_String_Data_Access); function Convert is new Ada.Unchecked_Conversion (Big_String_Data_Access, System.Address); Unshareable : constant GNATCOLL.Atomic.Atomic_Counter := GNATCOLL.Atomic.Atomic_Counter'Last; -- This is used as the refcount for strings that must not be -- shared. In particular, this is the case when we have taken -- a variable reference to a string, to fix the following case: -- R := S (2); -- a variable indexing -- S2 := S; -- share the buffer ??? WRONG -- R := 'A'; -- also alters S2 -- -- See http://www.gotw.ca/gotw/044.htm for a C++ discussion on why -- we need to make a string unshareable. Bytes_Per_Char : constant size_t := Char_Type'Size / Character'Size; -- Number of bytes for each character in the string. Extra_Header_Size : constant System.Memory.size_t := (if Copy_On_Write then System.Memory.size_t (GNATCOLL.Atomic.Atomic_Counter'Size / 8) else 0); -- Extra bytes needed for Big_String_Data in addition to the -- byte data stored in Unconstrained_String. procedure Store_Capacity (Self : in out XString; Capacity : String_Size) with Inline; function Get_Capacity (Self : XString) return String_Size is (2 * Self.Data.Big.Half_Capacity); -- Returns the current capacity of a large string procedure Store_Size (Self : in out XString; Size : Natural) with Inline; -- Store the size of Self. procedure Clone (Self : in out XString; Data : Big_String_Data_Access) with Pre => Self.Data.Small.Is_Big, Inline; -- Set the big string data, copying from Data. -- We copy the data from the parameter and not from Self.Data.Big.Data -- because the latter might already have been set to null at that -- point. -- New memory is allocated. procedure Make_Writable_Thread_Safe (Self : in out XString) with Inline; procedure Make_Writable_Thread_Unsafe (Self : in out XString) with Inline; Make_Writable : constant not null access procedure (Self : in out XString) := (if GNATCOLL.Refcount.Application_Uses_Tasks then Make_Writable_Thread_Safe'Access else Make_Writable_Thread_Unsafe'Access); -- Make sure we can modify Self (not a shared string) -- Two versions are provided: the Unsafe version is faster, but will -- fail when a string is read from a thread and written in another one, -- as in the following scenario: -- thread 1 | thread 2 -- S.Set ("some long long long str"); | -- Append (S, "some long long str"); | -- -- stops after testing refcount | -- | S2 := S; -- | -- buffer is now shared -- | Put_Line (S2.To_String); -- -- modifies shared buffer | -- | Put_Line (S2.To_String); -- | -- different output procedure Convert_To_Big_String (Self : in out XString; Size : String_Size) with Inline, Pre => not Self.Data.Small.Is_Big; -- Convert to a big string, by copying the small string data. -- We never convert back to a small string afterwards, to benefit from -- the memory we already allocated. -- This procedure does not copy the actual string, only allocates -- memory. -- Sets the size of the string -------------------- -- Store_Capacity -- -------------------- procedure Store_Capacity (Self : in out XString; Capacity : String_Size) is begin Self.Data.Big.Half_Capacity := Capacity / 2; end Store_Capacity; ---------------- -- Store_Size -- ---------------- procedure Store_Size (Self : in out XString; Size : Natural) is begin if Self.Data.Big.Is_Big then Self.Data.Big.Size := String_Size (Size); else Self.Data.Small.Size := SSize (Size); end if; end Store_Size; --------------------------------- -- Make_Writable_Thread_Unsafe -- --------------------------------- procedure Make_Writable_Thread_Unsafe (Self : in out XString) is begin if not Copy_On_Write or else not Self.Data.Small.Is_Big or else Self.Data.Big.Data.Refcount = Unshareable then null; -- nothing to do elsif Self.Data.Big.Data.Refcount = 1 then null; else Decrement (Self.Data.Big.Data.Refcount); Clone (Self, Self.Data.Big.Data); end if; end Make_Writable_Thread_Unsafe; ------------------------------- -- Make_Writable_Thread_Safe -- ------------------------------- procedure Make_Writable_Thread_Safe (Self : in out XString) is Tmp : Big_String_Data_Access; begin if not Copy_On_Write or else not Self.Data.Small.Is_Big or else Self.Data.Big.Data.Refcount = Unshareable then null; -- nothing to do else -- ??? We do not need an atomic sync_bool_compare_and_swap, -- since a string is not shared among threads (although the -- internal storage might be). Tmp := Self.Data.Big.Data; Self.Data.Big.Data := null; -- Now we know that Self.Data.Big.Data is null, and Tmp is -- set to the previous value. We still own a reference to -- that previous value, so it won't be freed by another -- thread. -- If another thread tries to do an assignment now, it will -- end up with a null buffer. But that is only possible if -- the other thread is accessing a shared string, which is -- not supported (a thread reading the string while we are -- modifying it). if Decrement (Tmp.Refcount) then -- We were the only user, so it is safe to keep the string Unsafe_Increment (Tmp.Refcount); Self.Data.Big.Data := Tmp; else -- Other threads were still sharing the data. We have to -- make a copy Clone (Self, Tmp); end if; end if; end Make_Writable_Thread_Safe; ----------- -- Clone -- ----------- procedure Clone (Self : in out XString; Data : Big_String_Data_Access) is Size : constant Integer := Integer (Self.Data.Big.Size); First : constant Natural := Natural (Self.Data.Big.First); Cap : constant String_Size := Growth_Strategy (0, Min_Size => Self.Data.Big.Size); Result : constant Big_String_Data_Access := Convert (System.Memory.Alloc (size_t (Cap) * Bytes_Per_Char + Extra_Header_Size)); begin if Copy_On_Write then Result.Refcount := 1; Result.Bytes2 (1 .. Size) := Data.Bytes2 (First .. First - 1 + Size); else Result.Bytes1 (1 .. Size) := Data.Bytes1 (First .. First - 1 + Size); end if; Self.Data.Big.First := 1; Store_Capacity (Self, Cap); Self.Data.Big.Data := Result; end Clone; ------------ -- Adjust -- ------------ overriding procedure Adjust (Self : in out XString) is begin if not Self.Data.Small.Is_Big then null; -- nothing to do elsif Copy_On_Write and then Self.Data.Big.Data.Refcount /= Unshareable then Increment (Self.Data.Big.Data.Refcount); else -- We do not need atomic operations here. We are still in -- the thread that did the assignment, and there is no -- shared data in this mode. Clone (Self, Self.Data.Big.Data); end if; end Adjust; -------------- -- Finalize -- -------------- overriding procedure Finalize (Self : in out XString) is Tmp : Big_String_Data_Access; begin -- nothing to do for small strings if Self.Data.Small.Is_Big then Tmp := Self.Data.Big.Data; if Tmp /= null then Self.Data.Big.Data := null; if not Copy_On_Write or else Tmp.Refcount = Unshareable or else Decrement (Tmp.Refcount) then System.Memory.Free (Convert (Tmp)); end if; end if; end if; end Finalize; ----------- -- Clear -- ----------- procedure Clear (Self : in out XString) is begin Finalize (Self); Self.Data.Small.Is_Big := False; Self.Data.Small.Size := 0; end Clear; --------------------------- -- Convert_To_Big_String -- --------------------------- procedure Convert_To_Big_String (Self : in out XString; Size : String_Size) is New_Size : constant String_Size := Growth_Strategy (0, Size); begin Store_Capacity (Self, New_Size); Self.Data.Big.Is_Big := True; Self.Data.Big.Data := Convert (System.Memory.Alloc (size_t (New_Size) * Bytes_Per_Char + Extra_Header_Size)); Self.Data.Big.Size := Size; Self.Data.Big.First := 1; if Copy_On_Write then Self.Data.Big.Data.Refcount := 1; end if; end Convert_To_Big_String; ------------- -- Reserve -- ------------- procedure Reserve (Self : in out XString; Capacity : String_Size) is Current_Cap : String_Size; First : Natural; New_Size : String_Size; Old_Size : Natural; begin if Self.Data.Small.Is_Big then -- We are about to modify the string if Copy_On_Write then Make_Writable (Self); end if; Current_Cap := Get_Capacity (Self); First := Self.Data.Big.First; -- Do we have enough space at the end already (i.e -- the capacity we really need extends from First, not -- from character 1). if Current_Cap >= String_Size (First) - 1 + Capacity then -- nothing to do, we have enough space null; else -- We'll have to make space. The simplest is first to move all -- characters back to First=1, which might free enough space at -- the end of the string. if First > 1 then Old_Size := Natural (Self.Data.Big.Size); if Copy_On_Write then Self.Data.Big.Data.Bytes2 (1 .. Old_Size) := Self.Data.Big.Data.Bytes2 (First .. First - 1 + Old_Size); else Self.Data.Big.Data.Bytes1 (1 .. Old_Size) := Self.Data.Big.Data.Bytes1 (First .. First - 1 + Old_Size); end if; Self.Data.Big.First := 1; end if; -- Do we have enough space now ? if Current_Cap < Capacity then New_Size := Growth_Strategy (Current_Cap, Capacity); Store_Capacity (Self, New_Size); Self.Data.Big.Data := Convert (System.Memory.Realloc (Convert (Self.Data.Big.Data), size_t (New_Size) * Bytes_Per_Char + Extra_Header_Size)); end if; end if; else -- If we'll need a large string if Capacity > Max_Small_Length then declare Current : constant Natural := Natural (Self.Data.Small.Size); Old : constant Char_String := Self.Data.Small.Data (1 .. Current); begin Convert_To_Big_String (Self, Capacity); pragma Assert (Self.Data.Big.First = 1); Self.Data.Big.Size := String_Size (Current); if Copy_On_Write then Self.Data.Big.Data.Bytes2 (1 .. Current) := Convert (Old'Address) (1 .. Current); else Self.Data.Big.Data.Bytes1 (1 .. Current) := Convert (Old'Address) (1 .. Current); end if; end; end if; end if; end Reserve; ------------ -- Shrink -- ------------ procedure Shrink (Self : in out XString) is New_Size : String_Size; begin if not Self.Data.Small.Is_Big then -- Nothing to do null; else -- ??? Should we try to revert to a small string Make_Writable (Self); New_Size := Growth_Strategy (0, Self.Data.Big.Size); Store_Capacity (Self, New_Size); Self.Data.Big.Data := Convert (System.Memory.Realloc (Convert (Self.Data.Big.Data), size_t (New_Size) * Bytes_Per_Char + Extra_Header_Size)); end if; end Shrink; --------- -- Set -- --------- procedure Set (Self : in out XString; Str : Char_String) is begin Store_Size (Self, 0); Self.Reserve (Capacity => Str'Length); if not Self.Data.Small.Is_Big then Self.Data.Small.Size := Str'Length; Self.Data.Small.Data (1 .. Str'Length) := Str; else Self.Data.Big.Size := String_Size (Str'Length); Self.Data.Big.First := 1; if Copy_On_Write then Self.Data.Big.Data.Bytes2 (1 .. Str'Length) := Convert (Str'Address) (1 .. Str'Length); else Self.Data.Big.Data.Bytes1 (1 .. Str'Length) := Convert (Str'Address) (1 .. Str'Length); end if; end if; end Set; ------------ -- Append -- ------------ procedure Append (Self : in out XString; Str : Char_String) is Current : constant Natural := Self.Length; New_Size : constant Natural := Current + Str'Length; F : Natural; begin if Str'Length = 0 then return; end if; -- Make sure we have enough space, possibly by moving -- characters back to position 1, or by converting to -- a big string, or resizing the current buffer. Self.Reserve (Capacity => String_Size (New_Size)); if not Self.Data.Small.Is_Big then Self.Data.Small.Data (Current + 1 .. New_Size) := Str; Self.Data.Small.Size := SSize (New_Size); else F := Natural (Self.Data.Big.First) + Current; Self.Data.Big.Size := String_Size (New_Size); if Copy_On_Write then Self.Data.Big.Data.Bytes2 (F .. F - 1 + Str'Length) := Convert (Str'Address) (1 .. Str'Length); else Self.Data.Big.Data.Bytes1 (F .. F - 1 + Str'Length) := Convert (Str'Address) (1 .. Str'Length); end if; end if; end Append; ------------ -- Append -- ------------ procedure Append (Self : in out XString; Char : Char_Type) is Current : constant Natural := Self.Length; F : Natural; begin Self.Reserve (Capacity => String_Size (Current + 1)); if not Self.Data.Small.Is_Big then Self.Data.Small.Data (Current + 1) := Char; Self.Data.Small.Size := SSize (Current + 1); else F := Natural (Self.Data.Big.First) + Current; Self.Data.Big.Size := String_Size (Current + 1); if Copy_On_Write then Self.Data.Big.Data.Bytes2 (F) := Char; else Self.Data.Big.Data.Bytes1 (F) := Char; end if; end if; end Append; ------------ -- Append -- ------------ procedure Append (Self : in out XString; Str : XString) is B : Char_Array; L : Natural; begin if Self.Length = 0 then -- Share the string instead of malloc+copy Self := Str; else Get_String (Str, B, L); if L /= 0 then Self.Append (Char_String (B (1 .. L))); end if; end if; end Append; --------- -- "*" -- --------- function "*" (Count : Natural; Right : Char_Type) return XString is Result : XString; begin Result.Reserve (Capacity => String_Size (Count)); for C in 1 .. Count loop Result.Append (Right); end loop; return Result; end "*"; --------- -- "*" -- --------- function "*" (Count : Natural; Right : Char_String) return XString is Result : XString; begin Result.Reserve (Capacity => String_Size (Count * Right'Length)); for C in 1 .. Count loop Result.Append (Right); end loop; return Result; end "*"; --------- -- "*" -- --------- function "*" (Count : Natural; Right : XString) return XString is Result : XString; begin Result.Reserve (Capacity => String_Size (Count * Right.Length)); for C in 1 .. Count loop Result.Append (Right); end loop; return Result; end "*"; ------------ -- Length -- ------------ function Length (Self : XString) return Natural is begin if not Self.Data.Small.Is_Big then return Natural (Self.Data.Small.Size); else return Natural (Self.Data.Big.Size); end if; end Length; ---------------- -- Get_String -- ---------------- procedure Get_String (Self : XString; S : out Char_Array; L : out Natural) is begin if not Self.Data.Small.Is_Big then L := Natural (Self.Data.Small.Size); S := Convert (Self.Data.Small.Data'Address); -- For a big string, we need to take into account First. Yet, -- everything should behave for the user as if the first character -- was always at index 1. elsif Copy_On_Write then L := Natural (Self.Data.Big.Size); S := Convert (Self.Data.Big.Data.Bytes2 (Natural (Self.Data.Big.First))'Address); else L := Natural (Self.Data.Big.Size); S := Convert (Self.Data.Big.Data.Bytes1 (Natural (Self.Data.Big.First))'Address); end if; end Get_String; ------------------- -- Access_String -- ------------------- procedure Access_String (Self : XString; Process : not null access procedure (S : Char_String)) is Copy : XString; To_Decref : Big_String_Data_Access; S : Char_Array; L : Natural; begin -- Self is passed by reference, so its refcount might still be 1. -- As a result, if Process would access the original variable and -- for instance Append to it, we would end up modifying the internal -- value of Self, and thus our S variable might end up referencing -- freed memory, same for Process. if not Self.Data.Small.Is_Big or else not Copy_On_Write then -- We must make a copy, since the internal data might change Copy := Self; Get_String (Copy, S, L); Process (Char_String (S (S'First .. L))); else if Self.Data.Big.Data.Refcount /= Unshareable then -- If anyone tries to modify the string, it will make a copy. -- But we might not have to make the copy at all. To_Decref := Self.Data.Big.Data; Increment (To_Decref.Refcount); end if; Get_String (Self, S, L); Process (Char_String (S (S'First .. L))); if To_Decref /= null then -- It is possible that we are now holding on to the last ref to -- the string, if Process has reset it to null for instance. if Decrement (To_Decref.Refcount) then System.Memory.Free (Convert (To_Decref)); end if; end if; end if; end Access_String; ---------------- -- To_XString -- ---------------- function To_XString (Str : Char_String) return XString is R : XString; begin R.Set (Str); return R; end To_XString; --------------- -- To_String -- --------------- function To_String (Self : XString) return Char_String is B : Char_Array; L : Natural; begin Get_String (Self, B, L); return Char_String (B (1 .. L)); end To_String; --------- -- "=" -- --------- function "=" (Left : XString; Right : Char_String) return Boolean is B : Char_Array; L : Natural; begin Get_String (Left, B, L); return Char_String (B (1 .. L)) = Right; end "="; --------- -- "=" -- --------- function "=" (Left, Right : XString) return Boolean is B1, B2 : Char_Array; L1, L2 : Natural; begin Get_String (Left, B1, L1); Get_String (Right, B2, L2); -- ??? Should we check the pointers and "First" return L1 = L2 and then B1 (1 .. L1) = B2 (1 .. L2); end "="; --------- -- "<" -- --------- function "<" (Left : XString; Right : Char_String) return Boolean is B : Char_Array; L : Natural; begin Get_String (Left, B, L); return Char_String (B (1 .. L)) < Right; end "<"; --------- -- "<" -- --------- function "<" (Left : Char_String; Right : XString) return Boolean is B : Char_Array; L : Natural; begin Get_String (Right, B, L); return Left < Char_String (B (1 .. L)); end "<"; --------- -- "<" -- --------- function "<" (Left, Right : XString) return Boolean is B, B2 : Char_Array; L, L2 : Natural; begin Get_String (Left, B, L); Get_String (Right, B2, L2); return B (1 .. L) < B2 (1 .. L2); end "<"; ---------- -- "<=" -- ---------- function "<=" (Left : XString; Right : Char_String) return Boolean is B : Char_Array; L : Natural; begin Get_String (Left, B, L); return Char_String (B (1 .. L)) <= Right; end "<="; ---------- -- "<=" -- ---------- function "<=" (Left : Char_String; Right : XString) return Boolean is B : Char_Array; L : Natural; begin Get_String (Right, B, L); return Left <= Char_String (B (1 .. L)); end "<="; ---------- -- "<=" -- ---------- function "<=" (Left, Right : XString) return Boolean is B, B2 : Char_Array; L, L2 : Natural; begin Get_String (Left, B, L); Get_String (Right, B2, L2); return B (1 .. L) <= B2 (1 .. L2); end "<="; ------------- -- Compare -- ------------- function Compare (Left : XString; Right : Char_String) return Compare_Result is S : Char_Array; L : Natural; C2 : Char_Type; begin Get_String (Left, S, L); for C in 1 .. Integer'Min (L, Right'Length) loop C2 := Right (Right'First + C - 1); if S (C) < C2 then return -1; elsif S (C) > C2 then return 1; end if; end loop; if L = Right'Length then return 0; elsif L < Right'Length then return -1; else return 1; end if; end Compare; ------------- -- Compare -- ------------- function Compare (Left : XString; Right : XString) return Compare_Result is S : Char_Array; L : Natural; begin Get_String (Right, S, L); return Compare (Left, Char_String (S (1 .. L))); end Compare; ------------------------------ -- Compare_Case_Insensitive -- ------------------------------ function Compare_Case_Insensitive (Left : XString; Right : Char_String) return Compare_Result is S : Char_Array; L : Natural; C2, C3 : Char_Type; begin Get_String (Left, S, L); for C in 1 .. Integer'Min (L, Right'Length) loop C3 := To_Lower (S (C)); C2 := To_Lower (Right (Right'First + C - 1)); if C3 < C2 then return -1; elsif C3 > C2 then return 1; end if; end loop; if L = Right'Length then return 0; elsif L < Right'Length then return -1; else return 1; end if; end Compare_Case_Insensitive; ------------------------------ -- Compare_Case_Insensitive -- ------------------------------ function Compare_Case_Insensitive (Left : XString; Right : XString) return Compare_Result is S : Char_Array; L : Natural; begin Get_String (Right, S, L); return Compare_Case_Insensitive (Left, Char_String (S (1 .. L))); end Compare_Case_Insensitive; --------- -- Get -- --------- function Get (Self : XString; Index : Positive) return Char_Type is B : Char_Array; L : Natural; begin Get_String (Self, B, L); if Index <= L then return B (Index); else raise Ada.Strings.Index_Error with "Invalid index" & Index'Img & " (greater than" & L'Img & ")"; end if; end Get; --------------- -- Reference -- --------------- function Reference (Self : aliased in out XString; Index : Positive) return Character_Reference is B : Char_Array; L : Natural; begin if Copy_On_Write and then Self.Data.Big.Is_Big then -- Make the string unshareable Make_Writable (Self); Self.Data.Big.Data.Refcount := Unshareable; end if; Get_String (Self, B, L); if Index <= L then return (Char => B (Index)'Unrestricted_Access); else raise Ada.Strings.Index_Error with "Invalid index" & Index'Img & " (greater than" & L'Img & ")"; end if; end Reference; ----------- -- Slice -- ----------- procedure Slice (Self : in out XString; Low : Positive; High : Natural) is New_Size : Natural; begin if Low > High then Self.Clear; return; end if; New_Size := High - Low + 1; if not Self.Data.Small.Is_Big then if Low > Natural (Self.Data.Small.Size) or else High > Natural (Self.Data.Small.Size) then raise Ada.Strings.Index_Error; end if; Self.Data.Small.Data (1 .. New_Size) := Self.Data.Small.Data (Low .. High); Self.Data.Small.Size := SSize (New_Size); else if String_Size (Low) > Self.Data.Big.Size or else String_Size (High) > Self.Data.Big.Size then raise Ada.Strings.Index_Error; end if; -- Keep the same data (no need for change in refcount -- or to duplicate) Self.Data.Big.First := Low + Self.Data.Big.First - 1; Self.Data.Big.Size := String_Size (New_Size); end if; end Slice; ----------- -- Slice -- ----------- procedure Slice (Self : XString; Low : Positive; High : Natural; Into : in out XString) is Len : constant Natural := Self.Length; Size : String_Size; Is_Same : Boolean; Str, IStr : Char_Array; begin -- Match the behavior of standard strings if Low > High then Into.Clear; return; end if; -- We can't use Set, since we want to share the buffer when -- possible. if Low > Len then raise Ada.Strings.Index_Error with Low'Img & ">" & Len'Img; end if; if High > Len then raise Ada.Strings.Index_Error with High'Img & ">" & Len'Img; end if; -- We should not call Reserve: this would call Make_Writable, -- and thus potentially requires a copy of the buffer. Instead, -- we want to reuse the buffer if possible. -- But Into might already have some data, so we must avoid leaks Size := String_Size (High - Low + 1); if not Self.Data.Big.Is_Big then -- Taking a slice of a small string always results in small if Into.Data.Big.Is_Big then Finalize (Into); Into.Data.Big.Is_Big := False; end if; Into.Data.Small.Data (1 .. Integer (Size)) := Self.Data.Small.Data (Low .. High); Into.Data.Small.Size := SSize (Size); elsif Copy_On_Write and then Self.Data.Big.Data.Refcount /= Unshareable then Is_Same := Into.Data.Big.Is_Big and then Into.Data.Big.Data = Self.Data.Big.Data; -- Stop holding a shared buffer, if we were if not Is_Same then Finalize (Into); end if; Into.Data.Big := (Is_Big => True, Data => Self.Data.Big.Data, Half_Capacity => Self.Data.Big.Half_Capacity, Size => Size, First => Low + Self.Data.Big.First - 1); if not Is_Same then Increment (Into.Data.Big.Data.Refcount); -- buffer is shared end if; else -- If Into and Self are the same object (the only case where -- their Data is the same), keep that buffer and change the -- slice we use. if Into.Data.Big.Is_Big and then Into.Data.Big.Data = Self.Data.Big.Data then Into.Data.Big.First := Low + Self.Data.Big.First - 1; Into.Data.Big.Size := Size; else if Copy_On_Write then Str := Convert (Self.Data.Big.Data.Bytes2'Address); else Str := Convert (Self.Data.Big.Data.Bytes1'Address); end if; -- Try and reuse memory if we can. This memory is unique -- to Into, so we can safely alter it. if not Into.Data.Big.Is_Big then if Size <= Max_Small_Length then Into.Data.Small.Data (1 .. Natural (Size)) := Char_String (Str (Low + Self.Data.Big.First - 1 .. High + Self.Data.Big.First - 1)); Into.Data.Small.Size := SSize (Size); return; else Into.Data.Small.Size := 0; Convert_To_Big_String (Into, Size); end if; else Into.Data.Big.Size := 0; Reserve (Into, Capacity => Size); end if; if Copy_On_Write then IStr := Convert (Into.Data.Big.Data.Bytes2'Address); else IStr := Convert (Into.Data.Big.Data.Bytes1'Address); end if; Into.Data.Big.Size := Size; IStr (Into.Data.Big.First .. Into.Data.Big.First + Natural (Size) - 1) := Str (Low + Self.Data.Big.First - 1 .. High + Self.Data.Big.First - 1); end if; end if; end Slice; ----------- -- Slice -- ----------- function Slice (Self : XString; Low : Positive; High : Natural) return XString is Result : XString; begin Slice (Self, Low, High, Into => Result); return Result; end Slice; ---------- -- Trim -- ---------- procedure Trim (Self : in out XString; Side : Ada.Strings.Trim_End := Ada.Strings.Both; Chars : Char_Type := Space) is S : Char_Array; L : Natural; F : Natural := 1; begin Get_String (Self, S, L); if Side = Ada.Strings.Both or else Side = Ada.Strings.Right then while L >= 1 and then S (L) = Chars loop L := L - 1; end loop; end if; if Side = Ada.Strings.Both or else Side = Ada.Strings.Left then while F <= L and then S (F) = Chars loop F := F + 1; end loop; end if; Self.Slice (F, L); end Trim; ---------- -- Trim -- ---------- function Trim (Self : XString; Side : Ada.Strings.Trim_End := Ada.Strings.Both; Chars : Char_Type := Space) return XString is S : Char_Array; L : Natural; F : Natural := 1; begin Get_String (Self, S, L); if Side = Ada.Strings.Both or else Side = Ada.Strings.Right then while L >= 1 and then S (L) = Chars loop L := L - 1; end loop; end if; if Side = Ada.Strings.Both or else Side = Ada.Strings.Left then while F <= L and then S (F) = Chars loop F := F + 1; end loop; end if; return Self.Slice (F, L); end Trim; ----------------- -- Starts_With -- ----------------- function Starts_With (Self : XString; Prefix : Char_String) return Boolean is S : Char_Array; L : Natural; begin Get_String (Self, S, L); return L >= Prefix'Length and then Char_String (S (1 .. Prefix'Length)) = Prefix; end Starts_With; ----------------- -- Starts_With -- ----------------- function Starts_With (Self : XString; Prefix : XString) return Boolean is S, S2 : Char_Array; L, L2 : Natural; begin Get_String (Self, S, L); Get_String (Prefix, S2, L2); return L >= L2 and then S (1 .. L2) = S2 (1 .. L2); end Starts_With; --------------- -- Ends_With -- --------------- function Ends_With (Self : XString; Suffix : Char_String) return Boolean is S : Char_Array; L : Natural; begin Get_String (Self, S, L); return L >= Suffix'Length and then Char_String (S (L - Suffix'Length + 1 .. L)) = Suffix; end Ends_With; --------------- -- Ends_With -- --------------- function Ends_With (Self : XString; Suffix : XString) return Boolean is S, S2 : Char_Array; L, L2 : Natural; begin Get_String (Self, S, L); Get_String (Suffix, S2, L2); return L >= L2 and then S (L - L2 + 1 .. L) = S2 (1 .. L2); end Ends_With; ---------- -- Head -- ---------- function Head (Self : XString; Count : Natural) return XString is L : constant Natural := Self.Length; begin return Self.Slice (1, Natural'Min (Count, L)); end Head; ---------- -- Tail -- ---------- function Tail (Self : XString; Count : Natural) return XString is L : constant Natural := Self.Length; begin return Self.Slice (Natural'Max (1, L - Count + 1), L); end Tail; ------------- -- Replace -- ------------- procedure Replace (Self : in out XString; Index : Positive; Char : Char_Type) is S : Char_Array; L : Natural; begin if Self.Data.Big.Is_Big then Make_Writable (Self); end if; Get_String (Self, S, L); if Index > L then raise Ada.Strings.Index_Error with Index'Img & ">" & L'Img; end if; S (Index) := Char; end Replace; ------------- -- Replace -- ------------- procedure Replace (Self : in out XString; Low : Positive; High : Natural; By : Char_String) is S : Char_Array; L, L2 : Natural; New_L : Natural; begin L := Self.Length; if Low > L then raise Ada.Strings.Index_Error with Low'Img & ">" & L'Img; end if; if High >= L then New_L := Low - 1 + By'Length; else New_L := Low - 1 + By'Length + (L - High); end if; -- This makes the string writable Self.Reserve (String_Size (New_L)); -- Couldn't get the string before, since we might have reset it Get_String (Self, S, L2); if High < L then S (Low + By'Length .. Low + By'Length + L - High - 1) := S (High + 1 .. L); end if; if By'Length /= 0 then S (Low .. Low + By'Length - 1) := Convert (By'Address) (1 .. By'Length); end if; if Self.Data.Small.Is_Big then Self.Data.Big.Size := String_Size (New_L); else Self.Data.Small.Size := SSize (New_L); end if; end Replace; ------------------- -- Replace_Slice -- ------------------- procedure Replace_Slice (Self : in out XString; Low : Positive; High : Natural; By : XString) is By_Length : constant Natural := By.Length; S, S2 : Char_Array; L, L2 : Natural; New_L : Natural; begin -- First make strings unique, in case Self and By share a buffer. -- Unfortunately, just calling Make_Writable first would require -- one malloc here, then a second one to reserve the correct size. -- So instead we have to duplicate part of the code for Replace. L := Self.Length; if Low > L then raise Ada.Strings.Index_Error with Low'Img & ">" & L'Img; end if; if High >= L then New_L := Low - 1 + By_Length; else New_L := Low - 1 + By_Length + (L - High); end if; -- This makes the string writable, and ensure we no longer share -- the buffer. Self.Reserve (String_Size (New_L)); -- Couldn't get the string before, since we might have reset it Get_String (Self, S, L2); Get_String (By, S2, L2); if High < L then S (Low + By_Length .. Low + By_Length + L - High - 1) := S (High + 1 .. L); end if; if By_Length /= 0 then S (Low .. Low + By_Length - 1) := S2 (1 .. L2); end if; if Self.Data.Small.Is_Big then Self.Data.Big.Size := String_Size (New_L); else Self.Data.Small.Size := SSize (New_L); end if; end Replace_Slice; ------------ -- Insert -- ------------ procedure Insert (Self : in out XString; Before : Positive; New_Item : Char_String) is begin Self.Replace (Low => Before, High => Before - 1, By => New_Item); end Insert; ------------ -- Insert -- ------------ procedure Insert (Self : in out XString; Before : Positive; New_Item : XString) is begin Self.Replace_Slice (Low => Before, High => Before - 1, By => New_Item); end Insert; --------------- -- Overwrite -- --------------- procedure Overwrite (Self : in out XString; Position : Positive; New_Item : Char_String) is begin Self.Replace (Low => Position, High => Position + New_Item'Length - 1, By => New_Item); end Overwrite; --------------- -- Overwrite -- --------------- procedure Overwrite (Self : in out XString; Position : Positive; New_Item : XString) is begin Self.Replace_Slice (Low => Position, High => Position + New_Item.Length - 1, By => New_Item); end Overwrite; ------------ -- Delete -- ------------ procedure Delete (Self : in out XString; Low : Positive; High : Natural) is begin Self.Replace (Low, High, Char_String'(1 .. 0 => Char_Type'First)); end Delete; ---------- -- Hash -- ---------- function Hash (Self : XString) return Ada.Containers.Hash_Type is function H is new System.String_Hash.Hash (Char_Type, Char_String, Ada.Containers.Hash_Type); S : Char_Array; L : Natural; begin Get_String (Self, S, L); return H (Char_String (S (1 .. L))); end Hash; --------------------------- -- Hash_Case_Insensitive -- --------------------------- function Hash_Case_Insensitive (Self : XString) return Ada.Containers.Hash_Type is function H is new System.String_Hash.Hash (Char_Type, Char_String, Ada.Containers.Hash_Type); S : Char_Array; L : Natural; begin Get_String (Self, S, L); declare S2 : Char_String := Char_String (S (1 .. L)); begin for C in 1 .. L loop S2 (C) := To_Lower (S2 (C)); end loop; return H (S2); end; end Hash_Case_Insensitive; ---------- -- Swap -- ---------- procedure Swap (Self, Str : in out XString) is D : constant String_Data := Str.Data; begin Str.Data := Self.Data; Self.Data := D; end Swap; ------------ -- Center -- ------------ procedure Center (Self : in out XString; Width : Positive; Pad : Char_Type := Space) is Len : constant Natural := Self.Length; S : Char_Array; L : Natural; F : Positive; begin if Len < Width then Self.Reserve (String_Size (Width)); Get_String (Self, S, L); F := (Width - Len + 1) / 2; S (F + 1 .. F + L) := S (1 .. L); for C in 1 .. F loop S (C) := Pad; end loop; for C in F + L + 1 .. Width loop S (C) := Pad; end loop; Store_Size (Self, Width); end if; end Center; ------------ -- Center -- ------------ function Center (Self : XString; Width : Positive; Pad : Char_Type := Space) return XString is Len : constant Natural := Self.Length; Result : XString; F : Positive; S, S2 : Char_Array; L, L2 : Natural; begin if Len >= Width then return Self; else Result.Reserve (String_Size (Width)); Get_String (Self, S, L); Get_String (Result, S2, L2); F := (Width - Len + 1) / 2; for C in 1 .. F loop S2 (C) := Pad; end loop; S2 (F + 1 .. F + L) := S (1 .. L); for C in F + L + 1 .. Width loop S2 (C) := Pad; end loop; Store_Size (Result, Width); return Result; end if; end Center; ------------------ -- Left_Justify -- ------------------ procedure Left_Justify (Self : in out XString; Width : Positive; Pad : Char_Type := Space) is Len : constant Natural := Self.Length; S : Char_Array; L : Natural; begin if Len < Width then Self.Reserve (String_Size (Width)); Get_String (Self, S, L); for C in Len + 1 .. Width loop S (C) := Pad; end loop; Store_Size (Self, Width); end if; end Left_Justify; ------------------ -- Left_Justify -- ------------------ function Left_Justify (Self : XString; Width : Positive; Pad : Char_Type := Space) return XString is -- A simpler implementation is: -- Result : XString := Self; -- Result.Left_Justify (Width, Pad); -- But when not using copy-on-write this results in onre -- extra copy of the string. Len : constant Natural := Self.Length; S : Char_Array; L : Natural; Result : XString; begin if Len >= Width then return Self; else Result := Self; Result.Reserve (String_Size (Width)); Get_String (Result, S, L); for C in Len + 1 .. Width loop S (C) := Pad; end loop; Store_Size (Result, Width); return Result; end if; end Left_Justify; ------------------- -- Right_Justify -- ------------------- procedure Right_Justify (Self : in out XString; Width : Positive; Pad : Char_Type := Space) is Len : constant Natural := Self.Length; S : Char_Array; L : Natural; begin if Len < Width then Self.Reserve (String_Size (Width)); Get_String (Self, S, L); S (Width - Len + 1 .. Width) := S (1 .. Len); for C in 1 .. Width - Len loop S (C) := Pad; end loop; Store_Size (Self, Width); end if; end Right_Justify; ------------------- -- Right_Justify -- ------------------- function Right_Justify (Self : XString; Width : Positive; Pad : Char_Type := Space) return XString is Len : constant Natural := Self.Length; S, S2 : Char_Array; L, L2 : Natural; Result : XString; begin if Len >= Width then return Self; else Result.Reserve (String_Size (Width)); Get_String (Result, S, L); Get_String (Self, S2, L2); S (Width - Len + 1 .. Width) := S2 (1 .. Len); for C in 1 .. Width - L2 loop S (C) := Pad; end loop; Store_Size (Result, Width); return Result; end if; end Right_Justify; ----------- -- Count -- ----------- function Count (Self : XString; Char : Char_Type; Low : Positive := 1; High : Natural := Natural'Last) return Natural is S : Char_Array; L : Natural; Result : Natural := 0; begin Get_String (Self, S, L); if L = 0 then return 0; end if; if Low > L then raise Ada.Strings.Index_Error with Low'Img & " >" & L'Img; end if; L := Natural'Min (High, L); for C in Low .. L loop if S (C) = Char then Result := Result + 1; end if; end loop; return Result; end Count; ----------- -- Count -- ----------- function Count (Self : XString; Str : Char_String; Low : Positive := 1; High : Natural := Natural'Last) return Natural is SL : constant Integer := Str'Length - 1; S : Char_Array; L : Natural; Num : Natural := 0; Index : Natural := Low; begin Get_String (Self, S, L); if L = 0 then return 0; end if; if SL = -1 then return Natural'Last; end if; if Low > L then raise Ada.Strings.Index_Error with Low'Img & " >" & L'Img; end if; L := Natural'Min (High, L); while Index <= L - SL loop if Char_String (S (Index .. Index + SL)) = Str then Num := Num + 1; Index := Index + SL + 1; else Index := Index + 1; end if; end loop; return Num; end Count; ---------- -- Find -- ---------- function Find (Self : XString; Char : Char_Type; Low : Positive := 1; High : Natural := Natural'Last) return Natural is S : Char_Array; L : Natural; begin Get_String (Self, S, L); if Low > L then raise Ada.Strings.Index_Error with Low'Img & " >" & L'Img; end if; L := Natural'Min (High, L); for C in Low .. L loop if S (C) = Char then return C; end if; end loop; return 0; end Find; ---------- -- Find -- ---------- function Find (Self : XString; Str : Char_String; Low : Positive := 1; High : Natural := Natural'Last) return Natural is SL : constant Integer := Str'Length - 1; S : Char_Array; L : Natural; Index : Natural := Low; begin Get_String (Self, S, L); if L = 0 or else SL = -1 then return 0; end if; if Low > L then raise Ada.Strings.Index_Error with Low'Img & " >" & L'Img; end if; L := Natural'Min (High, L); while Index <= L - SL loop if Char_String (S (Index .. Index + SL)) = Str then return Index; end if; Index := Index + 1; end loop; return 0; end Find; ---------------- -- Right_Find -- ---------------- function Right_Find (Self : XString; Char : Char_Type; Low : Positive := 1; High : Natural := Natural'Last) return Natural is S : Char_Array; L : Natural; begin Get_String (Self, S, L); if Low > L then raise Ada.Strings.Index_Error with Low'Img & " >" & L'Img; end if; L := Natural'Min (High, L); for C in reverse Low .. L loop if S (C) = Char then return C; end if; end loop; return 0; end Right_Find; ---------------- -- Right_Find -- ---------------- function Right_Find (Self : XString; Str : Char_String; Low : Positive := 1; High : Natural := Natural'Last) return Natural is SL : constant Integer := Str'Length - 1; S : Char_Array; L : Natural; Index : Natural; begin Get_String (Self, S, L); if L = 0 or else SL = -1 then return 0; end if; if Low > L then raise Ada.Strings.Index_Error with Low'Img & " >" & L'Img; end if; L := Natural'Min (High, L); Index := L - SL; while Index >= 1 loop if Char_String (S (Index .. Index + SL)) = Str then return Index; end if; Index := Index - 1; end loop; return 0; end Right_Find; ----------- -- Split -- ----------- procedure Split (Self : XString; Sep : Char_Type; Omit_Empty : Boolean := False; Into : out XString_Array; Last : out Natural) is S : Char_Array; L : Natural; Index : Positive; F : Positive; -- Start of current chunk begin Get_String (Self, S, L); if Into'Length = 1 then if L = 0 and then Omit_Empty then Last := Into'First - 1; else Last := Into'First; Into (Last) := Self; end if; else Last := Into'First - 1; Index := 1; F := 1; while Index <= L loop -- For efficiency, we do not use Find here, since that would -- do a lot of extra testing that we do not need if S (Index) = Sep then if not Omit_Empty or else F <= Index - 1 then Last := Last + 1; Slice (Self, F, Index - 1, Into => Into (Last)); end if; F := Index + 1; exit when Last = Into'Last - 1; end if; Index := Index + 1; end loop; if F > L then if not Omit_Empty then Last := Last + 1; Into (Last).Clear; end if; else Last := Last + 1; Slice (Self, F, L, Into => Into (Last)); end if; end if; end Split; ----------- -- Split -- ----------- function Split (Self : XString; Sep : Char_Type; Max_Split : Positive := Positive'Last; Omit_Empty : Boolean := False) return XString_Array is L : constant Natural := Self.Length; Max_Size : constant Natural := (if Max_Split /= Natural'Last then Integer'Min (Max_Split, L) else Self.Count (Sep) + 1); Result : XString_Array (1 .. Max_Size); Last : Natural; begin Split (Self, Sep, Omit_Empty, Result, Last); return Result (Result'First .. Last); end Split; ----------- -- Split -- ----------- function Split (Self : XString; Sep : Char_String; Max_Split : Positive := Positive'Last; Omit_Empty : Boolean := False) return XString_Array is L : constant Natural := Self.Length; Max_Size : constant Natural := (if Sep'Length = 0 then 1 -- Won't be used anyway elsif Max_Split /= Natural'Last then Integer'Min (Max_Split, L) else Self.Count (Sep) + 1); Result : XString_Array (1 .. Max_Size); Last : Natural; begin Split (Self, Sep, Omit_Empty, Result, Last); return Result (Result'First .. Last); end Split; ----------- -- Split -- ----------- procedure Split (Self : XString; Sep : Char_String; Omit_Empty : Boolean := False; Into : out XString_Array; Last : out Natural) is SL : constant Integer := Sep'Length - 1; S : Char_Array; L : Natural; Index : Positive; F : Positive; -- Start of current chunk begin Get_String (Self, S, L); if L = 0 or else SL = -1 then Last := Into'First - 1; return; end if; if Into'Length = 1 then if L = 0 and then Omit_Empty then Last := Into'First - 1; else Last := Into'First; Into (Last) := Self; end if; else Last := Into'First - 1; Index := 1; F := 1; while Index <= L - SL loop -- For efficiency, we do not use Find here, since that would -- do a lot of extra testing that we do not need if Char_String (S (Index .. Index + SL)) = Sep then if not Omit_Empty or else F <= Index - 1 then Last := Last + 1; Slice (Self, F, Index - 1, Into => Into (Last)); end if; F := Index + SL + 1; exit when Last = Into'Last - 1; Index := F; else Index := Index + 1; end if; end loop; if F > L then if not Omit_Empty then Last := Last + 1; Into (Last).Clear; end if; else Last := Last + 1; Slice (Self, F, L, Into => Into (Last)); end if; end if; end Split; ----------------- -- Right_Split -- ----------------- procedure Right_Split (Self : XString; Sep : Char_Type; Omit_Empty : Boolean := False; Into : out XString_Array; Last : out Natural) is S : Char_Array; L : Natural; Index : Integer; F : Natural; -- End of current chunk begin Get_String (Self, S, L); if Into'Length = 1 then if L = 0 and then Omit_Empty then Last := Into'First - 1; else Last := Into'First; Into (Last) := Self; end if; else Last := Into'First - 1; Index := L; F := L; while Index >= 1 loop if S (Index) = Sep then if not Omit_Empty or else F > Index then Last := Last + 1; if Index >= L then Into (Last).Clear; else Slice (Self, Index + 1, F, Into => Into (Last)); end if; end if; F := Index - 1; exit when Last = Into'Last - 1; end if; Index := Index - 1; end loop; if F < 1 then if not Omit_Empty then Last := Last + 1; Into (Last).Clear; end if; else Last := Last + 1; Slice (Self, 1, F, Into => Into (Last)); end if; end if; end Right_Split; ----------------- -- Right_Split -- ----------------- function Right_Split (Self : XString; Sep : Char_Type; Max_Split : Positive := Positive'Last; Omit_Empty : Boolean := False) return XString_Array is L : constant Natural := Self.Length; Max_Size : constant Natural := (if Max_Split /= Natural'Last then Integer'Min (Max_Split, L) else Self.Count (Sep) + 1); Result : XString_Array (1 .. Max_Size); Last : Natural; begin Right_Split (Self, Sep, Omit_Empty, Result, Last); return Result (Result'First .. Last); end Right_Split; ----------------- -- Right_Split -- ----------------- procedure Right_Split (Self : XString; Sep : Char_String; Omit_Empty : Boolean := False; Into : out XString_Array; Last : out Natural) is SL : constant Integer := Sep'Length - 1; S : Char_Array; L : Natural; Index : Integer; F : Natural; -- End of current chunk begin Get_String (Self, S, L); if L = 0 or else SL = -1 then Last := Into'First - 1; return; end if; if Into'Length = 1 then if L = 0 and then Omit_Empty then Last := Into'First - 1; else Last := Into'First; Into (Last) := Self; end if; else Last := Into'First - 1; Index := L - SL; F := L; while Index >= 1 loop if Char_String (S (Index .. Index + SL)) = Sep then if not Omit_Empty or else Index + SL + 1 <= F then Last := Last + 1; if Index + SL + 1 > L then Into (Last).Clear; else Slice (Self, Index + SL + 1, F, Into => Into (Last)); end if; end if; F := Index - 1; exit when Last = Into'Last - 1; Index := Index - SL; end if; Index := Index - 1; end loop; if F < 1 then if not Omit_Empty then Last := Last + 1; Into (Last).Clear; end if; else Last := Last + 1; Slice (Self, 1, F, Into => Into (Last)); end if; end if; end Right_Split; ----------------- -- Right_Split -- ----------------- function Right_Split (Self : XString; Sep : Char_String; Max_Split : Positive := Positive'Last; Omit_Empty : Boolean := False) return XString_Array is L : constant Natural := Self.Length; Max_Size : constant Natural := (if Sep'Length = 0 then 1 -- Won't be used anyway elsif Max_Split /= Natural'Last then Integer'Min (Max_Split, L) else Self.Count (Sep) + 1); Result : XString_Array (1 .. Max_Size); Last : Natural; begin Right_Split (Self, Sep, Omit_Empty, Result, Last); return Result (Result'First .. Last); end Right_Split; ---------- -- Join -- ---------- function Join (Sep : Char_Type; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String) return XString is Result : XString; begin Result.Set_As_Join (Sep, Items, Prefix, Suffix); return Result; end Join; ---------- -- Join -- ---------- function Join (Sep : XString; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String) return XString is Result : XString; B : Char_Array; L : Natural; begin Get_String (Sep, B, L); Result.Set_As_Join (Char_String (B (1 .. L)), Items, Prefix, Suffix); return Result; end Join; ----------------- -- Set_As_Join -- ----------------- procedure Set_As_Join (Self : out XString; Sep : Char_Type; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String) is Size : Integer; begin if Items'Length = 0 then Self.Set (Prefix); Self.Append (Suffix); else Size := Prefix'Length + Suffix'Length + Items'Length - 1; -- size for separators for It of Items loop Size := Size + It.Length; end loop; Store_Size (Self, 0); -- Reset the string Self.Reserve (String_Size (Size)); Self.Append (Prefix); for It in Items'Range loop Self.Append (Items (It)); if It /= Items'Last then Self.Append (Sep); end if; end loop; Self.Append (Suffix); end if; end Set_As_Join; ---------- -- Join -- ---------- function Join (Sep : Char_String; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String) return XString is Result : XString; begin Result.Set_As_Join (Sep, Items, Prefix, Suffix); return Result; end Join; ----------------- -- Set_As_Join -- ----------------- procedure Set_As_Join (Self : out XString; Sep : Char_String; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String) is Size : Natural; begin if Items'Length = 0 then Self.Set (Prefix); Self.Append (Suffix); else Size := Sep'Length * (Items'Length - 1) + Prefix'Length + Suffix'Length; for It of Items loop Size := Size + It.Length; end loop; Store_Size (Self, 0); -- Reset the string Self.Reserve (String_Size (Size)); Self.Append (Prefix); for It in Items'Range loop Self.Append (Items (It)); if It /= Items'Last then Self.Append (Sep); end if; end loop; Self.Append (Suffix); end if; end Set_As_Join; -------------- -- To_Upper -- -------------- procedure To_Upper (Self : in out XString) is S : Char_Array; L : Natural; begin Make_Writable (Self); Get_String (Self, S, L); for Idx in 1 .. L loop S (Idx) := To_Upper (S (Idx)); end loop; end To_Upper; -------------- -- To_Upper -- -------------- function To_Upper (Self : XString) return XString is R : XString := Self; begin To_Upper (R); return R; end To_Upper; -------------- -- To_Lower -- -------------- procedure To_Lower (Self : in out XString) is S : Char_Array; L : Natural; begin Make_Writable (Self); Get_String (Self, S, L); for Idx in 1 .. L loop S (Idx) := To_Lower (S (Idx)); end loop; end To_Lower; -------------- -- To_Lower -- -------------- function To_Lower (Self : XString) return XString is R : XString := Self; begin To_Lower (R); return R; end To_Lower; ---------------- -- Capitalize -- ---------------- procedure Capitalize (Self : in out XString) is S : Char_Array; L : Natural; begin Make_Writable (Self); Get_String (Self, S, L); S (1) := To_Upper (S (1)); end Capitalize; ----------- -- Title -- ----------- procedure Title (Self : in out XString) is S : Char_Array; L : Natural; Idx : Natural; begin Make_Writable (Self); Get_String (Self, S, L); S (1) := To_Upper (S (1)); Idx := 2; while Idx < L loop if S (Idx) = Space then S (Idx + 1) := To_Upper (S (Idx + 1)); Idx := Idx + 2; else Idx := Idx + 1; end if; end loop; end Title; -------------- -- Is_Upper -- -------------- function Is_Upper (Self : XString) return Boolean is begin for C of Self loop if C /= To_Upper (C) then return False; end if; end loop; return True; end Is_Upper; -------------- -- Is_Lower -- -------------- function Is_Lower (Self : XString) return Boolean is begin for C of Self loop if C /= To_Lower (C) then return False; end if; end loop; return True; end Is_Lower; end Strings; end GNATCOLL.Strings_Impl; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-strings_impl.ads000066400000000000000000001336271425465243200241250ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2017-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides the implementation for XString. -- Comparing with other string types -- ================================= -- Ada provides several kinds of strings: -- * A String -- is a fixed-width string, but very fast in general. Functions returning -- a String must do so on the secondary stack, which might be slow. -- * A Bounded_String -- has a known maximal size, but can represent any string smaller than this. -- It also doesn't do any memory allocation, and therefore is fast. You -- need one instance of the package for each size of bounded_string. This -- is the type to use if your coding standard restricts memory allocations. -- * An Unbounded_String -- is a string of any size, which automatically allocates more memory when -- needed. They are very flexible, but not very efficient. -- This package provides a fourth type of string, which tries to combine the -- advantages of all the above: -- * Unlimited size of the string, which grows as necessary -- More flexible than String and Bounded_String. -- * No memory allocation for small strings (for a certain definition of -- small, see the SSize parameter below). This means very fast handling of -- those small strings. -- Faster than Unbounded_String, both for small strings, as seen above, -- but also for large strings since one can use the Reserve procedure to -- preallocate enough space. -- * More extensive interface. -- For instance, you can use X(1) to get the first character of the string. -- The index always starts at 1, just like unbounded strings. -- * Supports various character types -- See the encodings section below. -- * Faster substrings -- When using copy-on-write, returning a substring does not require any -- copy of the data or memory allocation. This makes the operation much -- faster, in particular for operations that return lots of substrings, -- like Split. -- * Easy iteration -- It is possible to use a "for..of" loop to iterate on all valid indexes -- or on all characters, with a speed similar to what is done for a String. -- Task safety -- =========== -- Like Unbounded_String, a XString should not be accessed unprotected from -- several different tasks. We do not use locks for maximum efficiency. -- However, it is safe to pass a copy of a string to another thread, even when -- they share some data internally. The sharing is an implementation detail, -- and therefore properly encapsulated in this package. This package does not -- use locks internally, but atomic operations. -- So the following is invalid: -- -- Thread 1 | Thread 2 -- S.Set ("..."); | -- S.Append ("..."); | S.Append ("..."); -- invalid -- S.Append ("..."); | S.To_String; -- also invalid -- -- But the following is valid: -- -- Thread 1 | Thread 2 -- S.Set ("..."); | -- | lock; S2 := S; unlock; -- | -- S.Append ("..."); | S2.Append ("..."); -- at this point, they no longer share data, in fact -- Memory management -- ================= -- A major design decision for this package is that it does as little memory -- allocations as possible. Therefore for small strings, it does none. When -- the string grows, it ends up allocating a buffer, whose size will be -- increased when the string keeps growing. The growth strategy attempts a -- balance between speed and memory usage, so it will allocate more memory -- than strictly needed for the string, in case it eventually grows. See the -- Shrink subprogram if you need to restrict memory usage. -- When this package needs to return a copy of a string, or a substring, -- it has two possible strategies: -- * Either it tries to share the already allocated memory. As explained -- above, this is done in a thread-safe manner, and thus has a small -- performance penalty. On the other hand, it doesn't need to copy -- characters around, so it might be faster. -- As soon as you modify a string, the buffer can no longer be shared, -- and a copy is created (thus the term "copy on write"). -- * Or, if you disabled copy on write, it systematically allocates new -- memory when you do a copy or take a substring. This removes the -- need for atomic operations, and might be more efficient in heavily -- multi-threaded applications. -- We recommend doing actual performance measurement to decide which strategy -- to use. -- When you use this package, you could be seeing memory leaks when your -- program exits. This is because, like unbounded_string, it uses the pragma -- Finalize_Storage_Only which means that GNAT can skip the calls to free -- memory on exit, for performance reasons. It should not have memory leaks -- the rest of the time, though. -- Indexing -- ========= -- As opposed to what is done for standard Ada strings, all indexing always -- start at index 1. Even if you take a substring from indices 5 to 6, for -- instance, the resulting substring's first character is at index 1. -- This is both by design (for a lot of users, it is confusing to remember to -- use the proper indexes 'First and 'Last with standard strings), but also is -- needed because the internal buffer can be shared. For instance, when you -- take a substring as above, the internal buffer is shared (so we are really -- looking at characters 5 through 6 in this shared buffer). But as soon as -- you modify the substring, for instance by appending some data, this package -- needs to reallocate memory. In this case, it will move characters around, -- and we will be looking at actual characters 1 through 2 in the internal -- buffer. -- Always using "1" as the user-visible index for the first character ensures -- that any internal reallocation or move of data is transparent to the user. -- Unicode, character encodings,... -- ================================ -- When you need to manipulate characters outside of the ASCII character set -- (for instance accented letters, or Chinese symbols), things get more -- complicated. -- The unicode body assigned unique code points to all possible characters -- in use on Earth. These code points are 16 bits numbers. Ada provides -- various types to deal with code points: -- * A Character only represents code points 0 through 255. -- It is typically used to represent the Latin1 subset of unicode, -- i.e. western Europe characters. -- -- * A Wide_Character can represent mode Unicode code points, but -- requires twice as much memory to represent -- -- * A Wide_Wide_Character can represent all characters, but is even -- larger. -- There exist other character sets than Unicode, which usually predate it. -- They associate different character with codepoints. For instance, in the -- Latin1 charset, the code point 192 is "a grave"). But in latin5, it is a -- Russian letter. In Latin1, that Russian character cannot be represented. -- So to represent a character on the screen, we have to know its code point, -- but also its character set. The simplest, in terms of programming, it to -- always convert the input string from a known charset (say latin5) to -- unicode internally, so that we can always compare codepoints easily in the -- code, without the need for conversions all over the place. -- These code points (integers) need to be converted to strings so that we can -- display them, store them in files, input them,... Here, there also exists -- various ways to do that, called encodings: -- -- * Historical charset always have codepoints between 0 and 255 (and -- of course these are only a subset of all characters one might use -- in the world). So we simply use a series of bytes to represent them. -- In Ada, we would use a String for that purpose. But then, as stated -- above, this means that to compare two strings we have to know that -- they use the same charset. -- -- * Unicode defines a UTF-8 encoding. It can represent any codepoint, -- including greater than 255, but uses a variable number of bytes for -- code points. This is efficient in terms of storage (most of the -- time the characters only use a single byte), but costly in terms -- of manipulation since we have to make sure not to cut the string -- between two bytes of a multi-byte character. -- -- * Unicode also defines UTF-16, which has two variants, depending on -- whether the most significant byte goes first or not. Code points -- are represented on two bytes, though sometimes they will need a -- bit more for some rare codepoints. -- -- * Unicode finally defined UTF-32 (also with two variants), where -- codepoints are always represented as 4 bytes. -- As seen above, this is a very complex topic, and manipulating strings with -- different encodings, or comparing strings with different charsets becomes -- complex and costly in terms of performance. -- As a result, the choice taken in this package is to always store decoded -- strings (i.e. we don't use utf-8, utf-16 or anything else, but just store -- an array of code points). The Character_Type formal parameter can be used -- to chose the range of code points you want to be able to represent. -- Likewise, we always assume these are Unicode code points. -- So the workflow is the following: -- -- * Get an input string (from the user, a database,...), with a -- known charset and encoding. -- We call such a string a byte sequence since it cannot be -- interpreted correctly without information on the charset and -- encoding. -- -- * Decode this byte sequence into an XString -- -- * Manipulate the XString using any of the subprograms in this API. -- -- * If you need to output the string (to the user, into a file,...) -- encode it with an appropriate charset and encoding. private with Ada.Finalization; with Ada.Containers; with Ada.Strings; with GNATCOLL.Atomic; with System; package GNATCOLL.Strings_Impl is type String_Size is mod 2 ** 32; -- Internal size used for string sizes. This matches a Natural as used for -- standard Ada strings. Big_String_Size : constant := 2 * System.Word_Size + 2 * String_Size'Size; type Optimal_String_Size is mod (Big_String_Size / 8); for Optimal_String_Size'Size use Character'Size; -- Type used to instantiate GNATCOLL.Strings -- Ideal size is 19 bytes on 32 bits system or 23 on 64 bits systems), -- so that a small string (stored without memory allocation) takes the -- same size as a big string (not counting the size of the allocated -- memory). function Default_Growth (Current, Min_Size : String_Size) return String_Size; -- The default growth strategy. This decides how much memory we should -- allocate/reallocate for the internal buffer, based on the amount of -- memory we already use (Current), and the minimal number characters -- we need to store in the string. -- Current and Min_Size are given in 'characters' not in 'bytes', since -- a character could potentially take several bytes. generic type SSize is mod <>; -- Number of characters that can be stored in the XString object itself, -- without requiring memory allocations. -- We pass a type as opposed to an actual number of character because we -- need to apply representation clauses based on this type, which cannot -- be done if we have the number of characters. -- This type must be a range between 1 and 127. type Character_Type is (<>); -- The character type to use. You can use Character for compatibility -- with an Ada string, or Wide_Character for better Unicode support, -- or possibly other types. type Character_String is array (Positive range <>) of Character_Type; -- An array of Char_Type, i.e. a string as can be stored on the -- stack. Space : Character_Type := Character_Type'Val (Character'Pos (' ')); -- The space character with function To_Lower (Item : Character_Type) return Character_Type is <>; with function To_Upper (Item : Character_Type) return Character_Type is <>; -- character-specific functions. -- In general, you do not need to specify those if you have 'use'd -- the package Ada.Characters.Handling or Ada.Wide_Characters.Handling. Copy_On_Write : Boolean := GNATCOLL.Atomic.Is_Lock_Free; -- Whether we only duplicate strings when they are actually modified. -- The alternative is to duplicate them every time a xstring is copied -- into another. The latter might be faster in some cases (less -- contention in multithreading for instance). with function Growth_Strategy (Current, Min_Size : String_Size) return String_Size is Default_Growth; -- See the comment for Default_Growth package Strings is pragma Compile_Time_Error (Natural (SSize'Last) > 2 ** 7, "SSize too large"); subtype Char_Type is Character_Type; subtype Char_String is Character_String; Null_Char_String : constant Char_String := (1 .. 0 => <>); -- Local renamings, so that users of the package can use these types. type XString is tagged private with Constant_Indexing => Get, Variable_Indexing => Reference, Iterable => (First => First, Next => Next, Has_Element => Has_Element, Element => Get); pragma Preelaborable_Initialization (XString); Null_XString : constant XString; -- This Null_XString is always equal to an empty string. So you -- can use either -- if Str = "" then -- or if Str = Null_Xstring then type Unconstrained_Char_Array is array (1 .. Natural'Last) of aliased Char_Type; type Char_Array is access all Unconstrained_Char_Array; pragma Suppress_Initialization (Unconstrained_Char_Array); pragma No_Strict_Aliasing (Char_Array); for Char_Array'Storage_Size use 0; -- Type used to obtain a string access to a given address. -- Initialization is suppressed to handle pragma Normalize_Scalars. -- No variable of this type can be declared. It is only used via an -- access type (The storage size clause ensures we do not allocate -- variables of this type). -- It is the responsibility of the user to check the proper bounds. type XString_Array is array (Positive range <>) of XString; ---------------- -- Properties -- ---------------- function Length (Self : XString) return Natural; -- The number of characters in the string function Is_Empty (Self : XString) return Boolean is (Self.Length = 0); -- Whether the string is empty. function Get (Self : XString; Index : Positive) return Char_Type with Inline; -- Return the Index-th character of the string. -- The index always starts at 1. -- -- raises Ada.Strings.Index_Error if this is not a valid index. -- A simpler way to use this function is simply to use indexing: -- Self (Index) -- as done for a regular Ada string. type Character_Reference (Char : not null access Char_Type) is limited private with Implicit_Dereference => Char; -- A type through which we can modify a character of a string. -- It is made limited to make it harder to keep such a reference and -- pass it as parameter, for instance. -- Such a reference becomes invalid as soon as the contents of the -- string is modified, and could potentially reference freed memory. function Reference (Self : aliased in out XString; Index : Positive) return Character_Reference with Inline; -- Returns a reference to a specific character in the string. -- It is possible to change the contents of the string via this -- function. It is meant to be used implicitly as in: -- Self (Index) := 'A'; -- -- This makes Self unshareable, so that if you later do: -- S2 := Self; -- then S2 will have to make a copy of the string even when using -- copy-on-write. -------------------------- -- Iteration on indexes -- -------------------------- type Index_Range is record Low, High : Natural; end record with Iterable => (First => First, Next => Next, Has_Element => Has_Element, Element => Element); function First (Self : Index_Range) return Positive is (Self.Low); function Next (Ignored_Self : Index_Range; Index : Positive) return Positive is (Index + 1); function Has_Element (Self : Index_Range; Index : Positive) return Boolean is (Index <= Self.High); function Element (Ignored_Self : Index_Range; Index : Positive) return Positive is (Index); function Iterate (Self : XString) return Index_Range is ((Low => 1, High => Self.Length)); -- Provide an iterator to get all indexes of the string. -- This provides a convenient iterator: -- for Index of Self.Iterate loop -- C := Self (Index); -- end loop; -- This loop is about as fast as iterating directly on a -- String via a 'Range attribute. ----------------------------- -- Iteration on characters -- ----------------------------- function First (Self : XString) return Positive is (1); function Next (Self : XString; Index : Positive) return Positive is (Index + 1); function Has_Element (Self : XString; Index : Positive) return Boolean is (Index <= Self.Length); -- Standard iteration functions. -- Each iteration returns the next character in the string. -- -- Although this is better used as -- for C of Str loop -- null; -- end loop; -- -- See the Iterate function if you need to get the indexes instead ---------------------- -- Building strings -- ---------------------- -- No operator "&" is provided, for efficiency reasons. Such an -- operator would need to create temporary strings which then -- need to be freed almost immediately. Since this becomes a slow -- operation, this API does not provide it by default. procedure Set (Self : in out XString; Str : Char_String); -- Store a string in Self function To_XString (Str : Char_String) return XString; -- Same as creating a temporary function and Set-ing its value. -- This is less efficient that Set and results in more copies. procedure Append (Self : in out XString; Str : Char_String); procedure Append (Self : in out XString; Char : Char_Type); procedure Append (Self : in out XString; Str : XString); -- Append to the end of Self. function "*" (Count : Natural; Right : Char_Type) return XString; function "*" (Count : Natural; Right : Char_String) return XString; function "*" (Count : Natural; Right : XString) return XString; -- Build a new string that duplicates the Right parameter Count times procedure Reserve (Self : in out XString; Capacity : String_Size); -- Make sure Self has enough storage to contain a string of length -- Size. This doesn't impact the current value of Self, so if the -- current length is greater than Size, nothing is done. -- More memory could be allocated, for performance reasons. procedure Shrink (Self : in out XString); -- Shrinks the memory used by Self to the minimum needed. This will -- likely require some memory allocation and copying the characters. procedure Swap (Self, Str : in out XString); -- Swap the contents of the two strings. -- This is more efficient than using an intermediate variable, and -- is often useful in various algorithms. ------------------------ -- Justifying strings -- ------------------------ procedure Center (Self : in out XString; Width : Positive; Pad : Char_Type := Space); function Center (Self : XString; Width : Positive; Pad : Char_Type := Space) return XString; -- Center Self, and surround it with Pad characters, such that the -- total width is Width. -- If Self is longer than Width, it is unmodified (so the result -- could be longer than Width, use Head if you want to make sure -- this isn't the case). -- The function is not efficient since it needs to allocate memory -- and copy the characters. procedure Left_Justify (Self : in out XString; Width : Positive; Pad : Char_Type := Space); function Left_Justify (Self : XString; Width : Positive; Pad : Char_Type := Space) return XString; -- Add Pad characters at the end of Self, so that the resulting -- string is of length Width. -- If Self is longer than Width, it is returned as is. -- The function is not efficient since it needs to allocate memory -- and copy the characters. procedure Right_Justify (Self : in out XString; Width : Positive; Pad : Char_Type := Space); function Right_Justify (Self : XString; Width : Positive; Pad : Char_Type := Space) return XString; -- Add Pad characters at the beginning of Self, so that the resulting -- string is of length Width. -- If Self is longer than Width, it is returned as is. -- The function is not efficient since it needs to allocate memory -- and copy the characters. --------------- -- Comparing -- --------------- function "=" (Left : XString; Right : Char_String) return Boolean; function "=" (Left : XString; Right : XString) return Boolean; function "=" (Left : Char_String; Right : XString) return Boolean is (Right = Left); function "<" (Left : XString; Right : Char_String) return Boolean; function "<" (Left : Char_String; Right : XString) return Boolean; function "<" (Left : XString; Right : XString) return Boolean; function "<=" (Left : XString; Right : Char_String) return Boolean; function "<=" (Left : Char_String; Right : XString) return Boolean; function "<=" (Left : XString; Right : XString) return Boolean; function ">" (Left : XString; Right : Char_String) return Boolean is (not (Left <= Right)); function ">" (Left : Char_String; Right : XString) return Boolean is (not (Left <= Right)); function ">" (Left : XString; Right : XString) return Boolean is (not (Left <= Right)); function ">=" (Left : XString; Right : Char_String) return Boolean is (not (Left < Right)); function ">=" (Left : Char_String; Right : XString) return Boolean is (not (Left < Right)); function ">=" (Left : XString; Right : XString) return Boolean is (not (Left < Right)); -- Compare strings subtype Compare_Result is Integer range -1 .. 1; function Compare (Left : XString; Right : Char_String) return Compare_Result; function Compare (Left : XString; Right : XString) return Compare_Result with Inline; function Compare (Left : Char_String; Right : XString) return Compare_Result is (-Compare (Right, Left)); -- Compare two strings. -- If they are equal, returns 0. -- If Left is before Right in lexicographical order, return -1. -- If Left is after Right in lexicographical order, return 1. -- The standard operators above are not defined in terms of Compare -- because the compiler is sometimes able to generate more efficient -- code for them. function Compare_Case_Insensitive (Left : XString; Right : Char_String) return Compare_Result; function Compare_Case_Insensitive (Left : XString; Right : XString) return Compare_Result with Inline; function Compare_Case_Insensitive (Left : Char_String; Right : XString) return Compare_Result is (-Compare_Case_Insensitive (Right, Left)); -- Same as above, but ignore casing differences function Equal_Case_Insensitive (Left : XString; Right : Char_String) return Boolean is (Compare_Case_Insensitive (Left, Right) = 0); function Equal_Case_Insensitive (Left : XString; Right : XString) return Boolean is (Compare_Case_Insensitive (Left, Right) = 0); function Equal_Case_Insensitive (Left : Char_String; Right : XString) return Boolean is (Compare_Case_Insensitive (Left, Right) = 0); function Less_Case_Insensitive (Left : XString; Right : Char_String) return Boolean is (Compare_Case_Insensitive (Left, Right) = -1); function Less_Case_Insensitive (Left : XString; Right : XString) return Boolean is (Compare_Case_Insensitive (Left, Right) = -1); function Less_Case_Insensitive (Left : Char_String; Right : XString) return Boolean is (Compare_Case_Insensitive (Left, Right) = -1); ---------------- -- Converting -- ---------------- procedure Get_String (Self : XString; S : out Char_Array; L : out Natural) with Inline; -- Returns a pointer to the internal string data. -- Do not modify the characters in this string, since it could be -- shared among multiple strings. -- S is only valid as long as Self is not accessed or modified. procedure Access_String (Self : XString; Process : not null access procedure (S : Char_String)); -- Access the string contained in Self. -- While Process is running, Self itself will not be destroyed, even -- if Process should access Self and modify it. -- -- This might easier to use than Get_String, and is more efficient -- than To_String. function To_String (Self : XString) return Char_String; -- This functions returns the internal string. -- As much as possible, you should use Get_String instead, which is -- much more efficient. This function requires returning data whose -- size is not known statically to the compiler, thus requires using -- the secondary stack and copying the string. This can have significant -- performance impact when the string is big. ------------- -- Hashing -- ------------- function Hash (Self : XString) return Ada.Containers.Hash_Type; -- Return a hash value suitable for the standard containers map. -- This is not a cryptographica hash. function Hash_Case_Insensitive (Self : XString) return Ada.Containers.Hash_Type; -- Same as above, but ignore casing ------------ -- Casing -- ------------ procedure To_Upper (Self : in out XString); function To_Upper (Self : XString) return XString; -- Convert all characters of Self to upper case, using the formal -- parameter To_Upper. procedure To_Lower (Self : in out XString); function To_Lower (Self : XString) return XString; -- Convert all characters of Self to lower case, using the formal -- parameter To_Lower. procedure Capitalize (Self : in out XString); -- Make sure the first letter of Self is upper cased. -- All other characters are lower cased. procedure Title (Self : in out XString); -- The first letter and all letters after a space are upper cased, -- and all other characters are lower cased. function Is_Upper (Self : XString) return Boolean; function Is_Lower (Self : XString) return Boolean; -- True if all characters in Self are upper or lower cased ------------- -- Testing -- ------------- function Starts_With (Self : XString; Prefix : Char_String) return Boolean; function Starts_With (Self : XString; Prefix : XString) return Boolean; -- Whether Self starts with the specific prefix. function Ends_With (Self : XString; Suffix : Char_String) return Boolean; function Ends_With (Self : XString; Suffix : XString) return Boolean; -- Whether Self ends with the specific suffix. --------------- -- Searching -- --------------- -- These functions do not use advanced algorithms like Boyer-Moore, -- so do not take take advantage of the pattern to optimize the -- search. -- See also GNATCOLL.Boyer_Moore for more advanced algorithms function Count (Self : XString; Char : Char_Type; Low : Positive := 1; High : Natural := Natural'Last) return Natural; function Count (Self : XString; Str : Char_String; Low : Positive := 1; High : Natural := Natural'Last) return Natural; -- Return the number of non-overlapping occurrences of Char or Str. -- If Str is the empty string, returns Natural'Last (infinite). -- The search is done in the substring Low..High (by default the -- whole string). -- Index_Error is raised if Low is not a valid index (unless Self -- is the empty string). function Find (Self : XString; Char : Char_Type; Low : Positive := 1; High : Natural := Natural'Last) return Natural; function Find (Self : XString; Str : Char_String; Low : Positive := 1; High : Natural := Natural'Last) return Natural; function Right_Find (Self : XString; Char : Char_Type; Low : Positive := 1; High : Natural := Natural'Last) return Natural; function Right_Find (Self : XString; Str : Char_String; Low : Positive := 1; High : Natural := Natural'Last) return Natural; -- Return the index of the first occurrence of Char or Str, -- in the substring Self(Low..High). -- Index_Error is raised if Low is not a valid index (unless Self -- is the empty string). -- -- The Right_Find functions start searching from the right of -- Self. -- -- 0 is returned when no match was found or Str is the empty string. ---------------- -- Substrings -- ---------------- -- The following subprograms return a substring of Self, based on -- various criteria. -- -- When using copy-on-write, these subprograms will share the storage -- of Self, and thus will not require new memory allocation. This -- makes them fast. -- When not using copy-on-write, however, they require copy of the -- characters and memory allocations. The functions are even more -- expensive, since they require additional copies, so we recommend -- using the procedures instead. -- -- All returned substrings always start at index 1, even if you took -- a slice from another index on. procedure Slice (Self : in out XString; Low : Positive; High : Natural); function Slice (Self : XString; Low : Positive; High : Natural) return XString; procedure Slice (Self : XString; Low : Positive; High : Natural; Into : in out XString); -- Return a substring of Self. -- The first character of Self is always at index 1, so this function -- returns a slice from the Low-th character of Self to the High-th -- character of Self. -- -- raises Ada.Strings.Index_Error if any of the indexes is invalid. procedure Trim (Self : in out XString; Side : Ada.Strings.Trim_End := Ada.Strings.Both; Chars : Char_Type := Space); function Trim (Self : XString; Side : Ada.Strings.Trim_End := Ada.Strings.Both; Chars : Char_Type := Space) return XString; -- Remove characters on either end of the string. -- All characters equal to Chars are removed from either ends. function Head (Self : XString; Count : Natural) return XString; -- Return the first Count characters of Self. -- If Self is smaller, it is returned as is. function Tail (Self : XString; Count : Natural) return XString; -- Return the last Count characters of Self. -- If Self is smaller, it is returned as is. function Split (Self : XString; Sep : Char_Type; Max_Split : Positive := Positive'Last; Omit_Empty : Boolean := False) return XString_Array; procedure Split (Self : XString; Sep : Char_Type; Omit_Empty : Boolean := False; Into : out XString_Array; Last : out Natural); function Split (Self : XString; Sep : Char_String; Max_Split : Positive := Positive'Last; Omit_Empty : Boolean := False) return XString_Array; procedure Split (Self : XString; Sep : Char_String; Omit_Empty : Boolean := False; Into : out XString_Array; Last : out Natural); -- Split self into chunks, on every occurrence of Sep. -- -- The procedure is faster since it does fewer copies of the strings, -- in particular when not using Copy-On-Write. Only elements from -- Into'First .. Last have been set or modified. Others are left -- untouched. -- -- If Max_Split is specified, at most that many substrings are -- returned, and the last one extends till the end of Self. -- The procedure uses the size of Into has the maximum number of -- splits that are allowed. -- Specifying a Max_Split is more efficient, since otherwise these -- subprograms need to count the number of times splitting is -- necessary. -- -- If Omit_Empty is true, then none of the returned substring will -- be the empty string. -- -- For instance, if Self = "1,,2,3,,4", then: -- * Sep=',' => ["1", "2", "", "3", "", "4"] -- * Sep=',' and Omit_Empty=True => ["1", "2", "3", "4"] -- * Sep=',' and Max_Split=3 => ["1", "2", "3,,4"] -- As another example, if you need to split on consecutive whitespaces -- you can use Omit_Empty=True and Sep=' ', for instance: -- " 2 3 4" => ["2", "3", "4"] -- -- Splitting an empty string will return an empty array. -- Splitting on an empty Sep has the same effect. function Right_Split (Self : XString; Sep : Char_Type; Max_Split : Positive := Positive'Last; Omit_Empty : Boolean := False) return XString_Array; procedure Right_Split (Self : XString; Sep : Char_Type; Omit_Empty : Boolean := False; Into : out XString_Array; Last : out Natural); function Right_Split (Self : XString; Sep : Char_String; Max_Split : Positive := Positive'Last; Omit_Empty : Boolean := False) return XString_Array; procedure Right_Split (Self : XString; Sep : Char_String; Omit_Empty : Boolean := False; Into : out XString_Array; Last : out Natural); -- Same as Split, but starting from the right. -- The substrings are returned in the reverse order, from right to -- left in Self. procedure Set_As_Join (Self : out XString; Sep : Char_String; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String); function Join (Sep : Char_String; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String) return XString; function Join (Sep : XString; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String) return XString; procedure Set_As_Join (Self : out XString; Sep : Char_Type; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String); function Join (Sep : Char_Type; Items : XString_Array; Prefix : Char_String := Null_Char_String; Suffix : Char_String := Null_Char_String) return XString; -- Return a string that contains all elements from Items, separated -- by Self. -- Prefix is automatically added before the string, -- while Suffix is added after the string. Using them might save some -- extra memory allocation or copying. -- The function versions are less efficient (more so when not using -- copy-on-write). --------------- -- Modifying -- --------------- procedure Replace (Self : in out XString; Index : Positive; Char : Char_Type); -- Replace a specific character in the string. -- Index_Error is raised if the index is invalid. procedure Replace (Self : in out XString; Low : Positive; High : Natural; By : Char_String); procedure Replace_Slice (Self : in out XString; Low : Positive; High : Natural; By : XString) with Inline; -- Replace the substring Low..High with By. -- Low must be a valid index (but High might be larger than the -- string's length). -- If High < Low, this is the equivalent of inserting the new -- string at position Low. procedure Insert (Self : in out XString; Before : Positive; New_Item : Char_String) with Inline; procedure Insert (Self : in out XString; Before : Positive; New_Item : XString) with Inline; -- Insert the new item at the given position in Self. procedure Overwrite (Self : in out XString; Position : Positive; New_Item : Char_String) with Inline; procedure Overwrite (Self : in out XString; Position : Positive; New_Item : XString) with Inline; -- Replace the substring at the given Position with the new -- item. If Self is longer, characters after are preserved. procedure Delete (Self : in out XString; Low : Positive; High : Natural) with Inline; -- Delete the substring Low..High. -- Both indexes must be valid. procedure Clear (Self : in out XString); -- Reset the contents of Self, and frees all allocated memory. -- You do not need to call this procedure in general, since memory -- is handled automatically. For instance, when Self goes out of -- scope, memory is freed. -- In general, it is more efficient to call Set on the string without -- calling Clear first, since GNATCOLL will be able to reuse already -- allocated memory in such a case. private Max_Small_Length : constant String_Size := String_Size (SSize'Last); -- Number of bytes in the small_string buffer, as decided by the user. type Character_Reference (Char : not null access Char_Type) is null record; type Big_String_Data (Copy_On_Write : Boolean) is limited record case Copy_On_Write is when False => Bytes1 : Unconstrained_Char_Array; when True => Refcount : aliased GNATCOLL.Atomic.Atomic_Counter; Bytes2 : Unconstrained_Char_Array; end case; end record with Unchecked_Union; type Big_String_Data_Access is access all Big_String_Data; pragma Suppress_Initialization (Big_String_Data); pragma No_Strict_Aliasing (Big_String_Data_Access); -- Unsafe: this is the data used by big strings to store the actual -- byte sequence. When we use refcounting, we need to have an explicit -- refcount, which is not needed otherwise. type Small_String is record Is_Big : Boolean; Size : SSize; Data : Char_String (1 .. Natural (Max_Small_Length)); end record; for Small_String use record Is_Big at 0 range 0 .. 0; Size at 0 range 1 .. 7; end record; pragma Suppress_Initialization (Small_String); -- Hard-code the fact that we can represent the small size on 7 bits -- (the pragma Compile_Time_Error ensures this is the case). Would be -- nice if we could use "15" of "7" for larger small string, but we -- would need static constants for this, and generic formal are not -- (so that compilers can implement shared generics). subtype Half_Capacity_Size is String_Size range 0 .. 2 ** 31 - 1; type Big_String is record Is_Big : Boolean; Half_Capacity : Half_Capacity_Size; Size : String_Size; Data : aliased Big_String_Data_Access; -- This field must be aligned on multiple of word_size, so can't -- be last. First : Positive; -- Index of the first character in data. -- This is used to share the data between substrings. When we -- do not use copy-on-write, part of the buffer might becomes -- useless but this is faster than reallocating and copying. -- On 64-bits platforms, we have 32 bits unused here. end record; for Big_String use record Is_Big at 0 range 0 .. 0; Half_Capacity at 0 range 1 .. 31; Size at 4 range 0 .. 31; Data at 8 range 0 .. System.Word_Size - 1; First at 8 + System.Word_Size / 8 range 0 .. 31; end record; for Big_String'Size use Big_String_Size; pragma Suppress_Initialization (Big_String); -- Capacity is always an even number, and we store half of it, so that -- it leaves one bit for the flag. type String_Data (Is_Big : Boolean := False) is record case Is_Big is when False => Small : Small_String; when True => Big : Big_String; end case; end record with Unchecked_Union; type XString is new Ada.Finalization.Controlled with record Data : String_Data := (Is_Big => False, Small => <>); end record; overriding procedure Adjust (Self : in out XString); overriding procedure Finalize (Self : in out XString); pragma Finalize_Storage_Only (XString); -- Finalization is only required for freeing storage pragma Stream_Convert (XString, To_XString, To_String); -- provide stream routines without dragging in Ada.Streams Null_XString : constant XString := (Ada.Finalization.Controlled with Data => (Is_Big => False, Small => <>)); end Strings; -- Unbounded strings have: -- Index_Non_Blank Find_Token Translate -- Ada.Strings.UTF_Encoding -- Can we reorganize to share code between various instances that -- use the same Char_Type and Char_String ? -- C++ has: -- rfind find_first_of find_last_of -- find_first_not_of find_last_not_of -- Python adds: -- "in" isalpha isprintable -- format isdecimal isspace partition -- splitlines expandtabs isdigit istitle -- zfill isidentifier isalnum swapcase -- casefold isnumeric end GNATCOLL.Strings_Impl; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-symbols.adb000066400000000000000000000160511425465243200230510ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Containers; use Ada.Containers; with Ada.Strings.Hash; with Ada.Unchecked_Conversion; with Ada.Unchecked_Deallocation; with GNAT.IO; use GNAT.IO; with GNAT.Strings; with System.Address_Image; package body GNATCOLL.Symbols is use String_Htable; Table_Size : constant := 98_317; -- The initial capacity of the htable. This was computed from inserting -- all entities from the GPS project, using Ada.Strings.Hash for the hash, -- but seems to be the same when using other hash codes. -- The table will readjust itself anyway, but setting this properly avoids -- a few resizing. ----------------- -- Debug_Print -- ----------------- function Debug_Print (S : Symbol) return String is begin if S = No_Symbol then return ""; else return ""; end if; end Debug_Print; ---------- -- Hash -- ---------- function Hash (Str : Cst_String_Access) return Hash_Type is begin return Ada.Strings.Hash (Str.all); end Hash; --------------- -- Key_Equal -- --------------- function Key_Equal (Key1, Key2 : Cst_String_Access) return Boolean is begin return Key1.all = Key2.all; end Key_Equal; ---------- -- Find -- ---------- function Find (Table : access Symbol_Table_Record; Str : String) return Symbol is Result : String_Htable.Cursor; Tmp : Cst_String_Access; begin if Str'Length = 0 then return Empty_String; else Table.Calls_To_Find := Table.Calls_To_Find + 1; Result := Table.Hash.Find (Str'Unrestricted_Access); if not Has_Element (Result) then Table.Total_Size := Table.Total_Size + Str'Length; Tmp := new String'(Str); Table.Hash.Include (Tmp); return Symbol (Tmp); else Table.Size_Saved := Table.Size_Saved + Str'Length; end if; return Symbol (Element (Result)); end if; end Find; ------------------- -- Display_Stats -- ------------------- procedure Display_Stats (Self : access Symbol_Table_Record) is C : String_Htable.Cursor := Self.Hash.First; Tmp : Cst_String_Access; Count : Natural := 0; Last : Hash_Type := Hash_Type'Last; H : Hash_Type; Bucket_Count : Natural := 0; begin while Has_Element (C) loop Tmp := Element (C); H := Hash (Tmp); if H = Last then Count := Count + 1; else if Last /= Hash_Type'Last then Put_Line ("Bucket" & Last'Img & " =>" & Count'Img & " entries"); end if; Last := H; Count := 1; Bucket_Count := Bucket_Count + 1; end if; Put_Line (Hash (Tmp)'Img & " => " & Tmp.all); Next (C); end loop; Put_Line ("Total calls to Find: " & Self.Calls_To_Find'Img); Put_Line ("Number of entries in the symbols table:" & Self.Hash.Length'Img); Put_Line ("Maximum number of buckets:" & Self.Hash.Capacity'Img); Put_Line ("Number of buckets used:" & Bucket_Count'Img); Put_Line ("Mean entries per bucket:" & Integer'Image (Integer (Self.Hash.Length) / Bucket_Count)); Put_Line ("Total size in strings:" & Self.Total_Size'Img); Put_Line ("Size that would have been allocated for strings:" & Self.Size_Saved'Img); end Display_Stats; --------- -- Get -- --------- function Get (Sym : Symbol; Empty_If_Null : Boolean := True) return Cst_String_Access is begin if Sym = No_Symbol then if Empty_If_Null then return Cst_String_Access (Empty_String); else return null; end if; else return Cst_String_Access (Sym); end if; end Get; ---------- -- Free -- ---------- procedure Free (Table : in out Symbol_Table_Record) is function Convert is new Ada.Unchecked_Conversion (Cst_String_Access, GNAT.Strings.String_Access); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (String, GNAT.Strings.String_Access); S : GNAT.Strings.String_Access; C : String_Htable.Cursor := Table.Hash.First; Tmp : Cst_String_Access; begin while Has_Element (C) loop Tmp := Element (C); Next (C); S := Convert (Tmp); Unchecked_Free (S); end loop; Table.Hash.Clear; end Free; ---------- -- Free -- ---------- procedure Free (Table : in out Symbol_Table_Access) is procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Symbol_Table_Record'Class, Symbol_Table_Access); begin if Table /= null then Free (Table.all); Unchecked_Free (Table); end if; end Free; ---------- -- Hash -- ---------- function Hash (S : Symbol) return Hash_Type is begin return Hash (Cst_String_Access (S)); end Hash; -------------- -- Allocate -- -------------- function Allocate return Symbol_Table_Access is T : constant Symbol_Table_Access := new Symbol_Table_Record; begin T.Hash.Reserve_Capacity (Table_Size); return T; end Allocate; end GNATCOLL.Symbols; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-symbols.ads000066400000000000000000000111501425465243200230650ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- A symbol table -- Equal strings are always represented with the same pointer, thus -- reducing the amount of memory to store multiple instances of the same -- string, and speeding up comparison (since you only need to compare the -- pointer, not the string itself). with Ada.Containers.Hashed_Sets; with GNATCOLL.Utils; use GNATCOLL.Utils; package GNATCOLL.Symbols is type Symbol_Table_Record (<>) is tagged private; type Symbol_Table_Access is access all Symbol_Table_Record'Class; -- A symbol table associating integers with strings. -- By default, this is not task safe, so you will need to extend this if -- the symbol is to be shared between multiple tasks. type Symbol is private; No_Symbol : constant Symbol; Empty_String : constant Symbol; function Allocate return Symbol_Table_Access; -- Allocate a new symbol table function Find (Table : access Symbol_Table_Record; Str : String) return Symbol; -- Return the internal version of Str. -- Comparing Symbol is the same as comparing the string itself, but much -- faster. function Get (Sym : Symbol; Empty_If_Null : Boolean := True) return Cst_String_Access; pragma Inline_Always (Get); -- The string associated with the symbol. -- The returned string must not be deallocated, it points to internal data. -- For No_Symbol, this returns null or the empty string, depending on -- Empty_If_Null. procedure Free (Table : in out Symbol_Table_Record); procedure Free (Table : in out Symbol_Table_Access); -- Free the table function Hash (S : Symbol) return Ada.Containers.Hash_Type; -- Returns a hash for the symbol, in case you need to create your own -- hash tables. function Debug_Print (S : Symbol) return String; -- Return a displaying version of symbol (debugging purposes only) procedure Display_Stats (Self : access Symbol_Table_Record); -- Display statistics about the table. -- This is meant for debug purposes only, and the output might change from -- one version to the next. private type Symbol is new Cst_String_Access; Cst_Empty_String : aliased constant String := ""; No_Symbol : constant Symbol := null; Empty_String : constant Symbol := Cst_Empty_String'Access; function Hash (Str : Cst_String_Access) return Ada.Containers.Hash_Type; function Key_Equal (Key1, Key2 : Cst_String_Access) return Boolean; pragma Inline (Hash, Key_Equal); package String_Htable is new Ada.Containers.Hashed_Sets (Element_Type => Cst_String_Access, Hash => Hash, Equivalent_Elements => Key_Equal, "=" => "="); type Symbol_Table_Record is tagged record Hash : String_Htable.Set; Calls_To_Find : Natural := 0; Total_Size : Long_Long_Integer := 0; Size_Saved : Long_Long_Integer := 0; end record; end GNATCOLL.Symbols; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-templates.adb000066400000000000000000000210041425465243200233510ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with GNAT.Strings; use GNAT.Strings; package body GNATCOLL.Templates is procedure Find_Identifier (Str : String; Delimiter : Character; First : in out Integer; Last : out Integer; First_After : out Integer); -- Set Last to the last character of the identifier name. -- First should point to the first candidate character, but could be -- moved forward if it points to a curly brace. ---------- -- Free -- ---------- procedure Free (Substrings : in out Substitution_Array) is begin for S in Substrings'Range loop Free (Substrings (S).Name); Free (Substrings (S).Value); end loop; end Free; --------------------- -- Find_Identifier -- --------------------- procedure Find_Identifier (Str : String; Delimiter : Character; First : in out Integer; Last : out Integer; First_After : out Integer) is begin if Str (First) = Delimiter then -- We are escaping the delimiter by doubling it Last := First; First_After := First + 1; elsif Str (First) = '{' then First := First + 1; Last := First; while Last <= Str'Last and then Str (Last) /= '}' loop Last := Last + 1; end loop; First_After := Last + 1; Last := Last - 1; elsif Str (First) = '(' then First := First + 1; Last := First; while Last <= Str'Last and then Str (Last) /= ')' loop Last := Last + 1; end loop; First_After := Last + 1; Last := Last - 1; elsif Is_Digit (Str (First)) then Last := First + 1; while Last <= Str'Last and then Is_Digit (Str (Last)) loop Last := Last + 1; end loop; if Last <= Str'Last and then Str (Last) = '-' then Last := Last + 1; end if; First_After := Last; Last := Last - 1; elsif Is_Alphanumeric (Str (First)) then Last := First + 1; while Last <= Str'Last and then (Is_Alphanumeric (Str (Last)) or else Str (Last) = '_') loop Last := Last + 1; end loop; First_After := Last; Last := Last - 1; else Last := First; First_After := Last + 1; end if; end Find_Identifier; ---------------- -- Substitute -- ---------------- function Substitute (Str : String; Substrings : Substitution_Array := No_Substitution; Callback : Substitute_Callback := null; Delimiter : Character := Default_Delimiter; Recursive : Boolean := False; Errors : Error_Handling := Keep_As_Is) return String is Result : Unbounded_String; First, Last : Natural := Str'First; Found : Boolean; Identifier_First, Identifier_Last, First_After : Natural; Quoted : Boolean := False; begin while First <= Str'Last loop Last := First; -- Skip constant substrings while Last <= Str'Last and then Str (Last) /= Delimiter loop if Str (Last) = '"' then Quoted := not Quoted; end if; Last := Last + 1; end loop; if Last = Str'Last then Last := Last + 1; end if; Append (Result, Str (First .. Last - 1)); exit when Last > Str'Last; -- Find name of identifier First := Last + 1; Identifier_First := First; Find_Identifier (Str, Delimiter, Identifier_First, Last, First_After); -- Does the identifier contain a default value? Identifier_Last := Last; for D in Identifier_First .. Identifier_Last - 1 loop if Str (D) = ':' and then Str (D + 1) = '-' then Identifier_Last := D - 1; exit; end if; end loop; Found := False; for S in Substrings'Range loop if Substrings (S).Name.all = Str (Identifier_First .. Identifier_Last) then if Recursive then Append (Result, Substitute (Str => Substrings (S).Value.all, Substrings => Substrings, Callback => Callback, Delimiter => Delimiter, Recursive => Recursive)); else Append (Result, Substrings (S).Value.all); end if; Found := True; exit; end if; end loop; -- When doubled, the delimiter is always replaced with itself by -- default. if not Found and then Identifier_Last = Identifier_First and then Str (Identifier_First) = Delimiter then -- We are escaping the Substitution_Char by doubling it Append (Result, Delimiter); Found := True; elsif not Found and then Callback /= null then begin declare Sub : constant String := Callback (Str (Identifier_First .. Identifier_Last), Quoted); begin if Recursive then Append (Result, Substitute (Str => Sub, Substrings => Substrings, Callback => Callback, Delimiter => Delimiter, Recursive => Recursive)); else Append (Result, Sub); end if; Found := True; end; exception when Invalid_Substitution => Found := False; end; end if; -- If still not found, try the default value if it was specified if not Found and then Identifier_Last < Last then Append (Result, Str (Identifier_Last + 3 .. Last)); Found := True; end if; if not Found then case Errors is when Keep_As_Is => Append (Result, Str (First - 1 .. First_After - 1)); when Replace_With_Empty => null; when Report_Error => raise Invalid_Substitution; end case; end if; First := First_After; end loop; return To_String (Result); end Substitute; end GNATCOLL.Templates; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-templates.ads000066400000000000000000000156211425465243200234020ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides support for replacing special substrings in a string. -- Typically, these are used to replace substrings like "%version" by the some -- other value, at run time. -- Do not confuse this unit with the templates parser which is provided in the -- context of the Ada Web Server (AWS), and which is used to parse external -- file and replace part of them. with GNAT.Strings; package GNATCOLL.Templates is type Substitution_Value is record Name : GNAT.Strings.String_Access; Value : GNAT.Strings.String_Access; end record; type Substitution_Array is array (Natural range <>) of Substitution_Value; procedure Free (Substrings : in out Substitution_Array); -- Free the memory occupied by the array No_Substitution : constant Substitution_Array; type Substitute_Callback is access function (Name : String; Quoted : Boolean) return String; -- A callback for Substitute below. It is called once for each '%...' -- parameter found in the string. Name doesn't include the delimiter. -- Quoted indicate whether the parameter was quoted, ie the '%...' was -- found as part of a quoted subtrings (for instance -- a "quoted %version substring" b -- The reason is that the substituted version could be different in such -- a case, and the subtituted value might need to protect quote symbols -- in its replacement string. -- Should raise Invalid_Substitution if Name cannot be substituted Default_Delimiter : constant Character := '%'; -- The default delimiter used to mark the special substrings. It can be -- overridden in the various Substitute subprograms below. -- The special substrings always start with this delimiter, and including -- the following number or identifier. That identifier can be quoted -- between curly braces ({...}) or parentheses to avoid ambiguities. -- For instance: -- a%bcd*df => identifier name is "bcd" -- a%123ab => identifier name is "123" -- a%{bc}d*df => identifier name is "bc" -- a%(bc)d*df => identifier name is "bc" -- -- If the identifier is a number, the special character "-" will -- be included in the name if it follows the number exactly: -- a %1- b => identifier name is "1-" -- a %1+ b => identifier name is "1" -- The goal is to use this to indicate a range of parameter (in the first -- example above, the intended substitution is the value of %1 concatenated -- with that of %2, %3,..., so is an equivalent of "%1%2%3%4" if there are -- four possible parameters. -- -- If the first character after the delimiter is not an alphanumeric -- character, that will be the name of the identifier -- a %* b => identifier name is "*" -- a %^ b => identifier name is "^" -- -- When the delimiter is duplicated, it will always be replaced by a -- single instance of the delimiter (unless you have specified another -- explicit replacement for it in the Substrings parameter). For instance, -- if the string contains "a%%b" it will be replaced with "a%b". -- -- When an identifier is specified within curly braces or parentheses, a -- default value can be specified for it, which will be used if no other -- substitution is available. The syntax is similar to that of the Unix -- shell: -- %{var:-default} -- where "default" is the default value to use. type Error_Handling is (Keep_As_Is, Replace_With_Empty, Report_Error); -- What to do when no substitution value was found: -- If Keep_As_Is, the text is unaltered. "%invalid" remains as is -- If Replace_With_Empty, the text is replaced with the empty string. -- "%invalid" becomes "". -- If Report_Error, an exception Invalid_Substitution is raised function Substitute (Str : String; Substrings : Substitution_Array := No_Substitution; Callback : Substitute_Callback := null; Delimiter : Character := Default_Delimiter; Recursive : Boolean := False; Errors : Error_Handling := Keep_As_Is) return String; -- Replace all substrings in Str that start with Delimiter (see the -- declaration of Default_Delimiter for more information on identifier -- names). -- If an identifier found in Str matches no entry from Substrings, -- Callback is called to try and find the appropriate substitution. If -- that raises Invalid_Substitution, and the identifier contains a default -- value, it is used. -- If no substitution value was found, the behavior depends on the -- Error parameter. -- -- If Recursive is true, then this function will also substitute substrings -- in the values specified in Substrings, for instance: -- Delimiter := % -- Substrings (1) := (Name => "a", Value => "c%b") -- Substrings (2) := (Name => "b", Value => "d") -- -- Str := "%a" results in "cd" if Recursive is True -- results in "c%b" otherwise Invalid_Substitution : exception; private No_Substitution : constant Substitution_Array := (1 .. 0 => (null, null)); end GNATCOLL.Templates; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-terminal.adb000066400000000000000000000332501425465243200231740ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Text_IO; use Ada.Text_IO; with GNAT.OS_Lib; use GNAT.OS_Lib; package body GNATCOLL.Terminal is On_Windows : constant Boolean := GNAT.OS_Lib.Directory_Separator = '\'; Color_To_Win32 : constant array (ANSI_Color) of Integer := (Unchanged => -1, Black => 0, Red => 4, Green => 2, Yellow => 6, Blue => 1, Magenta => 5, Cyan => 3, Grey => 7, Reset => -1); Style_To_Win32 : constant array (ANSI_Style) of Integer := (Unchanged => -1, Bright => 16#08#, Dim => 16#00#, -- same as Normal Normal => 16#00#, Reset_All => -1); procedure Win_Set_Console (Self : Terminal_Info'Class; Attrs : Integer); -- Windows-specific implementation to change the attributes of the console procedure Decode_Windows_Attributes (Self : in out Terminal_Info'Class; Attrs : Integer); -- Decode the value of the attributes returned by Windows, into the -- default parameters for the terminal. procedure Auto_Detect_Colors (Self : in out Terminal_Info'Class; Support : Supports_Color); -- Auto-detect whether colors are supported function getConsoleScreenBufferInfo (Stderr : Integer) return Integer; pragma Import (C, getConsoleScreenBufferInfo, "gnatcoll_get_console_screen_buffer_info"); function terminal_has_colors (Fd : File_Descriptor) return Integer; pragma Import (C, terminal_has_colors, "gnatcoll_terminal_has_colors"); -- Whether Fd is a terminal that supports color output ------------------------------- -- Decode_Windows_Attributes -- ------------------------------- procedure Decode_Windows_Attributes (Self : in out Terminal_Info'Class; Attrs : Integer) is type Mod_32 is mod 2 ** 32; A : Mod_32; begin Self.Default_Fore := Black; Self.Default_Back := Grey; Self.Default_Style := Normal; if not On_Windows then return; elsif Attrs = -1 then Self.Colors := Unsupported; else A := Mod_32 (Attrs); case A and 7 is when 0 => Self.Default_Fore := Black; when 1 => Self.Default_Fore := Blue; when 2 => Self.Default_Fore := Green; when 3 => Self.Default_Fore := Cyan; when 4 => Self.Default_Fore := Red; when 5 => Self.Default_Fore := Magenta; when 6 => Self.Default_Fore := Yellow; when others => Self.Default_Fore := Grey; end case; case (A / 16) and 7 is when 0 => Self.Default_Back := Black; when 1 => Self.Default_Back := Blue; when 2 => Self.Default_Back := Green; when 3 => Self.Default_Back := Cyan; when 4 => Self.Default_Back := Red; when 5 => Self.Default_Back := Magenta; when 6 => Self.Default_Back := Yellow; when others => Self.Default_Back := Grey; end case; if (A and 16#08#) /= 0 then Self.Default_Style := Bright; else Self.Default_Style := Normal; end if; end if; end Decode_Windows_Attributes; ------------------------ -- Auto_Detect_Colors -- ------------------------ procedure Auto_Detect_Colors (Self : in out Terminal_Info'Class; Support : Supports_Color) is Env : String_Access; procedure Set_Color_Support; -- Set appropriate color support depend on environment ----------------------- -- Set_Color_Support -- ----------------------- procedure Set_Color_Support is begin if On_Windows then Env := Getenv ("ANSICON"); if Env = null or else Env.all = "" then Self.Colors := WIN32_Sequences; else Self.Colors := ANSI_Sequences; end if; Free (Env); else Self.Colors := ANSI_Sequences; end if; end Set_Color_Support; begin case Support is when No => Self.Colors := Unsupported; when Yes => Set_Color_Support; when Auto => if (Self.FD = Stdout and then terminal_has_colors (Standout) /= 0) or else (Self.FD = Stderr and then terminal_has_colors (Standerr) /= 0) then Set_Color_Support; else Self.Colors := Unsupported; end if; end case; end Auto_Detect_Colors; --------------------- -- Init_For_Stdout -- --------------------- procedure Init_For_Stdout (Self : in out Terminal_Info; Colors : Supports_Color := Auto) is begin Self.FD := Stdout; Auto_Detect_Colors (Self, Colors); Decode_Windows_Attributes (Self, getConsoleScreenBufferInfo (Stderr => 0)); end Init_For_Stdout; --------------------- -- Init_For_Stderr -- --------------------- procedure Init_For_Stderr (Self : in out Terminal_Info; Colors : Supports_Color := Auto) is begin Self.FD := Stderr; Auto_Detect_Colors (Self, Colors); Decode_Windows_Attributes (Self, getConsoleScreenBufferInfo (Stderr => 1)); end Init_For_Stderr; ------------------- -- Init_For_File -- ------------------- procedure Init_For_File (Self : in out Terminal_Info; Colors : Supports_Color := Auto) is begin Self.FD := File; case Colors is when Yes => -- Have to use ANSI sequences, since WIN32 sequences call -- subprograms on the terminal itself. Self.Colors := ANSI_Sequences; when No | Auto => Self.Colors := Unsupported; end case; end Init_For_File; ---------------- -- Has_Colors -- ---------------- function Has_Colors (Self : Terminal_Info) return Boolean is begin return Self.Colors /= Unsupported; end Has_Colors; --------------------- -- Has_ANSI_Colors -- --------------------- function Has_ANSI_Colors (Self : Terminal_Info) return Boolean is begin return Self.Colors = ANSI_Sequences; end Has_ANSI_Colors; --------------------- -- Win_Set_Console -- --------------------- procedure Win_Set_Console (Self : Terminal_Info'Class; Attrs : Integer) is procedure Set_Console_Text_Attribute (Stderr : Integer; Attrs : Integer); pragma Import (C, Set_Console_Text_Attribute, "gnatcoll_set_console_text_attribute"); begin Set_Console_Text_Attribute (Boolean'Pos (Self.FD = Stderr), Attrs); end Win_Set_Console; ------------ -- Set_Fg -- ------------ procedure Set_Fg (Self : in out Terminal_Info; Color : ANSI_Color; Term : Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output) is begin Set_Color (Self, Term, Color, Unchanged, Unchanged); end Set_Fg; ------------ -- Set_Bg -- ------------ procedure Set_Bg (Self : in out Terminal_Info; Color : ANSI_Color; Term : Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output) is begin Set_Color (Self, Term, Unchanged, Color, Unchanged); end Set_Bg; --------------- -- Set_Style -- --------------- procedure Set_Style (Self : in out Terminal_Info; Style : ANSI_Style; Term : Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output) is begin Set_Color (Self, Term, Unchanged, Unchanged, Style); end Set_Style; ----------------------- -- Get_ANSI_Sequence -- ----------------------- function Get_ANSI_Sequence (Style : Full_Style) return String is begin return (case Style.Style is when Unchanged => "", when Bright => ASCII.ESC & "[1m", when Dim => ASCII.ESC & "[2m", when Normal => ASCII.ESC & "[22m", when Reset_All => ASCII.ESC & "[0m" ) & (case Style.Fg is when Unchanged => "", when Black => ASCII.ESC & "[30m", when Red => ASCII.ESC & "[31m", when Green => ASCII.ESC & "[32m", when Yellow => ASCII.ESC & "[33m", when Blue => ASCII.ESC & "[34m", when Magenta => ASCII.ESC & "[35m", when Cyan => ASCII.ESC & "[36m", when Grey => ASCII.ESC & "[37m", when Reset => ASCII.ESC & "[39m" ) & (case Style.Bg is when Unchanged => "", when Black => ASCII.ESC & "[40m", when Red => ASCII.ESC & "[41m", when Green => ASCII.ESC & "[42m", when Yellow => ASCII.ESC & "[43m", when Blue => ASCII.ESC & "[44m", when Magenta => ASCII.ESC & "[45m", when Cyan => ASCII.ESC & "[46m", when Grey => ASCII.ESC & "[47m", when Reset => ASCII.ESC & "[49m" ); end Get_ANSI_Sequence; --------------- -- Set_Color -- --------------- procedure Set_Color (Self : in out Terminal_Info; Term : Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output; Foreground : ANSI_Color := Unchanged; Background : ANSI_Color := Unchanged; Style : ANSI_Style := Unchanged) is Attrs : Integer := 0; begin case Self.Colors is when Unsupported => null; when ANSI_Sequences => Put (Term, Get_ANSI_Sequence ((Fg => Foreground, Bg => Background, Style => Style))); when WIN32_Sequences => if Style = Reset_All then Self.Style := Self.Default_Style; Self.Fore := Self.Default_Fore; Self.Back := Self.Default_Back; elsif Style /= Unchanged then Self.Style := Style; end if; if Foreground = Reset then Self.Fore := Self.Default_Fore; elsif Foreground /= Unchanged then Self.Fore := Foreground; end if; if Background = Reset then Self.Back := Self.Default_Back; elsif Background /= Unchanged then Self.Back := Background; end if; Attrs := Attrs + Style_To_Win32 (Self.Style) + Color_To_Win32 (Self.Fore) + Color_To_Win32 (Self.Back) * 16; Win_Set_Console (Self, Attrs); end case; end Set_Color; ----------------------- -- Beginning_Of_Line -- ----------------------- procedure Beginning_Of_Line (Self : in out Terminal_Info) is procedure Internal (Stderr : Integer); pragma Import (C, Internal, "gnatcoll_beginning_of_line"); begin if Self.FD = File or else Self.Colors = Unsupported then null; else Internal (Boolean'Pos (Self.FD = Stderr)); end if; end Beginning_Of_Line; -------------------------- -- Clear_To_End_Of_Line -- -------------------------- procedure Clear_To_End_Of_Line (Self : in out Terminal_Info) is procedure Internal (Stderr : Integer); pragma Import (C, Internal, "gnatcoll_clear_to_end_of_line"); begin if Self.FD = File or else Self.Colors = Unsupported then null; else Internal (Boolean'Pos (Self.FD = Stderr)); end if; end Clear_To_End_Of_Line; --------------- -- Get_Width -- --------------- function Get_Width (Self : Terminal_Info) return Integer is function Internal (Stderr : Integer) return Integer; pragma Import (C, Internal, "gnatcoll_terminal_width"); begin if Self.FD = File or else Self.Colors = Unsupported then return -1; else return Internal (Boolean'Pos (Self.FD = Stderr)); end if; end Get_Width; end GNATCOLL.Terminal; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-terminal.ads000066400000000000000000000167371425465243200232300ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2014-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package provides a number of cross-platform subprograms to control -- output in terminals, in particular colors. -- -- On Windows, color sequences are either set using the standard WIN32 codes, -- or if the package ANSICON (https://github.com/adoxa/ansicon/) is running it -- will use the standard ANSI sequences. with Ada.Text_IO; package GNATCOLL.Terminal is type Terminal_Info is tagged private; type Terminal_Info_Access is access all Terminal_Info'Class; -- Information about a terminal on which we output. -- This structure does not encapsulate the terminal itself, which is a -- limited type. -- By default, this is configured without support for colors. It is thus -- recommended to first call Init before you use this type. -- This type is almost always used in conjunction with a File_Type, which -- is where text is actually output. The properties of that File_Type are -- queried and cached in the Terminal_Info. ------------ -- Colors -- ------------ type Supports_Color is (Yes, No, Auto); procedure Init_For_Stdout (Self : in out Terminal_Info; Colors : Supports_Color := Auto); procedure Init_For_Stderr (Self : in out Terminal_Info; Colors : Supports_Color := Auto); procedure Init_For_File (Self : in out Terminal_Info; Colors : Supports_Color := Auto); -- Checks whether the terminal supports colors. By default, automatic -- detection is attempted, but this can be overridden by the use of the -- Colors parameter. -- The three variants depend on which type of terminal you are outputting -- to. Unfortunately, the type Ada.Text_IO.File_Type is opaque and it is -- not possible to check what is applies to, or what are the properties of -- the underling file handle. function Has_Colors (Self : Terminal_Info) return Boolean; -- Whether the terminals supports colors. function Has_ANSI_Colors (Self : Terminal_Info) return Boolean; -- Whether the terminal supports ANSI escape sequences for colors. -- On Windows, it is possible for a terminal to support colors, but not -- ANSI sequences. This package will take care of doing the appropriate -- system calls to setup colors, but if you want to directly output -- ANSI sequences that will not work. type ANSI_Color is (Unchanged, Black, Red, Green, Yellow, Blue, Magenta, Cyan, Grey, Reset); -- The colors that can be output in a terminal (ANSI definitions). The -- actual color that the user will see might be different, since a terminal -- might associate a different color to the same escape sequence. type ANSI_Style is (Unchanged, Bright, Dim, Normal, Reset_All); -- The style for the text. Some styles are not supported on some -- terminals, like Dim on the Windows console. procedure Set_Color (Self : in out Terminal_Info; Term : Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output; Foreground : ANSI_Color := Unchanged; Background : ANSI_Color := Unchanged; Style : ANSI_Style := Unchanged); -- Change the colors that will be used for subsequent output on the -- terminal. -- This procedure has no effect if Has_Colors returns False. -- In general, it is not recommended to output colors to files, so you -- should not use Set_Color in such a context. procedure Set_Fg (Self : in out Terminal_Info; Color : ANSI_Color; Term : Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output); procedure Set_Bg (Self : in out Terminal_Info; Color : ANSI_Color; Term : Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output); procedure Set_Style (Self : in out Terminal_Info; Style : ANSI_Style; Term : Ada.Text_IO.File_Type := Ada.Text_IO.Standard_Output); -- Override specific colors. ------------- -- Cursors -- ------------- procedure Beginning_Of_Line (Self : in out Terminal_Info); -- Move the cursor back to the beginning of the line. -- This has no impact on files, only in interactive terminals. procedure Clear_To_End_Of_Line (Self : in out Terminal_Info); -- Delete from the cursor position to the end of line function Get_Width (Self : Terminal_Info) return Integer; -- Return the width of the terminal, or -1 if that width is either -- unknown or does not apply (as is the case for files for instance). ----------- -- Utils -- ----------- type Full_Style is record Fg : ANSI_Color := Unchanged; Bg : ANSI_Color := Unchanged; Style : ANSI_Style := Unchanged; end record; -- A convenient record to group all style-related attributes function Get_ANSI_Sequence (Style : Full_Style) return String; -- Append the ANSI escape sequence representing the style. -- Note that these sequences are not supported by all terminals, see -- Has_ANSI_Colors. private type Color_Sequence_Type is (Unsupported, ANSI_Sequences, WIN32_Sequences); type FD_Type is (Stdout, Stderr, File); -- What type of file descriptor the terminal_info applies to. type Terminal_Info is tagged record Colors : Color_Sequence_Type := Unsupported; Fore : ANSI_Color := Black; Back : ANSI_Color := Grey; Style : ANSI_Style := Normal; -- Current attributes (on Windows, all three must be changed at the -- same time) Default_Fore : ANSI_Color := Black; Default_Back : ANSI_Color := Grey; Default_Style : ANSI_Style := Normal; -- Default windows attributes (computed in Init) FD : FD_Type := Stdout; -- Whether the associated terminal is stdout (windows only) end record; end GNATCOLL.Terminal; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-traces.adb000066400000000000000000002061341425465243200226450ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2001-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ pragma Ada_2012; with Ada.Calendar; use Ada.Calendar; with Ada.Calendar.Formatting; use Ada.Calendar.Formatting; with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones; with Ada.Environment_Variables; with Ada.Strings.Fixed; use Ada.Strings.Fixed; with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback; with Ada.IO_Exceptions; with Ada.Unchecked_Deallocation; with GNAT.Calendar.Time_IO; use GNAT.Calendar.Time_IO; with GNAT.OS_Lib; use GNAT.OS_Lib; with GNAT.Regpat; use GNAT.Regpat; with GNAT.Traceback; use GNAT.Traceback; with Interfaces.C_Streams; use Interfaces.C_Streams; with System.Address_Image; with System.Assertions; use System.Assertions; with GNATCOLL.Memory; with GNATCOLL.Mmap; use GNATCOLL.Mmap; with GNATCOLL.Templates; with GNATCOLL.Utils; use GNATCOLL.Utils; package body GNATCOLL.Traces is use type FILEs, size_t; use type GNATCOLL.Terminal.ANSI_Color, GNATCOLL.Terminal.ANSI_Style; use type GNATCOLL.Terminal.Full_Style; Max_Active_Decorators : constant := 40; -- Maximum number of active iterators On_Exception : On_Exception_Mode := Propagate; -- The behavior that should be adopted when something unexpected prevent -- the log stream to be written. -- Note: rev 1.5 of this file has a (disabled) support for symbolic -- tracebacks. -- ??? We could display the stack pointer with -- procedure Print_Sp is -- start : aliased Integer; -- begin -- Put_Line (System.Address_Image (Start'Address)); -- end; A_Zero : aliased constant String := "a" & ASCII.NUL; W_Zero : aliased constant String := "w" & ASCII.NUL; Reset_All : constant String := GNATCOLL.Terminal.Get_ANSI_Sequence ((Style => GNATCOLL.Terminal.Reset_All, Fg => GNATCOLL.Terminal.Unchanged, Bg => GNATCOLL.Terminal.Unchanged)); Default_Style : constant Message_Style := (Fg => GNATCOLL.Terminal.Reset, Bg => GNATCOLL.Terminal.Unchanged, Style => GNATCOLL.Terminal.Unchanged); -- The default style used for handles. This uses the terminal's -- default foreground. Default_Exception_Style : constant Message_Style := (Fg => GNATCOLL.Terminal.Black, Bg => GNATCOLL.Terminal.Red, Style => GNATCOLL.Terminal.Unchanged); -- Highlight with a red background. -- This is used to report unexpected exceptions when an exception -- occurrence is passed to Trace. type Decorator_Array is array (1 .. Max_Active_Decorators) of Trace_Decorator; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Trace_Handle_Record'Class, Trace_Handle); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Trace_Stream_Record'Class, Trace_Stream); type Stream_Factories; type Stream_Factories_List is access Stream_Factories; type Stream_Factories is record Name : GNAT.Strings.String_Access; Factory : Stream_Factory_Access; Next : Stream_Factories_List; end record; procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Stream_Factories, Stream_Factories_List); procedure Unchecked_Free is new Ada.Unchecked_Deallocation (Stream_Factory'Class, Stream_Factory_Access); type Global_Vars is record Handles_List : Trace_Handle := null; -- The global list of all defined handles. Active_Decorators : Decorator_Array; Active_Last : Natural := 0; -- Never null after parsing the config file. -- Decorators on this list are all active, and also stored in the -- Handles_List. Wildcard_Handles_List : Trace_Handle := null; -- Contains the configuration for module names containing stars, for -- instance "*.EXCEPTIONS". Streams_List : Trace_Stream := null; -- The global list of all streams. -- The default stream is the first in the list. Factories_List : Stream_Factories_List := null; -- The global list of all factories. TZ : Time_Offset := UTC_Time_Offset; -- Time zone cache, assuming that the OS will not change time zones -- while this partition is running. Lock : aliased Atomic_Counter := 0; pragma Atomic (Lock); Absolute_Time : Trace_Decorator; Absolute_Date : Trace_Decorator; Micro_Time : Trace_Decorator; Colors : Trace_Decorator; Enclosing_Entity : Trace_Decorator; Location : Trace_Decorator; Finalize_Traces : Trace_Decorator; Split_Lines : Trace_Decorator; -- The predefined decorators. -- ??? These are also stored in the lists above, so we might not need -- them. Default_Activation : Boolean := False; -- Default activation status for debug handles (ie whether the -- configuration file contained "+"). -- ??? Could be handled via a "*" star handle Finalized : Boolean := False; -- Whether the package has been finalized. -- When this is true, some trace_handles will have been freed, and it -- is therefore illegal to access them. end record; Global : Global_Vars; type Elapse_Time_Trace is new Trace_Decorator_Record with null record; overriding procedure After_Message (Self : in out Elapse_Time_Trace; Handle : not null Logger; Msg : in out Msg_Strings.XString); type Stack_Trace is new Trace_Decorator_Record with null record; overriding procedure After_Message (Self : in out Stack_Trace; Handle : not null Logger; Msg : in out Msg_Strings.XString); type Count_Trace is new Trace_Decorator_Record with null record; overriding procedure Before_Message (Self : in out Count_Trace; Handle : not null Logger; Msg : in out Msg_Strings.XString); type Memory_Trace is new Trace_Decorator_Record with record Previous : GNATCOLL.Memory.Byte_Count := 0; end record; overriding procedure After_Message (Self : in out Memory_Trace; Handle : not null Logger; Msg : in out Msg_Strings.XString); type Ada_Memory_Trace is new Trace_Decorator_Record with record Previous : GNATCOLL.Memory.Byte_Count := 0; end record; overriding procedure After_Message (Self : in out Ada_Memory_Trace; Handle : not null Logger; Msg : in out Msg_Strings.XString); procedure Lock (The_Lock : aliased in out Atomic_Counter) with Inline_Always; procedure Unlock (The_Lock : aliased in out Atomic_Counter) with Inline_Always; -- For critical regions. A thread already owning the lock cannot try to -- take the lock again, or it will block. procedure Create_Exception_Handle (Handle : not null Trace_Handle); -- Create the exception handle associated with Handle. function Local_Sub_Second (T : Ada.Calendar.Time) return Integer; pragma Inline (Local_Sub_Second); -- Version of Local_Sub_Second taking advantage of the timezone cache -- return values in range 0 .. 999 function Find_Handle (Handle : Trace_Handle; Name_Upper_Case : String) return Trace_Handle; -- Return the debug handle associated with Unit_Name_Upper_Case, -- or null if there is none. The case of Unit_Name_Upper_Case is -- not changed. -- Note: this subprogram doesn't do any locking, it is the -- responsability of the called to make sure that not two tasks -- can access it at the same time. function Find_Wildcard_Handle (Unit_Name_Upper_Case : String) return Trace_Handle; -- Check whether there is a module name that contains a "*" and that can be -- used to provide the default configuration for Unit_Name_Upper_Case function Wildcard_Applies_To (Upper_Name : String; Upper_Star : String) return Boolean; -- Whether the module Upper_Name should take its default configuration from -- Upper_Wildcard_Name. function Find_Stream (Stream_Name : String; Relative_Path_To : Virtual_File; Append : Boolean) return Trace_Stream; -- Return the stream associated with that name (either an existing one or -- one created by a factory), or null if the default stream should be -- applied. -- The Stream_Name might include the settings for the stream, as in: -- "file.txt:buffer_size=0,async=true" procedure Put_Absolute_Time (Msg : in out Msg_Strings.XString); -- Print the absolute time in Handle. No locking is done, this is the -- responsability of the caller. No colors is modified either. function Config_File (Filename : Virtual_File; Default : Virtual_File) return Virtual_File; -- Return the name of the config file to use. -- If Filename is specified, this is the file to use, providing it exists. -- Otherwise, we use a .gnatdebug in the current directory, and if there is -- none, Default if it exists. -- The empty string is returned if no such file was found. procedure Register_Handle (Handle : not null Trace_Handle; Upper_Case : String; Finalize : Boolean := True); -- add Handle to the internal list and set default fields function Create_Internal (Unit_Name : String; Default : Default_Activation_Status := From_Config; Stream : Trace_Stream; Factory : Handle_Factory := null; Finalize : Boolean := True; Style : Message_Style; From_Config_File : Boolean) return Trace_Handle; -- Internal version of Create function Get_Process_Id return Integer; -- Return the process ID of the current process pragma Import (C, Get_Process_Id, "getpid"); type File_Stream_Record is new Trace_Stream_Record with record File : FILEs := NULL_Stream; Lock : aliased GNATCOLL.Atomic.Atomic_Counter := 0; Colors_Support : Boolean; end record; overriding procedure Put (Stream : in out File_Stream_Record; Str : Msg_Strings.XString); overriding procedure Close (Stream : in out File_Stream_Record); overriding function Supports_Color (Self : File_Stream_Record) return Boolean is (Self.Colors_Support); -- Logs to a file procedure Cache_Settings (Handle : not null Trace_Handle); -- Cache various settings in Handle, to avoid dispatching calls in Log -- and thus speed things up. -- These settings are changed much less frequently. ---------- -- Lock -- ---------- procedure Lock (The_Lock : aliased in out Atomic_Counter) is begin while True loop -- In this package, the lock is owned during the time it takes -- to Put a string to a stream (async streams go even faster). -- It doesn't seem worth adding a "delay" in this loop, though -- the standard implementation would be to have a delay on a -- random number, and increase the delay every time we have to -- loop until a given maximum. while The_Lock /= 0 loop null; end loop; exit when Sync_Add_And_Fetch (The_Lock'Unchecked_Access, 1) = 1; end loop; end Lock; ------------ -- Unlock -- ------------ procedure Unlock (The_Lock : aliased in out Atomic_Counter) is begin The_Lock := 0; end Unlock; ----------------- -- Find_Handle -- ----------------- function Find_Handle (Handle : Trace_Handle; Name_Upper_Case : String) return Trace_Handle is Tmp : Trace_Handle := Handle; begin while Tmp /= null and then Tmp.Name.all /= Name_Upper_Case loop Tmp := Tmp.Next; end loop; return Tmp; end Find_Handle; ------------------------- -- Wildcard_Applies_To -- ------------------------- function Wildcard_Applies_To (Upper_Name : String; Upper_Star : String) return Boolean is begin if Upper_Star (Upper_Star'First) = '*' then -- Test must include '.' in the suffix if Ends_With (Upper_Name, Upper_Star (Upper_Star'First + 1 .. Upper_Star'Last)) then return True; end if; elsif Upper_Star (Upper_Star'Last) = '*' then -- "MODULE.*" should include "MODULE" itself if Upper_Name = Upper_Star (Upper_Star'First .. Upper_Star'Last - 2) then return True; end if; -- Otherwise "MODULE.*" should match "MODULE.FOO" but not -- MODULEFOO.BAR if Starts_With (Upper_Name, Upper_Star (Upper_Star'First .. Upper_Star'Last - 1)) then return True; end if; end if; return False; end Wildcard_Applies_To; -------------------------- -- Find_Wildcard_Handle -- -------------------------- function Find_Wildcard_Handle (Unit_Name_Upper_Case : String) return Trace_Handle is Tmp : Trace_Handle := Global.Wildcard_Handles_List; begin while Tmp /= null loop if Wildcard_Applies_To (Upper_Name => Unit_Name_Upper_Case, Upper_Star => Tmp.Name.all) then return Tmp; end if; Tmp := Tmp.Next; end loop; return null; end Find_Wildcard_Handle; ------------------------ -- Show_Configuration -- ------------------------ procedure Show_Configuration (Output : Output_Proc) is Tmp : Trace_Handle := Global.Handles_List; function Stream_Name return String; -- Return the name of the stream if there is one function Stream_Name return String is begin if Tmp.Stream /= null and then Tmp.Stream /= Global.Streams_List then return " >" & Tmp.Stream.Name.all; else return ""; end if; end Stream_Name; begin if Global.Streams_List /= null then Output ("> " & Global.Streams_List.Name.all); end if; while Tmp /= null loop if Tmp.Active then Output (Tmp.Name.all & "=yes" & Stream_Name); elsif Tmp.all not in Trace_Decorator_Record'Class then -- Only output decorators when they are active Output (Tmp.Name.all & "=no" & Stream_Name); end if; Tmp := Tmp.Next; end loop; end Show_Configuration; ----------------- -- Find_Stream -- ----------------- function Find_Stream (Stream_Name : String; Relative_Path_To : Virtual_File; Append : Boolean) return Trace_Stream is procedure Add_To_Streams (Tmp : Trace_Stream); -------------------- -- Add_To_Streams -- -------------------- procedure Add_To_Streams (Tmp : Trace_Stream) is begin -- ??? Could use atomic operations to manipulate the -- list directly. Lock (Global.Lock); -- If possible, do not put this first on the list of streams, -- since it would become the default stream if Global.Streams_List = null then Global.Streams_List := Tmp; Tmp.Next := null; else Tmp.Next := Global.Streams_List.Next; Global.Streams_List.Next := Tmp; end if; Unlock (Global.Lock); end Add_To_Streams; Name : constant String := Trim (Stream_Name, Ada.Strings.Both); Tmp : Trace_Stream; Colon : Natural; TmpF : Stream_Factories_List; Default_Colors : GNATCOLL.Terminal.Supports_Color := GNATCOLL.Terminal.Auto; Term : GNATCOLL.Terminal.Terminal_Info; Supports_Buffer : Boolean := True; Buf_Size : size_t := 2**10; begin if Name = "" then return null; end if; -- Do we have a matching existing stream? -- Since we use a linked list and never remove elements from -- the list, we do not need locking. Tmp := Global.Streams_List; while Tmp /= null loop if Tmp.Name.all = Name then return Tmp; end if; Tmp := Tmp.Next; end loop; -- Parse stream options Colon := Index (Name, ":"); if Colon < Name'First then Colon := Name'Last + 1; end if; declare Args : String_List_Access := Split (Name, ':'); begin for A of Args (Args'First + 1 .. Args'Last) loop if Starts_With (A.all, "buffer_size=") then begin Buf_Size := size_t'Value (A (A'First + 12 .. A'Last)); exception when others => Buf_Size := 2**10; end; elsif Starts_With (A.all, "colors=") then declare V : constant String := To_Lower (A (A'First + 7 .. A'Last)); begin if V = "on" or else V = "true" then Default_Colors := GNATCOLL.Terminal.Yes; elsif V = "off" or else V = "false" then Default_Colors := GNATCOLL.Terminal.No; else Default_Colors := GNATCOLL.Terminal.Auto; end if; end; end if; end loop; Free (Args); end; -- Do we have a matching factory (if we start with "&")? if Name (Name'First .. Colon - 1) = "&1" then Term.Init_For_Stdout (Colors => Default_Colors); Tmp := new File_Stream_Record' (Name => new String'(Name), File => stdout, Colors_Support => Term.Has_ANSI_Colors, others => <>); Add_To_Streams (Tmp); Supports_Buffer := False; elsif Name (Name'First .. Colon - 1) = "&2" then Term.Init_For_Stderr (Colors => Default_Colors); Tmp := new File_Stream_Record' (Name => new String'(Name), File => stderr, Colors_Support => Term.Has_ANSI_Colors, others => <>); Add_To_Streams (Tmp); Supports_Buffer := False; elsif Name (Name'First) = '&' then Tmp := null; TmpF := Global.Factories_List; while TmpF /= null loop if TmpF.Name.all = Name (Name'First .. Colon - 1) then if Colon < Name'Last then Tmp := TmpF.Factory.New_Stream (Name (Colon + 1 .. Name'Last)); else Tmp := TmpF.Factory.New_Stream (""); end if; Tmp.Name := new String'(Name); Add_To_Streams (Tmp); exit; end if; TmpF := TmpF.Next; end loop; else declare use GNATCOLL.Templates; Now : constant Ada.Calendar.Time := Clock; Nam_Dollar : aliased String := "$"; Val_Dollar : aliased String := Trim (Get_Process_Id'Img, Ada.Strings.Both); Nam_D : aliased String := "D"; Val_D : aliased String := Image (Now, ISO_Date); Nam_T : aliased String := "T"; Val_T : aliased String := Val_D & Image (Now, "T%H%M%S"); Predef_Substitutions : constant Substitution_Array := ((Name => Nam_Dollar'Unchecked_Access, Value => Val_Dollar'Unchecked_Access), (Name => Nam_D'Unchecked_Access, Value => Val_D'Unchecked_Access), (Name => Nam_T'Unchecked_Access, Value => Val_T'Unchecked_Access)); function Substitute_Cb (Var : String; Quoted : Boolean) return String; -- Callback for variable substitution in Name -------------------- -- Substitute_Cb -- -------------------- function Substitute_Cb (Var : String; Quoted : Boolean) return String is pragma Unreferenced (Quoted); use Ada.Environment_Variables; begin if Exists (Var) then return Value (Var); end if; raise Invalid_Substitution; end Substitute_Cb; N : constant String := Normalize_Pathname (Substitute (Str => Name (Name'First .. Colon - 1), Substrings => Predef_Substitutions, Callback => Substitute_Cb'Unrestricted_Access, Delimiter => '$'), +Relative_Path_To.Full_Name.all); N_Zero : aliased constant String := N & ASCII.NUL; F : FILEs; begin if Append then F := fopen (N_Zero'Address, mode => A_Zero'Address); else F := fopen (N_Zero'Address, mode => W_Zero'Address); end if; if F = NULL_Stream then F := stderr; end if; Term.Init_For_File (Colors => Default_Colors); Tmp := new File_Stream_Record' (Name => new String'(Name), File => F, Colors_Support => Term.Has_ANSI_Colors, others => <>); Add_To_Streams (Tmp); end; end if; if Tmp /= null and then Tmp.all in File_Stream_Record'Class and then Supports_Buffer then declare Dummy : int; begin Dummy := setvbuf (File_Stream_Record (Tmp.all).File, System.Null_Address, (case Buf_Size is when 0 => IONBF, -- unbuffered when 1 => IOLBF, -- line buffered when others => IOFBF), -- full buffered Buf_Size); end; end if; -- Else use the default stream return Tmp; end Find_Stream; ------------ -- Create -- ------------ function Create (Unit_Name : String; Default : Default_Activation_Status := From_Config; Stream : String := ""; Factory : Handle_Factory := null; Finalize : Boolean := True) return Trace_Handle is begin return Create_Internal (From_Config_File => False, Unit_Name => Unit_Name, Default => Default, Stream => Find_Stream (Stream, No_File, Append => False), Factory => Factory, Style => Default_Style, Finalize => Finalize); end Create; --------------------- -- Create_Internal -- --------------------- function Create_Internal (Unit_Name : String; Default : Default_Activation_Status := From_Config; Stream : Trace_Stream; Factory : Handle_Factory := null; Finalize : Boolean := True; Style : Message_Style; From_Config_File : Boolean) return Trace_Handle is Is_Star : constant Boolean := Starts_With (Unit_Name, "*.") or else Ends_With (Unit_Name, ".*"); Handle : Trace_Handle; Upper_Case : constant String := To_Upper (Unit_Name); Tmp2 : Trace_Handle; Wildcard : Trace_Handle; begin -- Do we already have an existing handle ? Handle := Find_Handle ((if Is_Star then Global.Wildcard_Handles_List else Global.Handles_List), Upper_Case); if Handle = null then if Factory /= null then Handle := Factory.all; end if; if Handle = null then Handle := new Trace_Handle_Record; end if; Register_Handle (Handle => Handle, Upper_Case => Upper_Case, Finalize => Finalize); -- Unless both settings are already known, check if we have a -- wildcard. if (Default = From_Config or else Stream = null) and then not Is_Star then Wildcard := Find_Wildcard_Handle (Handle.Name.all); if Wildcard /= null then Set_Active (Handle, Wildcard.Active); Handle.Forced_Active := True; -- Unless we specified an explicit stream, inherit it if Stream = null and then Wildcard.Stream /= null then Handle.Stream := Wildcard.Stream; Handle.Stream_Is_Default := Wildcard.Stream_Is_Default; end if; else Set_Active (Handle, Global.Default_Activation); end if; end if; end if; if Stream /= null then -- Only override when we are parsing the configuration file, so -- that if we have the following: -- Me : Trace_Handle := Create ("ME", Stream => "str1"); -- parse config file, which contains "ME=yes >str2" -- Me := Create ("ME", Stream => "str3") -- then "ME" is sent to "str2" (priority is given to the config -- file. if From_Config_File or else Handle.Stream_Is_Default then Handle.Stream := Stream; Handle.Stream_Is_Default := False; end if; -- A wildcard only impacts the stream of loggers if it has its own -- stream. elsif not Is_Star then -- Use the default stream. If we are still parsing the config -- file, we might not have this info yet, so we set Stream to -- 'null' and it will be overridden later if not From_Config_File and then Handle.Stream_Is_Default then Handle.Stream := Global.Streams_List; Handle.Stream_Is_Default := True; end if; end if; -- Set activation if not Handle.Forced_Active or else From_Config_File then case Default is when On => Handle.Forced_Active := True; Set_Active (Handle, Active => True); when Off => Handle.Forced_Active := True; Set_Active (Handle, Active => False); when From_Config => null; end case; end if; -- If we are declaring a "wildcard" handle, we need to check -- whether any existing handle would match (which will in -- general be the case, since handles are declared at -- elaboration time and star handles in the config file). if Is_Star then Tmp2 := Global.Handles_List; while Tmp2 /= null loop if Wildcard_Applies_To (Tmp2.Name.all, Upper_Star => Handle.Name.all) then -- Always override the status of matching streams: -- There are two scenarios here: -- - in a given config file, we always respect the order -- of declarations, thus wildcards should in general be put -- at the beginning. -- - if a wildcard is declared later on in Ada, we want -- it to impact existing streams as well (as a convenience -- for forcing specific settings from the code. -- -- So do not check Tmp2.Forced_Active Set_Active (Tmp2, Handle.Active); if Style /= Use_Default_Style and then Tmp2.Default_Style = Default_Style then Tmp2.Default_Style := Style; end if; if Tmp2.Stream_Is_Default and then Handle.Stream /= null then Tmp2.Stream := Handle.Stream; Tmp2.Stream_Is_Default := Handle.Stream_Is_Default; end if; end if; Tmp2 := Tmp2.Next; end loop; end if; if Style /= Use_Default_Style then Handle.Default_Style := Style; end if; Cache_Settings (Handle); return Handle; end Create_Internal; -------------------- -- Cache_Settings -- -------------------- procedure Cache_Settings (Handle : not null Trace_Handle) is begin -- If we have already registered the default decorators if Global.Colors /= null and then Handle.Stream /= null then Handle.With_Time := (Global.Absolute_Time.Active or else Global.Absolute_Date.Active) and then Handle.Stream.Supports_Time; Handle.With_Colors := Global.Colors.Active and then Handle.Stream.Supports_Color; end if; end Cache_Settings; --------------------- -- Register_Handle -- --------------------- procedure Register_Handle (Handle : not null Trace_Handle; Upper_Case : String; Finalize : Boolean := True) is Is_Star : constant Boolean := Starts_With (Upper_Case, "*.") or else Ends_With (Upper_Case, ".*"); begin Handle.Name := new String'(Upper_Case); Handle.Forced_Active := False; Handle.Count := 0; Handle.Timer := No_Time; Handle.Finalize := Finalize; Handle.Active := False; Handle.Stream_Is_Default := True; Lock (Global.Lock); if Is_Star then Handle.Next := Global.Wildcard_Handles_List; Global.Wildcard_Handles_List := Handle; else Handle.Next := Global.Handles_List; Global.Handles_List := Handle; end if; Unlock (Global.Lock); exception when others => Unlock (Global.Lock); raise; end Register_Handle; ---------------- -- Set_Active -- ---------------- procedure Set_Active (Handle : not null access Trace_Handle_Record'Class; Active : Boolean) is Tmp : Trace_Handle; Dec : Trace_Decorator; begin Handle.Active := Active; if Handle.all in Trace_Decorator_Record'Class then Dec := Trace_Decorator (Handle); if Dec /= Global.Colors and then Dec /= Global.Finalize_Traces and then Dec /= Global.Split_Lines then -- If active, store it in the list of active decorators if Active then -- ??? Should check if we have too many decorators Global.Active_Last := Global.Active_Last + 1; Global.Active_Decorators (Global.Active_Last) := Dec; else for A in 1 .. Global.Active_Last loop if Global.Active_Decorators (A) = Dec then Global.Active_Decorators (A .. Global.Active_Last - 1) := Global.Active_Decorators (A + 1 .. Global.Active_Last); Global.Active_Last := Global.Active_Last - 1; exit; end if; end loop; end if; end if; if Dec = Global.Colors or else Dec = Global.Absolute_Time or else Dec = Global.Absolute_Date then Tmp := Global.Handles_List; while Tmp /= null loop Cache_Settings (Tmp); Tmp := Tmp.Next; end loop; end if; end if; end Set_Active; --------------- -- Is_Active -- --------------- function Is_Active (Handle : not null access Trace_Handle_Record'Class) return Boolean is begin return not Global.Finalized and then Handle.Active; end Is_Active; --------------- -- Unit_Name -- --------------- function Unit_Name (Handle : not null access Trace_Handle_Record'Class) return String is begin return Handle.Name.all; end Unit_Name; ----------------------------- -- Create_Exception_Handle -- ----------------------------- procedure Create_Exception_Handle (Handle : not null Trace_Handle) is S : Trace_Stream; begin if Handle.Exception_Handle = null then -- Unless the config file specified an explicit stream, -- we inherit the one from Handle. if Handle.Stream = Global.Streams_List then S := null; else S := Handle.Stream; end if; Handle.Exception_Handle := Create_Internal (Unit_Name => Handle.Name.all & ".EXCEPTIONS", From_Config_File => False, Stream => S, Default => (if Handle.Active then On else Off), Style => Default_Exception_Style); Cache_Settings (Handle.Exception_Handle); end if; end Create_Exception_Handle; ----------- -- Trace -- ----------- procedure Trace (Handle : not null access Trace_Handle_Record'Class; E : Ada.Exceptions.Exception_Occurrence; Msg : String := "Unexpected exception: "; Color : String) is begin if Debug_Mode then if Handle.With_Colors then Trace (Handle, E, Color & Msg); else Trace (Handle, E, Msg); end if; end if; end Trace; ----------- -- Trace -- ----------- procedure Trace (Handle : not null access Trace_Handle_Record'Class; E : Ada.Exceptions.Exception_Occurrence; Msg : String := "Unexpected exception: "; Style : Message_Style := Use_Default_Style) is begin if Debug_Mode and then not Global.Finalized -- module not terminated then Create_Exception_Handle (Trace_Handle (Handle)); Trace (Handle.Exception_Handle, Msg & Ada.Exceptions.Exception_Information (E), Style => Style); end if; end Trace; ----------- -- Trace -- ----------- procedure Trace (Handle : not null access Trace_Handle_Record'Class; Message : String; Color : String; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Debug_Mode then if Handle.With_Colors then Trace (Handle, Color & Message, Location => Location, Entity => Entity); else Trace (Handle, Message, Location => Location, Entity => Entity); end if; end if; end Trace; ----------- -- Trace -- ----------- procedure Trace (Handle : not null access Trace_Handle_Record'Class; Message : String; Style : Message_Style := Use_Default_Style; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is -- We want maximum performance for traces. This saves about 2% -- in single-threaded applications and sometimes 1% for multi-threaded -- apps. pragma Suppress (All_Checks); Merged_Style : Message_Style; begin -- Do not output anything until we have called Parse_Config_File, -- and do not output anything after we have called Finalized and -- potentially freed Handle. -- The stream is null if the trace was Create-d as On by default -- but Parse_Config_File was never called. if not Active (Handle) or else Handle.Stream = null then return; end if; declare Start, Last : Natural; Indent : constant Integer := Integer (Handle.Stream.Indentation); With_Color : constant Boolean := Handle.With_Colors; Msg : Msg_Strings.XString; begin for D in 1 .. Global.Active_Last loop Global.Active_Decorators (D).Start_Of_Line (Msg, Is_Continuation => False); end loop; if Indent > 0 then Msg.Append ((1 .. Indent * 3 => ' ')); end if; if With_Color then Merged_Style := Handle.Default_Style; if Style.Fg /= GNATCOLL.Terminal.Unchanged then Merged_Style.Fg := Style.Fg; end if; if Style.Bg /= GNATCOLL.Terminal.Unchanged then Merged_Style.Bg := Style.Bg; end if; if Style.Style /= GNATCOLL.Terminal.Unchanged then Merged_Style.Style := Style.Style; end if; Msg.Append (Cyan_Fg); end if; Msg.Append ('['); Msg.Append (Handle.Name.all); Msg.Append (']'); Msg.Append (' '); -- Decorate before the message for D in 1 .. Global.Active_Last loop Global.Active_Decorators (D).Before_Message (Trace_Handle (Handle), Msg); end loop; -- Add the message if Global.Split_Lines /= null and then Global.Split_Lines.Active then Start := Message'First; loop Last := Start; while Last <= Message'Last and then Message (Last) /= ASCII.LF loop Last := Last + 1; end loop; if With_Color then Msg.Append (GNATCOLL.Terminal.Get_ANSI_Sequence (Merged_Style)); end if; Msg.Append (Message (Start .. Last - 1)); Start := Last + 1; exit when Start > Message'Last; Msg.Append (ASCII.LF); for D in 1 .. Global.Active_Last loop Global.Active_Decorators (D).Start_Of_Line (Msg, Is_Continuation => True); end loop; if Indent > 0 then Msg.Append ((1 .. Indent * 3 => ' ')); end if; if With_Color then Msg.Append (Purple_Fg); end if; Msg.Append ('_'); Msg.Append (Handle.Name.all); Msg.Append ('_'); Msg.Append (' '); end loop; else if With_Color then Msg.Append (GNATCOLL.Terminal.Get_ANSI_Sequence (Merged_Style)); end if; Msg.Append (Message); end if; -- Decorate after the message if Global.Active_Last /= 0 then if With_Color then Msg.Append (Brown_Fg); end if; Msg.Append (' '); for D in 1 .. Global.Active_Last loop Global.Active_Decorators (D).After_Message (Trace_Handle (Handle), Msg); end loop; -- Remove trailing space if needed if Handle.With_Time then Put_Absolute_Time (Msg); end if; if Global.Location.Active then Msg.Append ("(loc: "); Msg.Append (Location); Msg.Append (')'); end if; if Global.Enclosing_Entity.Active then Msg.Append ("(entity:"); Msg.Append (Entity); Msg.Append (')'); end if; Msg.Trim (Ada.Strings.Right); end if; if With_Color then Msg.Append (Reset_All); end if; Msg.Append (ASCII.LF); Handle.Stream.Put (Msg); end; exception when others => case On_Exception is when Propagate => raise; when Ignore => null; when Deactivate => begin Close (Handle.Stream.all); exception when others => null; end; end case; end Trace; ------------ -- Assert -- ------------ procedure Assert (Handle : not null access Trace_Handle_Record'Class; Condition : Boolean; Error_Message : String; Message_If_Success : String := ""; Raise_Exception : Boolean := True; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Active (Handle) then if not Condition then Create_Exception_Handle (Trace_Handle (Handle)); Trace (Handle.Exception_Handle, Error_Message, Location => Location, Entity => Entity); if Raise_Exception then Raise_Assert_Failure (Error_Message & " (" & Entity & " at " & Location & ")"); end if; elsif Message_If_Success'Length /= 0 then Trace (Handle, Message_If_Success, Location, Entity); end if; end if; end Assert; --------------------- -- Increase_Indent -- --------------------- procedure Increase_Indent (Handle : access Trace_Handle_Record'Class := null; Msg : String := ""; Style : Message_Style := Use_Default_Style; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Handle /= null and then Handle.Stream /= null then if Msg /= "" then Trace (Handle, Msg, Style, Location => Location, Entity => Entity); end if; -- ??? Should we do this when the handle is inactive ? Increment (Handle.Stream.Indentation); end if; end Increase_Indent; --------------------- -- Decrease_Indent -- --------------------- procedure Decrease_Indent (Handle : access Trace_Handle_Record'Class := null; Msg : String := ""; Style : Message_Style := Use_Default_Style; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if Handle /= null and then Handle.Stream /= null then -- The counter is a modulo type if Sync_Sub_And_Fetch (Handle.Stream.Indentation'Unchecked_Access, 1) = Minus_One then Handle.Stream.Indentation := 0; Trace (Handle, "Indentation error: too many decrease"); end if; if Msg /= "" then Trace (Handle, Msg, Style, Location => Location, Entity => Entity); end if; end if; end Decrease_Indent; ---------------------- -- Local_Sub_Second -- ---------------------- function Local_Sub_Second (T : Ada.Calendar.Time) return Integer is Y : Year_Number; M : Month_Number; D : Day_Number; H : Ada.Calendar.Formatting.Hour_Number; Mi : Ada.Calendar.Formatting.Minute_Number; S : Ada.Calendar.Formatting.Second_Number; Ss : Ada.Calendar.Formatting.Second_Duration; Ls : Boolean; begin Ada.Calendar.Formatting.Split (T, Y, M, D, H, Mi, S, Ss, Ls, Global.TZ); if Ss > 0.999 then return 999; else return Integer (Ss * 1000.0); end if; end Local_Sub_Second; ----------------------- -- Put_Absolute_Time -- ----------------------- procedure Put_Absolute_Time (Msg : in out Msg_Strings.XString) is T : constant Ada.Calendar.Time := Ada.Calendar.Clock; Z : String (1 .. 3) := "000"; Ms : constant String := Integer'Image (Local_Sub_Second (T)); begin Z (3 + 1 - (Ms'Length - 1) .. 3) := Ms (Ms'First + 1 .. Ms'Last); if Global.Absolute_Date.Active then if Global.Absolute_Time.Active then if Global.Micro_Time.Active then Msg.Append ("(" & Image (T, ISO_Date & " %T:%e") & ')'); else Msg.Append ("(" & Image (T, ISO_Date & " %T.") & Z & ')'); end if; else Msg.Append ("(" & Image (T, ISO_Date) & ')'); end if; else if Global.Micro_Time.Active then Msg.Append ("(" & Image (T, ISO_Date & " %T:%e") & ')'); else Msg.Append ("(" & Image (T, "%T.") & Z & ')'); end if; end if; end Put_Absolute_Time; -------------------- -- Before_Message -- -------------------- overriding procedure Before_Message (Self : in out Count_Trace; Handle : not null Trace_Handle; Msg : in out Msg_Strings.XString) is -- ??? Should we lock to get consistent counters ? Total : constant Atomic_Counter := Sync_Add_And_Fetch (Self.Count'Unchecked_Access, 1); Local : constant Atomic_Counter := Sync_Add_And_Fetch (Handle.Count'Unchecked_Access, 1); C : constant String := Atomic_Counter'Image (Total); H : constant String := Atomic_Counter'Image (Local); begin Msg.Append (H (H'First + 1 .. H'Last) & '/' & C (C'First + 1 .. C'Last) & ' '); end Before_Message; ------------------- -- After_Message -- ------------------- overriding procedure After_Message (Self : in out Memory_Trace; Handle : not null Trace_Handle; Msg : in out Msg_Strings.XString) is pragma Unreferenced (Handle); use GNATCOLL.Memory; Watermark : constant Watermark_Info := Get_Allocations; begin Msg.Append ("[Watermark:" & (if Watermark.Current > Self.Previous then '>' else '<') & Watermark.Current'Img & '/' & Watermark.High'Img & "]"); Self.Previous := Watermark.Current; end After_Message; ------------------- -- After_Message -- ------------------- overriding procedure After_Message (Self : in out Ada_Memory_Trace; Handle : not null Trace_Handle; Msg : in out Msg_Strings.XString) is pragma Unreferenced (Handle); use GNATCOLL.Memory; Watermark : constant Watermark_Info := Get_Ada_Allocations; begin if Watermark.High /= 0 then Msg.Append ("[AdaWatermark:" & (if Watermark.Current > Self.Previous then '>' else '<') & Watermark.Current'Img & '/' & Watermark.High'Img & "]"); end if; Self.Previous := Watermark.Current; end After_Message; ------------------- -- After_Message -- ------------------- overriding procedure After_Message (Self : in out Elapse_Time_Trace; Handle : not null Trace_Handle; Msg : in out Msg_Strings.XString) is pragma Unreferenced (Self); T : constant Ada.Calendar.Time := Ada.Calendar.Clock; Dur : Integer; begin if Handle.Timer /= No_Time then Dur := Integer ((T - Handle.Timer) * 1000); Msg.Append ("(elapsed:" & Integer'Image (Dur) & "ms)"); end if; Handle.Timer := T; end After_Message; ------------------- -- After_Message -- ------------------- overriding procedure After_Message (Self : in out Stack_Trace; Handle : not null Trace_Handle; Msg : in out Msg_Strings.XString) is pragma Unreferenced (Self, Handle); Tracebacks : GNAT.Traceback.Tracebacks_Array (1 .. 50); Len : Natural; begin Call_Chain (Tracebacks, Len); Msg.Append ("(callstack: "); for J in Tracebacks'First .. Len loop Msg.Append (System.Address_Image (Get_PC (Tracebacks (J))) & ' '); end loop; Msg.Append (")"); end After_Message; -------------------------- -- Add_Global_Decorator -- -------------------------- procedure Add_Global_Decorator (Decorator : not null access Trace_Decorator_Record'Class; Name : String) is begin Register_Handle (Trace_Handle (Decorator), To_Upper (Name)); Decorator.Active := False; -- Set this flag, so that a "+" in the config file has no impact on -- decorators. Decorator.Forced_Active := True; end Add_Global_Decorator; ----------------- -- Config_File -- ----------------- function Config_File (Filename : Virtual_File; Default : Virtual_File) return Virtual_File is Env : GNAT.Strings.String_Access; Ret : Virtual_File; begin if Filename /= No_File and then Filename.Is_Regular_File then return Filename; end if; Env := Getenv (Config_File_Environment); -- First test the file described in the environment variable if Env /= null and then Env.all /= "" then Ret := Create (+Env.all); Free (Env); if Ret.Is_Regular_File then return Ret; end if; return No_File; end if; Free (Env); -- Then the file in the current directory Ret := Create_From_Dir (Get_Current_Dir, Default_Config_File); if Ret.Is_Regular_File then return Ret; end if; -- Then the file in the user's home directory Ret := Create_From_Dir (Get_Home_Directory, Default_Config_File); if Ret.Is_Regular_File then return Ret; end if; -- Finally the default file if Default /= No_File and then Is_Regular_File (Default) then return Default; end if; return No_File; end Config_File; ----------------------------- -- Register_Stream_Factory -- ----------------------------- procedure Register_Stream_Factory (Name : String; Factory : Stream_Factory_Access) is begin Lock (Global.Lock); Global.Factories_List := new Stream_Factories' (Name => new String'("&" & Name), Factory => Factory, Next => Global.Factories_List); Unlock (Global.Lock); end Register_Stream_Factory; ----------- -- Close -- ----------- procedure Close (Stream : in out Trace_Stream_Record) is begin Free (Stream.Name); end Close; --------- -- Put -- --------- overriding procedure Put (Stream : in out File_Stream_Record; Str : Msg_Strings.XString) is N : size_t; S : Msg_Strings.Char_Array; L : Natural; begin -- fwrite is thread safe on Windows and POSIX systems, -- we should not need locking. Str.Get_String (S, L); -- The call to fwrite is C, so will not raise exceptions Lock (Stream.Lock); N := fwrite (buffer => S.all'Address, size => size_t (L), count => 1, stream => Stream.File); Unlock (Stream.Lock); if N /= size_t (L) then -- ??? Could not write to file, disk full ? null; end if; end Put; ----------- -- Close -- ----------- overriding procedure Close (Stream : in out File_Stream_Record) is Status : int; pragma Unreferenced (Status); begin if Stream.File /= stdout and then Stream.File /= stderr then Status := fclose (Stream.File); Stream.File := NULL_Stream; end if; Close (Trace_Stream_Record (Stream)); end Close; ------------------ -- Parse_Config -- ------------------ procedure Parse_Config (Config : String; On_Exception : On_Exception_Mode := Propagate; Force_Activation : Boolean := True; Relative_Path_To : GNATCOLL.VFS.Virtual_File := GNATCOLL.VFS.Get_Current_Dir) is Handle : Trace_Handle; Dec : Trace_Decorator; Count : Natural := 0; procedure Create_Decorators; -- Create all default decorators, if not done yet function One_Line (Line : String) return Boolean; -- Callback function for each line of the configuration ----------------------- -- Create_Decorators -- ----------------------- procedure Create_Decorators is begin if Global.Colors = null then Set_Default_Stream ("&1"); Global.Micro_Time := new Trace_Decorator_Record; Global.Micro_Time.Add_Global_Decorator ("DEBUG.MICRO_TIME"); Dec := new Elapse_Time_Trace; Dec.Add_Global_Decorator ("DEBUG.ELAPSED_TIME"); Dec := new Stack_Trace; Dec.Add_Global_Decorator ("DEBUG.STACK_TRACE"); Dec := new Count_Trace; Dec.Add_Global_Decorator ("DEBUG.COUNT"); Dec := new Memory_Trace; Dec.Add_Global_Decorator ("DEBUG.MEMORY"); Dec := new Ada_Memory_Trace; Dec.Add_Global_Decorator ("DEBUG.ADA_MEMORY"); -- These are handled directly in Trace, but we should have them on -- the active list of decorators to know whether we need to add a -- space. Global.Absolute_Time := new Trace_Decorator_Record; Global.Absolute_Time.Add_Global_Decorator ("DEBUG.ABSOLUTE_TIME"); Global.Absolute_Date := new Trace_Decorator_Record; Global.Absolute_Date.Add_Global_Decorator ("DEBUG.ABSOLUTE_DATE"); Global.Enclosing_Entity := new Trace_Decorator_Record; Global.Enclosing_Entity.Add_Global_Decorator ("DEBUG.ENCLOSING_ENTITY"); Global.Location := new Trace_Decorator_Record; Global.Location.Add_Global_Decorator ("DEBUG.LOCATION"); -- The following are not decorators, and handled specially Global.Finalize_Traces := new Trace_Decorator_Record; Global.Finalize_Traces.Add_Global_Decorator ("DEBUG.FINALIZE_TRACES"); Global.Finalize_Traces.Active := True; Global.Split_Lines := new Trace_Decorator_Record; Global.Split_Lines.Add_Global_Decorator ("DEBUG.SPLIT_LINES"); Global.Split_Lines.Active := True; Global.Colors := new Trace_Decorator_Record; Global.Colors.Add_Global_Decorator ("DEBUG.COLORS"); end if; end Create_Decorators; S : constant String := "[ \t]*"; Line_Re : constant GNAT.Regpat.Pattern_Matcher := GNAT.Regpat.Compile ("^(?:" & "([^\s=:>+-]+)" & S -- 1 = name & "(?:=" & S & "(yes|no))?" & S -- 2 = active? & "(:[^\s>]+)?" & S -- 3 = options & "(?:>" & S & "(\S+))?" & S -- 4 = stream & "|" & "(>\S+)?" & S -- 5 = default stream & "|" & "(\+)" & S -- 6 = "+" & ")?" -- line can be empty & S & "(?:(?:#|--).*)?" -- end of line comments & "\r?$"); function One_Line (Line : String) return Boolean is M : GNAT.Regpat.Match_Array (0 .. 6); Group_Name : constant := 1; Group_Active : constant := 2; Group_Options : constant := 3; Group_Stream : constant := 4; Group_Default_Stream : constant := 5; Group_All : constant := 6; begin Count := Count + 1; if Line = "" then return True; end if; Match (Line_Re, Line, Matches => M); if M (0) = No_Match then if On_Exception = Propagate then raise Constraint_Error with "Line " & Count'Img & ": """ & Line & """ is not recognised."; end if; elsif M (Group_All) /= No_Match then Global.Default_Activation := True; Handle := Global.Handles_List; while Handle /= null loop if not Handle.Forced_Active then Set_Active (Handle, True); -- A later declaration of the stream in the code -- should not be allowed to reset Active to False Handle.Forced_Active := True; end if; Handle := Handle.Next; end loop; elsif M (Group_Default_Stream) /= No_Match then Set_Default_Stream (Config (M (Group_Default_Stream).First .. M (Group_Default_Stream).Last), Config_File => Relative_Path_To); elsif M (Group_Name) /= No_Match then declare Active : constant Default_Activation_Status := (if M (Group_Active) = No_Match or else Config (M (Group_Active).First .. M (Group_Active).Last) /= "no" then On else Off); Stream : Trace_Stream := null; Style : Message_Style := Default_Style; begin -- Do we have options for this handle ? if M (Group_Options) /= No_Match then declare use GNATCOLL.Terminal; Options : String_List_Access := Split (Config (M (Group_Options).First .. M (Group_Options).Last), ':'); begin for Opt of Options.all loop if Starts_With (Opt.all, "fg=") then Style.Fg := ANSI_Color'Value (Opt (Opt'First + 3 .. Opt'Last)); elsif Starts_With (Opt.all, "bg=") then Style.Bg := ANSI_Color'Value (Opt (Opt'First + 3 .. Opt'Last)); elsif Starts_With (Opt.all, "style=") then Style.Style := ANSI_Style'Value (Opt (Opt'First + 6 .. Opt'Last)); end if; end loop; Free (Options); end; end if; -- What stream is this sent to ? if M (Group_Stream) /= No_Match then declare Save : Integer := M (Group_Stream).First; Append : Boolean := False; begin if Save + 1 <= M (Group_Stream).Last and then Config (Save) = '>' then Append := True; Save := Save + 1; end if; Stream := Find_Stream (Config (Save .. M (Group_Stream).Last), Relative_Path_To, Append); end; end if; Handle := Create_Internal (Config (M (Group_Name).First .. M (Group_Name).Last), From_Config_File => True, Default => Active, Style => Style, Stream => Stream); end; end if; return True; end One_Line; begin if not Debug_Mode then return; end if; GNATCOLL.Traces.On_Exception := On_Exception; if Force_Activation or else Config /= "" then Create_Decorators; end if; if Config /= "" then Split (Config, (1 => ASCII.LF), One_Line'Access); end if; end Parse_Config; ----------------------- -- Parse_Config_File -- ----------------------- procedure Parse_Config_File (Filename : Virtual_File; Default : Virtual_File := No_File; On_Exception : On_Exception_Mode := Propagate; Force_Activation : Boolean := True) is File_Name : constant Virtual_File := Config_File (Filename, Default); Buffer : Str_Access; File : Mapped_File; begin if not Debug_Mode then return; end if; GNATCOLL.Traces.On_Exception := On_Exception; if File_Name = No_File then Parse_Config ("", On_Exception, Force_Activation => Force_Activation); else begin File := Open_Read (+File_Name.Full_Name); exception when Ada.IO_Exceptions.Name_Error => Parse_Config ("", On_Exception, Force_Activation => Force_Activation); return; end; Read (File); Buffer := Data (File); Parse_Config (Config => String (Buffer (1 .. Last (File))), On_Exception => On_Exception, Force_Activation => Force_Activation, Relative_Path_To => File_Name.Dir); Close (File); end if; end Parse_Config_File; ----------------------- -- Parse_Config_File -- ----------------------- procedure Parse_Config_File (Filename : String := ""; Default : String := ""; On_Exception : On_Exception_Mode := Propagate; Force_Activation : Boolean := True) is F_Filename : Virtual_File; F_Default : Virtual_File; begin if Filename = "" then F_Filename := No_File; else F_Filename := Create_From_Base (+Filename); end if; if Default = "" then F_Default := No_File; else F_Default := Create_From_Base (+Default); end if; Parse_Config_File (F_Filename, F_Default, On_Exception, Force_Activation); end Parse_Config_File; -------------- -- Finalize -- -------------- procedure Finalize is Tmp : Trace_Handle; Next : Trace_Handle; TmpS : Trace_Stream; NextS : Trace_Stream; TmpF : Stream_Factories_List; NextF : Stream_Factories_List; begin if not Global.Finalized -- Might never have been initialized at all and then Global.Finalize_Traces /= null and then Global.Finalize_Traces.Active then Lock (Global.Lock); Tmp := Global.Handles_List; while Tmp /= null loop Next := Tmp.Next; if Tmp.Finalize then Free (Tmp.Name); Unchecked_Free (Tmp); end if; Tmp := Next; end loop; Global.Handles_List := null; Tmp := Global.Wildcard_Handles_List; while Tmp /= null loop Next := Tmp.Next; if Tmp.Finalize then Free (Tmp.Name); Unchecked_Free (Tmp); end if; Tmp := Next; end loop; Global.Wildcard_Handles_List := null; TmpS := Global.Streams_List; while TmpS /= null loop NextS := TmpS.Next; Close (TmpS.all); Unchecked_Free (TmpS); TmpS := NextS; end loop; Global.Streams_List := null; TmpF := Global.Factories_List; while TmpF /= null loop NextF := TmpF.Next; Free (TmpF.Name); Unchecked_Free (TmpF.Factory); Unchecked_Free (TmpF); TmpF := NextF; end loop; Global.Factories_List := null; Unlock (Global.Lock); end if; Global.Finalized := True; end Finalize; --------------------- -- For_Each_Handle -- --------------------- procedure For_Each_Handle (Proc : not null Handlers_Proc) is Tmp : Trace_Handle := Global.Handles_List; begin while Tmp /= null loop Proc (Tmp); Tmp := Tmp.Next; end loop; end For_Each_Handle; ------------------------ -- Set_Default_Stream -- ------------------------ procedure Set_Default_Stream (Name : String; Config_File : Virtual_File := No_File) is S : Trace_Stream; T : Trace_Stream; H : Trace_Handle; begin if Name'Length > 2 and then Name (Name'First .. Name'First + 1) = ">>" then S := Find_Stream (Name (Name'First + 2 .. Name'Last), Config_File.Dir, Append => True); elsif Name (Name'First) = '>' then S := Find_Stream (Name (Name'First + 1 .. Name'Last), Config_File.Dir, Append => False); else S := Find_Stream (Name, Config_File.Dir, Append => False); end if; if S /= null then -- Put it first in the list Lock (Global.Lock); if Global.Streams_List /= S then T := Global.Streams_List; while T.Next /= S loop T := T.Next; end loop; T.Next := S.Next; S.Next := Global.Streams_List; Global.Streams_List := S; end if; -- Apply the default stream for all streams that do not have an -- explicit one H := Global.Handles_List; while H /= null loop if H.Stream = null or else H.Stream_Is_Default then H.Stream := S; H.Stream_Is_Default := True; Cache_Settings (H); end if; H := H.Next; end loop; Unlock (Global.Lock); end if; end Set_Default_Stream; ----------- -- Count -- ----------- function Count (Handler : not null access Trace_Handle_Record'Class) return Natural is begin return Natural (Handler.Count); end Count; ------------ -- Create -- ------------ function Create (Handle : Trace_Handle; Message : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity; Style : Message_Style := Default_Block_Style) return Block_Trace_Handle is begin return Result : Block_Trace_Handle do if Active (Handle) then Result.Me := Handle; Result.Style := Style; Result.Loc := new String'(Entity & ':' & Location); if Message /= "" then Increase_Indent (Handle, "Entering " & Result.Loc.all & ' ' & Message, Style => Style, Location => "", Entity => ""); else Increase_Indent (Handle, "Entering " & Result.Loc.all, Style => Style, Location => "", Entity => ""); end if; end if; end return; end Create; -------------- -- Finalize -- -------------- overriding procedure Finalize (Self : in out Block_Trace_Handle) is begin -- If we were active when Create was called if Self.Me /= null then Decrease_Indent (Self.Me, "Leaving " & Self.Loc.all, Style => Self.Style, Location => "", -- avoid duplicate info in the output Entity => ""); end if; Free (Self.Loc); end Finalize; end GNATCOLL.Traces; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-traces.ads000066400000000000000000001202551425465243200226650ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2001-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Logging framework -- Usage in the code -- ================= -- Here is an example of code: -- -- with GNATCOLL.Traces; use GNATCOLL.Traces; -- -- procedure Main is -- Me : constant Trace_Handle := Create ("NAME"); -- begin -- Parse_Config_File (".gnatdebug"); -- mandatory -- Trace (Me, "Message 1"); -- end Main; -- -- You would then provide an additional .gnatdebug file in the current -- directory, see below for its format. -- Configuration -- ============== -- -- The format of the configuration file is the following: -- * activating or deactivating a specific module: -- -- MODULE_NAME=yes -- MODULE_NAME -- same as "=yes" -- MODULE_NAME=no -- default, unless you used "+" -- MODULE_NAME=yes :option1:option2 -- -- where the options are generally given as key=value. The valid -- options are: -- -- fg=color # where color is red|black|green|yellow|blue| -- # magenta|cyan|gray -- bg=color # Same colors as for fg -- style=style # where style is bright|dim|normal -- -- These options configure the default color of the messages in -- this stream. The colors are ignored unless you also enable -- DEBUG.COLORS (see below). The exact color that is output depends -- on the configuration of your terminal (see GNATCOLL.Terminal for -- more information). -- * redirecting a specific module to a file -- -- MODULE_NAME=yes >filename -- MODULE_NAME=yes >&stream -- MODULE_NAME=yes :option1:option2 >filename -- * Activate all modules, except those with an explicit "=no" line, -- and those that are created with "Create (..., Default => Off)" in -- the code. This command does not apply to decorators like -- DEBUG.COLORS (see below). -- -- + -- * redirecting all modules to a different stream: -- - to a file: -- -- >filename -- -- If filename is a relative path, it is relative to the location of -- the configuration file. $$ is automatically replaced by the -- process number. $D is automatically replaced by the current date. -- $T is automatically replaced by the current date and time. -- You can use >>filename instead if you want to append to the file. -- -- - to standard output -- -- >&1 -- -- - to standard error -- -- >&2 -- -- - to a user-defined stream (see gnat-traces-syslog.ads): -- -- >&stream -- -- In all the cases above, the name of the stream can be followed by -- one or more options, for instance: -- >filename:buffer_size=0 -- >&1:colors=on -- >&stream:option1:option2 -- -- The list of options is given below. They do not necessarily apply -- to all streams (for instance controlling the buffer size is not -- supported for standard output or standard error, and syslog does -- not support colors). -- -- * "buffer_size": the size of the buffer. The logs are -- synchronized with the disk when this buffer is full. -- Setting this to 0 means that synchronization appears after -- every output line, which is slow but might help when -- debugging a crashing application. -- -- * "colors": whether to allow colors on this stream. -- This combines with the DEBUG.COLORS settings. -- Setting this to "on" or "true" forces color output, to -- "off" or "false" disables colors, and "auto" will try and -- autodetect whether the terminal supports colors. -- For Windows users, note that colors are only supported via -- the use of ANSI sequences (see gnatcoll-terminal.ads) -- * comments -- -- comment -- Wildcards -- ========= -- It is also possible to substitute a module name with a '*', to configure -- a whole set of modules with a single line. For instance: -- -- * *.EXCEPTIONS=yes >&stdout -- will always display a stream whose name ends with ".EXCEPTIONS" to -- stdout. -- -- * MODULE_NAME.*=no -- Disables all streams starting with "MODULE_NAME" (including -- MODULE_NAME itself). The star can only be used to substitute the -- whole first or last name. If the configuration file also contains -- a line like "MODULE_NAME.FOO" anywhere (before or after), then this -- specific stream is not disabled. -- -- * *.ERROR=yes :fg=red -- Enable all modules ending with "ERROR", and display their messages -- in red by default. -- Decorators -- ========== -- All messages are output with decorators, which can add extra information -- like timestamp, colors, message count,... Those decorators are -- configured like modules (see above), but have reserved names. It is -- possible to create your own decorators, but all of the predefined -- decorators start with "DEBUG.". Here is the extensive list: -- "DEBUG.ABSOLUTE_TIME" -- If this handle is activated, then the absolute time will be added to the -- output, if the stream supports it (syslog does not) -- "DEBUG.MICRO_TIME" -- If this handle is activated, the absolute time will be displayed using -- micro-seconds resolution, instead of just seconds. -- "DEBUG.ABSOLUTE_DATE" -- If this handle is activated, then the absolute date will be added to the -- output, if the stream supports it (syslog does not) -- "DEBUG.ELAPSED_TIME" -- If this handle is activated, then the elapsed time since the last -- call to Trace for this handler will be displayed. -- "DEBUG.STACK_TRACE" -- If this handle is activated, then the stack trace will be displayed. -- "DEBUG.LOCATION" -- If this is activated, then the location of the call to Trace is -- displayed. Note that, contrary to DEBUG.STACK_TRACE, this works on -- all targets, and even if the executable wasn't compiled with debug -- information. -- "DEBUG.COLORS" -- When this config is enabled, then other decorators (like the name of -- the handle, current time, count,...) will be displayed in color when -- the stream supports them (see also the "colors" option when you -- declare the streams, at the top of this package). -- "DEBUG.ENCLOSING_ENTITY" -- If this handle is activated, the name of the enclosing entity at the -- location of the call to Trace will be displayed. -- "DEBUG.COUNT" -- If this handle is active, two counters are associated with each output -- trace: one of them is unique for the handle, the other is unique in the -- whole application life. These can for instance be used to set -- conditional breakpoints for a specific trace (break on traces.Log or -- traces.Trace, and check the value of Handle.Count -- "DEBUG.MEMORY" -- This decorator will show the size of resident memory for the -- application, as well as the peek size. This takes into account memory -- allocated from any language, C, Ada,.. and is queries from the -- operating system). -- It also shows a ">" or "<" to indicate whether memory use increased or -- not. -- "DEBUG.ADA_MEMORY" -- This is similar to DEBUG.MEMORY, but only displays memory allocated -- from Ada (provided you have setup GNATCOLL.Memory to become the default -- allocator for your application). -- "DEBUG.FINALIZE_TRACES" (default: active) -- If deactivated, the trace handles will never be freed when the program -- is finalized by the compiler. This is mostly for debugging purposes. -- "DEBUG.SPLIT_LINES" (default: true) -- Whether long messages should be split at each ASCII.LF character. When -- we do this, the trace handle name and decorators are replicated at the -- beginning of each followup line. This results in a slow down. -- Example -- ======= -- Here is a short example of configuration file: -- + -- by default, show all -- >&2 -- defines the default stream -- DEBUG.COLORS=yes -- enable colors -- PKG1=no -- do not show -- PKG2=yes -- to the default stream, ie stderr -- PKG3=yes >file -- to the file "file" in current directory -- PKG4=yes >&syslog -- to syslog, see gnat-traces-syslog.ads with GNAT.Source_Info; with GNAT.Strings; with Ada.Calendar; with Ada.Exceptions; with Ada.Characters.Handling; use Ada.Characters.Handling; private with Ada.Finalization; with GNATCOLL.VFS; use GNATCOLL.VFS; with GNATCOLL.Atomic; use GNATCOLL.Atomic; with GNATCOLL.Strings_Impl; with GNATCOLL.Terminal; package GNATCOLL.Traces is Config_File_Environment : constant String := "ADA_DEBUG_FILE"; Default_Config_File : constant Filesystem_String := ".gnatdebug"; -- Name of the default configuration file. This file is looked for first in -- the current directory, then in the user's home directory. If no file is -- found, then no handle will be activated. The name of this file can be -- overridden by the environment variable Config_File_Environment, which -- should be an absolute name (or relative to the current directory). If -- this variable is set, the standard file is never searched. Debug_Mode : constant Boolean := True; -- Set the global activation status for the debug traces. If this is set to -- False and the subprograms below are inlined, then no code will be -- generated to support debug traces. Otherwise, if Debug_Mode is True, -- then the debug traces can be activated selectively for each module. type On_Exception_Mode is (Propagate, Ignore, Deactivate); -- Behavior when an exception is raised while writing to the log stream e.g -- because of NFS error when writing to a file. -- Propagate: the exception is propagated -- Ignore: the exception is silently ignored -- Deactivate: when an exception is raised when manipulating a handle -- deactivate it; no logging will happen on this handle -- anymore. procedure Parse_Config_File (Filename : Virtual_File; Default : Virtual_File := No_File; On_Exception : On_Exception_Mode := Propagate; Force_Activation : Boolean := True); -- Initializes this package, and parse the configuration file. The -- algorithm is the following: -- - If filename is specified and exists on the disk, parse this file -- - Else test the file described in Config_File_Environment -- - If not found, search in the current directory for a file -- Default_Config_File -- - If not found, search in the user's home directory for a file -- Default_Config_File -- - If still not found, parses Default -- On_Exception is used to define the behavior should something unexpected -- prevent the log stream to be written. -- -- If the file is found on the disk, or Force_Activation is True: -- This procedure will set the default stream. At this -- stage, most loggers will start outputting information. If you do not -- call Parse_Config_File, then most loggers will have no associated -- stream and therefore will not output anything. An alternative is to -- simply call Parse_Config below. procedure Parse_Config_File (Filename : String := ""; Default : String := ""; On_Exception : On_Exception_Mode := Propagate; Force_Activation : Boolean := True); -- Same as above, using regular strings for file names. procedure Parse_Config (Config : String; On_Exception : On_Exception_Mode := Propagate; Force_Activation : Boolean := True; Relative_Path_To : GNATCOLL.VFS.Virtual_File := GNATCOLL.VFS.Get_Current_Dir); -- Similar to the above, but the configuration is read from a string. -- This might be convenient when you distribute your application since you -- do not have to provide a default config file. -- You can call this procedure multiple times. -- -- Relative_Path_To is used to resolve relative path names in the -- configuration. -- -- It is still recommended to parse Parse_Config_File afterwards so that -- you can override the configuration without having to recompile your -- application. type Output_Proc is access procedure (Str : String); procedure Show_Configuration (Output : Output_Proc); -- Output on Output the current configuration for all traces. The resulting -- file is a valid configuration file, which can be reused in later runs. procedure Finalize; -- Free all the registered handles. This is not strictly needed, but is -- specially useful when testing memory leaks in your application. This -- also ensures that output streams are correctly closed. ------------- -- Loggers -- ------------- type Trace_Handle_Record is tagged limited private; type Trace_Handle is access all Trace_Handle_Record'Class; subtype Logger is Trace_Handle; -- alternative name -- A handle for a trace stream. -- One such handle should be created for each module/unit/package where it -- is relevant. They are associated with a specific name and output stream, -- and can be activated through a configuration file. If two or more -- packages create streams with the same name, they will share their -- attributes. type Handle_Factory is access function return Logger; type Default_Activation_Status is (From_Config, On, Off); function Create (Unit_Name : String; Default : Default_Activation_Status := From_Config; Stream : String := ""; Factory : Handle_Factory := null; Finalize : Boolean := True) return Logger; -- Create a new handle -- Unit_Name is upper-cased, and looked-for in the configuration file to -- check whether traces should be emitted for that module. Calling this -- function several times with the same Unit_Name will always return the -- same handle. -- -- If Default is not From_Config, this forces an explicit activation -- status for that handle. To change it, the user must explicitly have -- a line for this handle in the config file, and this handle is not -- impacted by the use of "+" in this config file. -- -- Stream indicates which stream the application is sent to. This has the -- same format as in the configuration file: -- - if left to the empty string, this is the default stream specified -- in the configuration file on the line starting with ">". -- - otherwise, the string is similar to what can be specified in the -- configuration file after ">", ie one of "filename", "&2" (stderr), -- "&1" (stdout) or any of the registered streams ("&syslog" for -- instance, see gnat-traces-syslog.ads) -- If no such stream is found, defaults on the default stream declared in -- the config file. -- -- If the handle has not been created yet in some other part of the code, -- a new one will be allocated. Factory can be used in this case to do the -- actual allocation, so that you can return your own Trace_Handle_Record, -- when you need to override Trace. The factory is only called once. -- -- If Finalize is True, the handle will be freed when Finalize is called, -- otherwise it won't be. The only reason to set this to False is so that -- the handle still exists when the application itself is being finalized -- by the compiler, so that you can have logs till the last minute. -- See also the "DEBUG.FINALIZE_TRACES" configuration. function Unit_Name (Handle : not null access Trace_Handle_Record'Class) return String; -- Return the unit name (upper-cased) for this handle. This can be used for -- instance in generic packages to specialize the handle for a specific -- instance. -- -- Recommended use with generics: -- Since generics might be used in various, independent modules, the -- recommended use is to have one more generic parameter for the logger -- Internally, it is then possible to specialize this stream (see -- the subprogram Unit_Name): -- generic -- Self_Debug : Logger := Create ("My_Generic"); -- package My_Generic is -- Me : Logger := Create ("Generic" & Unit_Name (Self_Debug)); -- ... Red_Fg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Red, Bg => Terminal.Unchanged)); Green_Fg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Green, Bg => Terminal.Unchanged)); Brown_Fg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Yellow, Bg => Terminal.Unchanged)); Blue_Fg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Blue, Bg => Terminal.Unchanged)); Purple_Fg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Magenta, Bg => Terminal.Unchanged)); Cyan_Fg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Unchanged, Fg => Terminal.Cyan, Bg => Terminal.Unchanged)); Grey_Fg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Grey, Bg => Terminal.Unchanged)); Default_Fg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Unchanged, Fg => Terminal.Reset, Bg => Terminal.Unchanged)); Red_Bg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Unchanged, Bg => Terminal.Red)); Green_Bg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Unchanged, Bg => Terminal.Green)); Brown_Bg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Unchanged, Bg => Terminal.Yellow)); Blue_Bg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Unchanged, Bg => Terminal.Blue)); Purple_Bg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Unchanged, Bg => Terminal.Magenta)); Cyan_Bg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Unchanged, Bg => Terminal.Cyan)); Grey_Bg : constant String := Terminal.Get_ANSI_Sequence ((Style => Terminal.Reset_All, Fg => Terminal.Unchanged, Bg => Terminal.Grey)); -- The various colors that can be applied to text. You can combine a -- foreground and a background color by concatenating the strings. -- !!! This constants provided for backward compartibility. Use Style -- parameter instead in new applications. subtype Message_Style is GNATCOLL.Terminal.Full_Style; -- Styling applied to the text of a message. -- This has no effect if the stream does not support colors, or if -- the DEBUG.COLORS setting has not been enabled. Use_Default_Style : constant Message_Style := (Fg => GNATCOLL.Terminal.Unchanged, Bg => GNATCOLL.Terminal.Unchanged, Style => GNATCOLL.Terminal.Unchanged); -- Messages will use the default style declared for the handle, no -- overriding takes place Default_Block_Style : constant Message_Style := (Fg => GNATCOLL.Terminal.Unchanged, Bg => GNATCOLL.Terminal.Unchanged, Style => GNATCOLL.Terminal.Dim); procedure Trace (Handle : not null access Trace_Handle_Record'Class; E : Ada.Exceptions.Exception_Occurrence; Msg : String := "Unexpected exception: "; Style : Message_Style := Use_Default_Style); procedure Trace (Handle : not null access Trace_Handle_Record'Class; E : Ada.Exceptions.Exception_Occurrence; Msg : String := "Unexpected exception: "; Color : String) with Obsolescent; -- Extract information from the given Exception_Occurrence and output it -- with Msg as a prefix. -- You can override the default color used for the stream by specifying the -- color parameter. -- -- The output is really done on a separate handle with the same name as -- Handle and a suffix of ".EXCEPTIONS". This way, it is possible to -- configure this handle differently. For instance, the configuration file -- could contain: -- *.EXCEPTIONS=yes >&stdout -- to always display those exceptions on stdout and not on the default -- stream for Handle itself (a useful scenario when this version of Trace -- is used to display unexpected exceptions in your application). procedure Trace (Handle : not null access Trace_Handle_Record'Class; Message : String; Style : Message_Style := Use_Default_Style; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); procedure Trace (Handle : not null access Trace_Handle_Record'Class; Message : String; Color : String; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) with Obsolescent; -- Output Message to the stream associated with Handle, along with any -- extra information setup by the user (see the default handles below). -- If Handle is not active, this subprogram will do nothing. -- Likewise, this procedure will do nothing if Handle has no associated -- stream (which is the case when Parse_Config_File has not been called -- and no stream was specified in the call to Create). -- -- If message includes ASCII.LF characters, then several lines are output, -- starting with a special prefix -- -- Do not modify the parameters Location and Entity, they will have proper -- default values, and are used to output additional information about the -- context of the call. -- -- In case of exception (for instance because the log file is not -- writable), the behavior is controlled by the parameter On_Exception -- that was passed to Parse_Config_File. -- -- You can override this procedure if you systematically want to add extra -- information when logging via a specific handle. The other procedures -- like Assert, Increase_Indent and Decrease_Indent will call this -- procedure. procedure Assert (Handle : not null access Trace_Handle_Record'Class; Condition : Boolean; Error_Message : String; Message_If_Success : String := ""; Raise_Exception : Boolean := True; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) with Inline; -- Check that Condition is true. -- This subprogram does nothing if Handle is not active. -- If Condition is False: -- * Error_Message is output to a handle named Handle & ".EXCEPTIONS" -- just like an exception would be. This means that in general the -- message will be displayed in red. -- However, do not use this procedure just to get a red message. -- Instead use a standard Trace and specify the Style, or configure -- Handle to have red messages by default. -- * In addition, if Raise_Exception is true then an Assertion_Error -- exception is raised. -- -- If Condition is True: -- * Message_If_Success is output to Handle, if it isn't empty. procedure Increase_Indent (Handle : access Trace_Handle_Record'Class := null; Msg : String := ""; Style : Message_Style := Use_Default_Style; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); procedure Decrease_Indent (Handle : access Trace_Handle_Record'Class := null; Msg : String := ""; Style : Message_Style := Use_Default_Style; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); -- Change the indentation level for traces with the same output stream. -- This is so that traces that result from other subprograms be slightly -- indented, so as to make the output more readable. The output would for -- instance look like: -- [HANDLE1] Procedure 1 -- [HANDLE2] Procedure 2 -- [HANDLE1] End of Procedure 1 -- If Handle and Msg are specified, a message is output on that handle to -- explain the change of indentation. The message is only displayed if the -- handle is active, but the indentation is always changed. function Count (Handler : not null access Trace_Handle_Record'Class) return Natural; -- Return the number of times that Trace was called on the handler. This -- count is only incremented when Handler is active. procedure Set_Active (Handle : not null access Trace_Handle_Record'Class; Active : Boolean) with Inline; -- Override the activation status for Handle. -- When not Active, the Trace function will do nothing. -- -- An active trace might still have no output if it doesn't have an -- associated stream, i.e. if Parse_Config_File was never called and -- no stream was specified in the call to Create. function Is_Active (Handle : not null access Trace_Handle_Record'Class) return Boolean with Inline; function Active (Handle : not null access Trace_Handle_Record'Class) return Boolean is (Debug_Mode and then Is_Active (Handle)) with Inline; -- Return True if traces for Handle are activated. -- This function can be used to avoid the evaluation of complex -- expressions in case traces are not active, as in the following -- code: -- if Active (Handle) then -- Trace (Handle, Message & Expensive_Computation); -- end if; -- -- Is_Active will check the flag on the trace handle, which is fast but -- can only be done dynamically. Active, on the other hand, also checks -- the Debug_Mode flag statically, so that if you have disable debugging -- altogether, the code will not even be inserted in the object code by -- the compiler. type Handlers_Proc is access procedure (Handle : Trace_Handle); procedure For_Each_Handle (Proc : not null Handlers_Proc); -- Calls Proc for all created trace handlers. ------------ -- Blocks -- ------------ type Block_Trace_Handle (<>) is limited private with Warnings => Off; subtype Block_Logger is Block_Trace_Handle; -- The aspect avoids warnings on unused instances, yet allows code to -- manipulate those instances when needed (which a "Unused=>True" would -- not) function Create (Handle : Logger; Message : String := ""; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity; Style : Message_Style := Default_Block_Style) return Block_Logger; -- An object used to trace execution of blocks. -- This is a controlled object, which you should create first in your -- subprogram, and that will automatically finalize itself when the -- subprogram exists. For instance: -- Me : constant Logger := Create ("PKG"); -- procedure Foo (A : Integer) is -- Block_Me : constant Block_Logger := Create (Me); -- begin -- Trace (Me, "A=" & A'Img); -- if A > 1 then -- Foo (A - 1); -- end if; -- end Foo; -- Foo (2); -- -- which will automatically display in the traces : -- [PKG] Entering Foo:pkg.adb:5 -- [PKG] A= 2 -- [PKG] Entering Foo:pkg.adb:5 -- [PKG] A=1 -- [PKG] Leaving Foo:pkg.adb:5 -- [PKG] Leaving Foo:pkg.adb:5 -- -- Note the use of "with Unreferenced" in the above example (which could -- be replaced with a pragma Unreferenced). This is to avoid warnings from -- the compiler that the variable is unused, and is only necessary if you -- are compiling with -gnatwa or -gnatwm. -- -- Message can be used to display extra information. For efficiency -- reasons, it is not recommended to build the string dynamically to -- display the parameter of the enclosing subprograms, or perhaps as: -- -- procedure Foo (A, B, C : Integer) is -- Block_Me : constant Block_Logger := Create -- (Me, (if Active (Me) then A'Img & B'Img & C'Img else "")); -- begin -- null; -- end Foo; -- -- so that the string is only built if the trace is active. -- -- If the subprogram exits with an exception, no trace of the exception -- is displayed, you should still have an explicit exception handler if -- you want to Trace that exception. Of course, the "Leaving" message will -- be properly displayed. ------------- -- Streams -- ------------- type Typical_Msg_Size is mod 128; for Typical_Msg_Size'Size use 8; package Msg_Strings is new GNATCOLL.Strings_Impl.Strings (SSize => Typical_Msg_Size, Character_Type => Character, Character_String => String); -- We assume that most messages (including decorators) will be less than -- this number of characters, and optimize the string creation for this. -- But we still support larger messages, at a cost of one memory -- allocation which slows things down a bit. type Trace_Stream_Record is abstract tagged limited private; type Trace_Stream is access all Trace_Stream_Record'Class; -- A stream is an object responsible for ultimately displaying a string (as -- opposed to using Put_Line). Such objects do not need, in general, to be -- manipulated by your application, and you only access them by name (see -- the various descriptions above, and the parameter Stream in the call to -- Create). -- The various streams support various capabilities, and for instance not -- all of them can display colors. -- You could create your own stream if you want to redirect the traces to -- some specific area in your graphical application for instance, or -- because you want to output the logs on a socket and have them read by -- another application. -- A few predefined streams are provided in this package, and others in -- child packages (gnat-traces-syslog.ads for instance). procedure Put (Stream : in out Trace_Stream_Record; Str : Msg_Strings.XString) is abstract; -- Outputs a whole line to the stream. -- Str always ends up with a trailing newline. -- The stream needs to take appropriate lock or other synchronization -- mechanism to avoid mixing multiple lines of output. This lets each -- stream have its own lock, rather than a global lock, which improves -- the throughput. procedure Close (Stream : in out Trace_Stream_Record); -- Close the stream function Supports_Color (Stream : Trace_Stream_Record) return Boolean is (True); function Supports_Time (Stream : Trace_Stream_Record) return Boolean is (True); -- Whether the stream accepts color output, and whether we should output -- the time (if the user requested it). In some cases (syslog for instance) -- it isn't necessary to output the time, since that's already done -- automatically type Stream_Factory is abstract tagged null record; type Stream_Factory_Access is access all Stream_Factory'Class; function New_Stream (Factory : Stream_Factory; Args : String) return Trace_Stream is abstract; -- Return a newly allocated stream. -- Args is part of the string provided by the user in the configuration -- file (see below Register_Stream_Factory). -- The factory is never called twice with the same arguments, since this -- package will reuse existing streams whenever possible. procedure Register_Stream_Factory (Name : String; Factory : Stream_Factory_Access); -- Add Factory as one of the supported streams, available to Create or in -- the configuration files. This must be called before parsing the -- configuration file, of course. -- The following predefined streams are always registered: -- "&1": output to stdout (syntax similar to Unix) -- "&2": output to stderr -- "filename": output to a file named "filename" -- To avoid confusion with filenames, streams registered through this -- procedure will be available as: -- "&" & Name [ & ":" & Args ] -- The arguments are optional and can be used to further customize your -- stream. -- In the configuration file, you can redirect to any of the registered -- stream, either by default by putting the following on a line of its own: -- >&stream_name -- >&stream_name:args -- or for each specific stream: -- STREAM=yes >&stream_name -- STREAM=yes >&stream_name:args -- The object pointed by Factory will be freed by automatically when the -- factory container is freed. procedure Set_Default_Stream (Name : String; Config_File : GNATCOLL.VFS.Virtual_File := GNATCOLL.VFS.No_File); -- Set Name as the default stream. -- See Register_Stream_Factory for a list of valid names. The name can be -- prefixed with ">>" to append to that stream. -- An optional '>' is also allowed, although it is implicit if not -- specified. -- The Config_File is used to resolve a relative path name when -- needed. ---------------- -- Decorators -- ---------------- type Trace_Decorator_Record is new Trace_Handle_Record with private; type Trace_Decorator is access all Trace_Decorator_Record'Class; procedure Start_Of_Line (Self : in out Trace_Decorator_Record; Msg : in out Msg_Strings.XString; Is_Continuation : Boolean) is null; -- Called at the start of each line of the message. This procedure -- should modify Msg to Append extra information to it, if needed. -- GNATCOLL.Traces will then append the indentation for each line -- automatically, see Increase_Indent and Decrease_Indent. -- You can override this procedure to display a timestamp aligned at the -- beginning of the line, for instance. procedure Before_Message (Self : in out Trace_Decorator_Record; Handle : not null Logger; Msg : in out Msg_Strings.XString) is null; procedure After_Message (Self : in out Trace_Decorator_Record; Handle : not null Logger; Msg : in out Msg_Strings.XString) is null; -- You can override either of these two procedures to create your own -- decorators to specific trace handles (ie additional information) each -- time some message is logged. These functions are only called for the -- handles passed to Add_Global_Decorator. -- -- When displayed in the log, a line looks like: -- -- [HANDLE_NAME] MESSAGE -- -- The prefix decorator is in charge of displaying blank spaces to -- indent the line (see Increase_Indent and Decrease_Indent). But you -- can also use it to display other pieces of information (like a -- timestamp if you always want them aligned for instance). -- Any global decorator will be called before the indentation (so at -- column 1). -- Indent is the indentation level (1, 2, 3,...). This isn't the -- number of columns to indent. -- -- Only the prefix_decorator is called on continuation lines (when a -- message doesn't fit on a single line). procedure Add_Global_Decorator (Decorator : not null access Trace_Decorator_Record'Class; Name : String); -- Register a global decorator that will apply to all existing -- Trace_Handle. The decorator only has an effect when it is active. -- Here is an example: -- type My_Decorator is new Trace_Decorator_Record with null record; -- overriding procedure Before_Message -- (Self : in out My_Decorator; -- Handle : not null Logger; -- Message : in out Msg_Strings.XString) is -- begin -- Msg_Strings.Append (Message, "Some info"); -- end Before_Message; -- -- Add_Global_Decorator (new My_Decorator, "MY_DECO"); -- -- And then you can use your configuration file as usual to activate or -- deactivate the "MY_DECO" handle. -- -- A decorator is disabled by default (when it is registered via this -- procedure). To active, you can either do this in the configuration -- file, with the usual: -- MY_DECO=yes -- or in the code, as: -- Set_Active (Create ("MY_DECO"), True); private type Trace_Stream_Record is abstract tagged limited record Name : GNAT.Strings.String_Access; Next : Trace_Stream; Indentation : aliased Atomic_Counter := 0; -- Current indentation for stream end record; -- Name is the full name including the arguments, for instance "file:foo" -- if the user has defined a stream called "file" with a parameter "foo" type Block_Trace_Handle is new Ada.Finalization.Limited_Controlled with record Me : Logger; Loc : GNAT.Strings.String_Access; Style : Message_Style; end record; overriding procedure Finalize (Self : in out Block_Logger); type Trace_Handle_Record is tagged limited record Next : Logger; -- linked list Name : GNAT.Strings.String_Access; Timer : Ada.Calendar.Time; Stream : Trace_Stream; -- null for default stream Exception_Handle : Logger; -- The handle used when calling Trace and passing an exception -- occurrence. This has Name & ".EXCEPTIONS" as a name, and is created -- the first time it is needed. Count : aliased Atomic_Counter; Default_Style : Message_Style; Finalize : Boolean; Active : Boolean; Forced_Active : Boolean; Stream_Is_Default : Boolean; With_Colors : Boolean := False; With_Time : Boolean := False; -- Compute values, from the stream and corresponding settings. These -- are used to avoid dispatching calls in Log. end record; pragma Pack (Trace_Handle_Record); -- If Forced_Active is true, then the Active status shouldn't be impacted -- by a '+' in the configuration file type Trace_Decorator_Record is new Trace_Handle_Record with null record; end GNATCOLL.Traces; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-tribooleans.adb000066400000000000000000000211771425465243200237070ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ package body GNATCOLL.Tribooleans is And_Truth_Table1 : constant array (Triboolean, Triboolean) of Triboolean := (True => (True => True, False => False, Indeterminate => Indeterminate), False => (True => False, False => False, Indeterminate => False), Indeterminate => (True => Indeterminate, False => False, Indeterminate => Indeterminate)); And_Truth_Table2 : constant array (Triboolean, Boolean) of Triboolean := (True => (True => True, False => False), False => (True => False, False => False), Indeterminate => (True => Indeterminate, False => False)); Or_Truth_Table1 : constant array (Triboolean, Triboolean) of Triboolean := (True => (True => True, False => True, Indeterminate => True), False => (True => True, False => False, Indeterminate => Indeterminate), Indeterminate => (True => True, False => Indeterminate, Indeterminate => Indeterminate)); Or_Truth_Table2 : constant array (Triboolean, Boolean) of Triboolean := (True => (True => True, False => True), False => (True => True, False => False), Indeterminate => (True => True, False => Indeterminate)); Xor_Truth_Table1 : constant array (Triboolean, Triboolean) of Triboolean := (True => (True => False, False => True, Indeterminate => Indeterminate), False => (True => True, False => False, Indeterminate => Indeterminate), Indeterminate => (True => Indeterminate, False => Indeterminate, Indeterminate => Indeterminate)); Xor_Truth_Table2 : constant array (Triboolean, Boolean) of Triboolean := (True => (True => False, False => True), False => (True => True, False => False), Indeterminate => (True => Indeterminate, False => Indeterminate)); Eq_Truth_Table1 : constant array (Triboolean, Triboolean) of Triboolean := (True => (True => True, False => False, Indeterminate => Indeterminate), False => (True => False, False => True, Indeterminate => Indeterminate), Indeterminate => (True => Indeterminate, False => Indeterminate, Indeterminate => Indeterminate)); Eq_Truth_Table2 : constant array (Triboolean, Boolean) of Triboolean := (True => (True => True, False => False), False => (True => False, False => True), Indeterminate => (True => Indeterminate, False => Indeterminate)); ------------------- -- To_TriBoolean -- ------------------- function To_TriBoolean (Value : Boolean) return Triboolean is begin if Value then return Triboolean'(True); else return Triboolean'(False); end if; end To_TriBoolean; ---------------- -- To_Boolean -- ---------------- function To_Boolean (Value : Triboolean) return Boolean is begin return Value = Triboolean'(True); end To_Boolean; ----------- -- "not" -- ----------- function "not" (Value : Triboolean) return Triboolean is begin case Value is when Triboolean'(True) => return Triboolean'(False); when Triboolean'(False) => return Triboolean'(True); when Triboolean'(Indeterminate) => return Triboolean'(Indeterminate); end case; end "not"; ----------- -- "and" -- ----------- function "and" (Value1, Value2 : Triboolean) return Triboolean is begin return And_Truth_Table1 (Value1, Value2); end "and"; function "and" (Value1 : Triboolean; Value2 : Boolean) return Triboolean is begin return And_Truth_Table2 (Value1, Value2); end "and"; function "and" (Value1 : Boolean; Value2 : Triboolean) return Triboolean is begin return And_Truth_Table2 (Value2, Value1); end "and"; ---------- -- "or" -- ---------- function "or" (Value1, Value2 : Triboolean) return Triboolean is begin return Or_Truth_Table1 (Value1, Value2); end "or"; function "or" (Value1 : Triboolean; Value2 : Boolean) return Triboolean is begin return Or_Truth_Table2 (Value1, Value2); end "or"; function "or" (Value1 : Boolean; Value2 : Triboolean) return Triboolean is begin return Or_Truth_Table2 (Value2, Value1); end "or"; ----------- -- "xor" -- ----------- function "xor" (Value1, Value2 : Triboolean) return Triboolean is begin return Xor_Truth_Table1 (Value1, Value2); end "xor"; function "xor" (Value1 : Triboolean; Value2 : Boolean) return Triboolean is begin return Xor_Truth_Table2 (Value1, Value2); end "xor"; function "xor" (Value1 : Boolean; Value2 : Triboolean) return Triboolean is begin return Xor_Truth_Table2 (Value2, Value1); end "xor"; --------- -- "=" -- --------- function "=" (Value1 : Boolean; Value2 : Triboolean) return Boolean is begin if Value1 then return Value2 = Triboolean'(True); else return Value2 = Triboolean'(False); end if; end "="; function "=" (Value1 : Triboolean; Value2 : Boolean) return Boolean is begin if Value2 then return Value1 = Triboolean'(True); else return Value1 = Triboolean'(False); end if; end "="; ----------- -- Equal -- ----------- function Equal (Value1 : Triboolean; Value2 : Boolean) return Triboolean is begin return Eq_Truth_Table2 (Value1, Value2); end Equal; ----------- -- Equal -- ----------- function Equal (Value1 : Boolean; Value2 : Triboolean) return Triboolean is begin return Eq_Truth_Table2 (Value2, Value1); end Equal; function Equal (Value1 : Triboolean; Value2 : Triboolean) return Triboolean is begin return Eq_Truth_Table1 (Value1, Value2); end Equal; ----------- -- Image -- ----------- function Image (Value : Triboolean) return String is begin case Value is when True => return "TRUE"; when False => return "FALSE"; when Indeterminate => return "INDETERMINATE"; end case; end Image; ----------- -- Value -- ----------- function Value (Str : String) return Triboolean is begin if Boolean'Value (Str) then return True; else return False; end if; exception when Constraint_Error => return Indeterminate; end Value; end GNATCOLL.Tribooleans; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-tribooleans.ads000066400000000000000000000123331425465243200237220ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ package GNATCOLL.Tribooleans is type Triboolean is (True, False, Indeterminate); -- This type is an extension to the basic boolean type. -- It provides a 3-state boolean logic, where the first two states are -- equivalent to the standard Boolean values. -- You can easily provide a renaming for the Indeterminate state by -- declaring a constant: -- Maybe : constant Triboolean := Indeterminate; function To_TriBoolean (Value : Boolean) return Triboolean; -- Convert a boolean into a TriBoolean function To_Boolean (Value : Triboolean) return Boolean; -- Convert to a boolean, with the following rules: -- if Value is True, the resulting boolean is true, otherwise the result -- is false. function "not" (Value : Triboolean) return Triboolean; -- Returns the negative of a triboolean: -- True => False -- False => True, -- Indeterminate => Indeterminate function "and" (Value1, Value2 : Triboolean) return Triboolean; function "and" (Value1 : Triboolean; Value2 : Boolean) return Triboolean; function "and" (Value1 : Boolean; Value2 : Triboolean) return Triboolean; -- Logical "and" between two tribooleans, with the following truth table: -- T | F | I -- ---------- -- T | T | F | I -- F | F | F | F -- I | I | F | I function "or" (Value1, Value2 : Triboolean) return Triboolean; function "or" (Value1 : Triboolean; Value2 : Boolean) return Triboolean; function "or" (Value1 : Boolean; Value2 : Triboolean) return Triboolean; -- Logical "or" between two tribooleans, with the following truth table: -- T | F | I -- ---------- -- T | T | T | T -- F | T | F | I -- I | T | I | I function "xor" (Value1, Value2 : Triboolean) return Triboolean; function "xor" (Value1 : Triboolean; Value2 : Boolean) return Triboolean; function "xor" (Value1 : Boolean; Value2 : Triboolean) return Triboolean; -- Logical "xor" between two tribooleans, with the following truth table: -- T | F | I -- ---------- -- T | F | T | I -- F | T | F | I -- I | I | I | I function "=" (Value1 : Boolean; Value2 : Triboolean) return Boolean; function "=" (Value1 : Triboolean; Value2 : Boolean) return Boolean; -- Compare a triboolean and a boolean. If the triboolean is Indeterminate, -- the result is always False. function Equal (Value1 : Triboolean; Value2 : Boolean) return Triboolean; function Equal (Value1 : Boolean; Value2 : Triboolean) return Triboolean; function Equal (Value1 : Triboolean; Value2 : Triboolean) return Triboolean; -- Compare two tribooleans, with the following truth table: -- T | F | I -- ---------- -- T | T | F | I -- F | F | T | I -- I | I | I | I -- Note that comparing two indeterminate values also returns indeterminate, -- as opposed to what "=" would return! function Image (Value : Triboolean) return String; function Value (Str : String) return Triboolean; -- Convert to and from a string. Any value that does not match the value -- that would be returned by Boolean'Image or Boolean'Value is declared as -- indeterminate. pragma Inline (To_TriBoolean); pragma Inline (To_Boolean); pragma Inline ("and"); pragma Inline ("or"); pragma Inline ("xor"); pragma Inline ("="); pragma Inline (Equal); end GNATCOLL.Tribooleans; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-utils.adb000066400000000000000000000672261425465243200225330ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Calendar.Formatting; with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Command_Line; with Ada.Strings.Fixed; use Ada.Strings; with Ada.Strings.Maps; use Ada.Strings.Maps; with GNAT.Calendar.Time_IO; with GNAT.Case_Util; with GNAT.OS_Lib; with GNAT.Strings; use GNAT.Strings; package body GNATCOLL.Utils is OpenVMS_Host : Boolean := False; function Count_For_Split (Str : String; On : Character; Omit_Empty_Lines : Boolean := True) return Natural; -- Returns the number of strings that will occur after splitting Str on On. ---------- -- Free -- ---------- procedure Free (List : in out GNAT.Strings.String_List) is begin for L in List'Range loop Free (List (L)); end loop; end Free; ------------------- -- Is_Whitespace -- ------------------- function Is_Whitespace (Char : Character) return Boolean is begin if Char = ' ' or else Char = ASCII.HT or else Char = ASCII.LF or else Char = ASCII.CR then return True; end if; return False; end Is_Whitespace; ----------- -- Equal -- ----------- function Equal (S1, S2 : String; Case_Sensitive : Boolean) return Boolean is J1 : Natural; J2 : Natural; begin if Case_Sensitive then return S1 = S2; else if S1'Length /= S2'Length then return False; end if; J1 := S1'First; J2 := S2'First; while J1 <= S1'Last loop if To_Lower (S1 (J1)) /= To_Lower (S2 (J2)) then return False; end if; J1 := J1 + 1; J2 := J2 + 1; end loop; return True; end if; end Equal; ---------------------------- -- Case_Insensitive_Equal -- ---------------------------- function Case_Insensitive_Equal (S1, S2 : String) return Boolean is begin return Equal (S1, S2, Case_Sensitive => False); end Case_Insensitive_Equal; ----------- -- Image -- ----------- function Image (Value : Integer; Min_Width : Integer; Force_Sign : Boolean := False; Padding : Character := '0') return String is S : constant String := Integer'Image (Value); Buf : String (1 .. Integer'Max (S'Length, Min_Width + 1)) := (others => Padding); First : Integer := 2; begin Buf (Buf'Last - S'Length + 2 .. Buf'Last) := S (2 .. S'Last); if Value < 0 then First := 1; Buf (1) := '-'; elsif Force_Sign then First := 1; Buf (1) := '+'; end if; return Buf (First .. Buf'Last); end Image; ------------- -- Replace -- ------------- procedure Replace (S : in out Ada.Strings.Unbounded.Unbounded_String; Pattern : String; Replacement : String) is use Ada.Strings.Unbounded; Ind : Natural := Index_Non_Blank (S); begin while Ind < Length (S) loop Ind := Index (S, Pattern, Ind); exit when Ind = 0; S := Replace_Slice (S, Ind, Ind + Pattern'Length - 1, Replacement); Ind := Ind + Replacement'Length; end loop; end Replace; function Replace (S : String; Pattern : String; Replacement : String) return String is Idx : Natural; begin Idx := Fixed.Index (S, Pattern); if Idx = 0 then return S; else return S (S'First .. Idx - 1) & Replacement & Replace (S => S (Idx + Pattern'Length .. S'Last), Pattern => Pattern, Replacement => Replacement); end if; end Replace; --------------------- -- Count_For_Split -- --------------------- function Count_For_Split (Str : String; On : Character; Omit_Empty_Lines : Boolean := True) return Natural is Count : Natural := 0; function For_Each (Item : String) return Boolean; -------------- -- For_Eash -- -------------- function For_Each (Item : String) return Boolean is begin if not Omit_Empty_Lines or else Item'Length > 0 then Count := Count + 1; end if; return True; end For_Each; begin Split (Str, "" & On, For_Each'Access); return Count; end Count_For_Split; ----------- -- Split -- ----------- procedure Split (Str : String; On : String; For_Each : access function (Item : String) return Boolean) is First : Positive := Str'First; Last : Natural; begin while First <= Str'Last loop Last := Fixed.Index (Str, On, First); if Last = 0 then Last := Str'Last + 1; end if; exit when not For_Each (Str (First .. Last - 1)); First := Last + On'Length; end loop; end Split; ----------- -- Split -- ----------- function Split (Str : String; On : Character; Omit_Empty_Lines : Boolean := True) return GNAT.Strings.String_List_Access is Total : constant Natural := Count_For_Split (Str, On, Omit_Empty_Lines); Result : constant GNAT.Strings.String_List_Access := new GNAT.Strings.String_List (1 .. Total); Count : Positive := 1; function For_Each (Item : String) return Boolean; -------------- -- For_Each -- -------------- function For_Each (Item : String) return Boolean is begin if not Omit_Empty_Lines or else Item'Length > 0 then Result (Count) := new String'(Item); Count := Count + 1; end if; return True; end For_Each; -- Start of processing for Split begin Split (Str, (1 => On), For_Each'Access); return Result; end Split; ----------- -- Split -- ----------- function Split (Str : String; On : Character; Omit_Empty_Lines : Boolean := True) return Unbounded_String_Array is use Ada.Strings.Unbounded; Total : constant Natural := Count_For_Split (Str, On, Omit_Empty_Lines); Result : Unbounded_String_Array (1 .. Total); Count : Positive := 1; function For_Each (Item : String) return Boolean; -------------- -- For_Each -- -------------- function For_Each (Item : String) return Boolean is begin if not Omit_Empty_Lines or else Item'Length > 0 then Result (Count) := To_Unbounded_String (Item); Count := Count + 1; end if; return True; end For_Each; -- Start of processing for Split begin Split (Str, (1 => On), For_Each'Access); return Result; end Split; ---------------- -- Capitalize -- ---------------- function Capitalize (Name : String) return String is Result : String (Name'Range); J : Integer := Result'First; begin for N in Name'Range loop if Name (N) = '+' then Result (J) := 'p'; J := J + 1; elsif Name (N) = '?' then Result (J) := 'U'; J := J + 1; elsif Name (N) = '_' and then N > Name'First and then Name (N - 1) = '_' then null; elsif Name (N) >= ' ' and then Name (N) <= '/' then Result (J) := '_'; J := J + 1; elsif J = Result'First or else Result (J - 1) = '_' then Result (J) := To_Upper (Name (N)); J := J + 1; else Result (J) := To_Lower (Name (N)); J := J + 1; end if; end loop; return Result (Result'First .. J - 1); end Capitalize; --------------- -- Ends_With -- --------------- function Ends_With (Str : String; Suffix : String) return Boolean is pragma Suppress (All_Checks); begin -- This version is slightly faster than checking -- return Tail (File_Name, Suffix'Length) = Suffix; -- which needs a function returning a string. if Str'Length < Suffix'Length then return False; end if; -- Do the loop in reverse, since it likely that Suffix starts with '.' -- In the GPS case, it is also often the case that suffix starts with -- '.ad' for Ada extensions for J in reverse Suffix'Range loop if Str (Str'Last + J - Suffix'Last) /= Suffix (J) then return False; end if; end loop; return True; end Ends_With; ----------------- -- Starts_With -- ----------------- function Starts_With (Str : String; Prefix : String) return Boolean is pragma Suppress (All_Checks); begin if Str'Length < Prefix'Length then return False; end if; return Str (Str'First .. Str'First + Prefix'Length - 1) = Prefix; end Starts_With; ---------------------------- -- Is_Directory_Separator -- ---------------------------- function Is_Directory_Separator (C : Character) return Boolean is begin -- In addition to the default directory_separator allow the '/' to -- act as separator since this is allowed in MS-DOS, Windows 95/NT, -- and OS2 ports. On VMS, the situation is more complicated because -- there are two characters to check for. return C = GNAT.OS_Lib.Directory_Separator or else C = '/' or else (OpenVMS_Host and then (C = ']' or else C = ':')); end Is_Directory_Separator; ---------------------- -- Set_OpenVMS_Host -- ---------------------- procedure Set_OpenVMS_Host (Setting : Boolean := True) is begin OpenVMS_Host := Setting; end Set_OpenVMS_Host; ------------------------- -- Executable_Location -- ------------------------- function Executable_Location return String is Exec_Name : constant String := Ada.Command_Line.Command_Name; function Get_Install_Dir (S : String) return String; -- S is the executable name preceeded by the absolute or relative -- path, e.g. "c:\usr\bin\gcc.exe" or "..\bin\gcc". Returns the absolute -- or relative directory where "bin" lies (in the example "C:\usr" -- or ".."). If the executable is not a "bin" directory, return "". --------------------- -- Get_Install_Dir -- --------------------- function Get_Install_Dir (S : String) return String is Exec : String := GNAT.OS_Lib.Normalize_Pathname (S, Resolve_Links => True); Path_Last : Integer := 0; begin for J in reverse Exec'Range loop if Is_Directory_Separator (Exec (J)) then Path_Last := J - 1; exit; end if; end loop; if Path_Last >= Exec'First + 2 then GNAT.Case_Util.To_Lower (Exec (Path_Last - 2 .. Path_Last)); end if; -- If we are not in a bin/ directory if Path_Last < Exec'First + 2 or else Exec (Path_Last - 2 .. Path_Last) /= "bin" or else (Path_Last - 3 >= Exec'First and then not Is_Directory_Separator (Exec (Path_Last - 3))) then return Exec (Exec'First .. Path_Last) & GNAT.OS_Lib.Directory_Separator; else -- Skip bin/, but keep the last directory separator return Exec (Exec'First .. Path_Last - 3); end if; end Get_Install_Dir; -- Beginning of Executable_Location begin -- First determine if a path prefix was placed in front of the -- executable name. for J in reverse Exec_Name'Range loop if Is_Directory_Separator (Exec_Name (J)) then return Get_Install_Dir (Exec_Name); end if; end loop; -- If you are here, the user has typed the executable name with no -- directory prefix. -- There is a potential issue here (see K112-046) where GNAT.OS_Lib -- will in fact return any non-executable file found in the PATH, -- whereas shells only consider executable files. As a result, the -- user might end up with a wrong directory, not matching the one -- found by the shell. declare Ex : String_Access := GNAT.OS_Lib.Locate_Exec_On_Path (Exec_Name); Dir : constant String := Get_Install_Dir (Ex.all); begin Free (Ex); return Dir; end; end Executable_Location; ----------------- -- Skip_Blanks -- ----------------- procedure Skip_Blanks (Str : String; Index : in out Natural) is begin while Index <= Str'Last and then Is_Whitespace (Str (Index)) loop Index := Index + 1; end loop; end Skip_Blanks; -------------------------- -- Skip_Blanks_Backward -- -------------------------- procedure Skip_Blanks_Backward (Str : String; Index : in out Natural) is begin while Index >= Str'First and then Is_Whitespace (Str (Index)) loop Index := Index - 1; end loop; end Skip_Blanks_Backward; --------------- -- Find_Char -- --------------- function Find_Char (Str : String; Char : Character) return Natural is Last : Natural := Str'First; begin while Last <= Str'Last and then Str (Last) /= Char loop Last := Last + 1; end loop; return Last; end Find_Char; --------- -- EOL -- --------- function EOL (Str : String) return Natural is begin return Find_Char (Str, ASCII.LF); end EOL; ---------- -- Join -- ---------- function Join (Str : String; List : GNAT.Strings.String_List) return String is use Ada.Strings.Unbounded; Result : Unbounded_String; begin for L in List'Range loop if List (L) /= null then if Result /= Null_Unbounded_String then Append (Result, Str); end if; Append (Result, List (L).all); end if; end loop; return To_String (Result); end Join; --------------------- -- Strip_Character -- --------------------- function Strip_Character (Text : String; C : Character) return String is pragma Suppress (All_Checks); To : String (1 .. Text'Length); Index_To : Positive := 1; begin for Index in Text'Range loop if Text (Index) /= C then To (Index_To) := Text (Index); Index_To := Index_To + 1; end if; end loop; return To (1 .. Index_To - 1); end Strip_Character; -------------- -- Strip_CR -- -------------- function Strip_CR (Text : String) return String is begin return Strip_Character (Text, ASCII.CR); end Strip_CR; ------------------------ -- Get_Command_Output -- ------------------------ function Get_Command_Output (Command : access GNAT.Expect.Process_Descriptor'Class) return String is use GNAT.Expect; Output : String_Access := new String (1 .. 1024); -- Buffer used to accumulate standard output from the launched -- command, expanded as necessary during execution. Last : Integer := 0; -- Index of the last used character within Output Status : Integer; begin declare Unused_Result : Expect_Match; begin -- This loop runs until the call to Expect raises Process_Died loop Expect (Command.all, Unused_Result, ".+", Timeout => -1); declare NOutput : String_Access; S : constant String := Expect_Out (Command.all); pragma Assert (S'Length > 0); begin -- Expand buffer if we need more space. Note here that we add -- S'Length to ensure that S will fit in the new buffer size. if Last + S'Length > Output'Last then NOutput := new String (1 .. 2 * Output'Last + S'Length); NOutput (Output'Range) := Output.all; Free (Output); -- Here if current buffer size is OK else NOutput := Output; end if; NOutput (Last + 1 .. Last + S'Length) := S; Last := Last + S'Length; Output := NOutput; end; end loop; exception when Process_Died => Close (Command.all, Status); end; if Last = 0 then Free (Output); return ""; end if; declare S : constant String := Output (1 .. Last); begin Free (Output); return S; end; end Get_Command_Output; ---------------- -- Time_Value -- ---------------- function Time_Value (Str : String) return Ada.Calendar.Time is First : Integer := Str'First; Last : Integer := Str'Last; -- When no timezone is specified by the user, UTC is assumed. TZ : Duration := 0.0; TZ_Mark : constant Character_Set := To_Set ("+-"); begin if Str = "" then return No_Time; end if; -- Do we have the name of the day at the beginning of the string, as in -- Tue, 19 Dec 2006 13:59:04+00 if Str'Length > 4 and then Str (First + 3) = ',' then First := First + 5; end if; -- Check for presence of time zone information in the various formats -- specified by ISO8601. This only applies when the time is also given, -- i.e. the value is long enough (8 chars for time + at least 8 for -- date (01/02/02). if Str'Length > 16 then if Is_In (Str (Last - 2), TZ_Mark) then -- [+-]HH TZ := -Duration'Value (Str (Last - 2 .. Last)) * 3600; Last := Last - 3; elsif Is_In (Str (Last - 4), TZ_Mark) then -- [+-]HHMM TZ := -Duration'Value (Str (Last - 4 .. Last - 2)) * 3600 - Duration'Value (Str (Last - 4) & Str (Last - 1 .. Last)) * 60; Last := Last - 5; elsif Is_In (Str (Last - 5), TZ_Mark) and then Str (Last - 2) = ':' then -- [+-]HH:MM TZ := -Duration'Value (Str (Last - 5 .. Last - 3)) * 3600 - Duration'Value (Str (Last - 5) & Str (Last - 1 .. Last)) * 60; Last := Last - 6; end if; end if; -- Special case: UTC time zone speficied as 'Z' if Str'Length > 1 and then Str (Last) = 'Z' then Last := Last - 1; TZ := 0.0; -- date is given as UTC end if; -- Ignore fraction of second for S in reverse First .. Last loop if Str (S) = '.' then Last := S - 1; exit; end if; end loop; -- In ISO format, the separator between date and time is 'T', whereas -- GNAT.Calendar.Time_IO expects as space. declare S2 : String := Str (First .. Last); Local : Ada.Calendar.Time; Local_TZ : Duration; begin for S in S2'Range loop if S2 (S) = 'T' then S2 (S) := ' '; exit; end if; end loop; Local := GNAT.Calendar.Time_IO.Value (S2); -- GNAT.Calendar.Time_IO.Value uses Ada.Calendars.Time_Of, which -- for GNAT assumes the input date is in the local time zone. -- Local_TZ is used to compensated that offset. Local_TZ := Duration (Ada.Calendar.Time_Zones.UTC_Time_Offset (Local)) * 60.0; -- Time zone offset (in seconds) for the local timezone return Local + TZ + Local_TZ; end; exception when Constraint_Error => return No_Time; end Time_Value; -------------- -- Truncate -- -------------- function Truncate (Date : Time; Time_Zone : Time_Zones.Time_Offset := 0) return Time is Year : Year_Number; Month : Month_Number; Day : Day_Number; Dum1 : Day_Duration; Dum2 : Boolean; begin Formatting.Split (Date, Year, Month, Day, Dum1, Leap_Second => Dum2, Time_Zone => Time_Zone); return Formatting.Time_Of (Year, Month, Day, Time_Zone => Time_Zone); end Truncate; ---------------- -- Line_Start -- ---------------- function Line_Start (Str : String; P : Natural) return Natural is Index : Natural := Natural'Min (Str'Last, P); begin if P <= Str'First then return P; end if; if Str (Index) = ASCII.LF then Index := Index - 1; if Str (Index) = ASCII.LF then return Index + 1; elsif Str (Index) = ASCII.CR then if Index > Str'First then Index := Index - 1; if Str (Index) = ASCII.LF then return Index + 1; end if; else return Str'First; end if; end if; elsif Str (Index) = ASCII.CR then Index := Index - 1; if Str (Index) = ASCII.LF then return Index + 1; end if; end if; for J in reverse Str'First .. Index loop if Str (J) = ASCII.LF or else Str (J) = ASCII.CR then if J < Str'Last then return J + 1; else return Str'Last; end if; end if; end loop; return Str'First; end Line_Start; -------------- -- Line_End -- -------------- function Line_End (Str : String; P : Natural) return Natural is begin for J in P .. Str'Last loop if Str (J) = ASCII.LF or else Str (J) = ASCII.CR then return J - 1; end if; end loop; return Str'Last; end Line_End; --------------- -- Next_Line -- --------------- function Next_Line (Str : String; P : Natural) return Natural is begin for J in P .. Str'Last - 1 loop if Str (J) = ASCII.LF then return J + 1; end if; end loop; return Str'Last; end Next_Line; ------------------- -- Previous_Line -- ------------------- function Previous_Line (Str : String; P : Natural) return Natural is Index : constant Natural := Line_Start (Str, P); begin if Index > Str'First then return Line_Start (Str, Index - 1); else return Str'First; end if; end Previous_Line; ---------------- -- Skip_Lines -- ---------------- procedure Skip_Lines (Str : String; Lines : Integer; Index : in out Natural; Lines_Skipped : out Natural) is Index_Saved : Natural; begin Lines_Skipped := 0; if Lines >= 0 then while Lines_Skipped < Lines loop Index := Next_Line (Str, Index); if Index = Str'Last then Index := Line_Start (Str, Index); exit; end if; Lines_Skipped := Lines_Skipped + 1; end loop; else Index_Saved := Line_Start (Str, Index); while Lines_Skipped < -Lines loop Index := Previous_Line (Str, Index); exit when Index = Index_Saved; Lines_Skipped := Lines_Skipped + 1; end loop; end if; end Skip_Lines; ------------------- -- Is_Blank_Line -- ------------------- function Is_Blank_Line (Str : String; Index : Natural := 0) return Boolean is It : Natural := Index; begin if It = 0 then It := Str'First; end if; if It >= Str'First then while It <= Str'Last and then Str (It) /= ASCII.CR and then Str (It) /= ASCII.LF loop if Str (It) /= ' ' and then Str (It) /= ASCII.HT then return False; end if; It := It + 1; end loop; end if; return True; end Is_Blank_Line; -------------------- -- Skip_To_String -- -------------------- procedure Skip_To_String (Str : String; Index : in out Natural; Substring : String) is L : constant Natural := Substring'Length - 1; begin while Index + L <= Str'Last and then Str (Index .. Index + L) /= Substring loop Index := Index + 1; end loop; end Skip_To_String; ----------------------- -- Forward_UTF8_Char -- ----------------------- function Forward_UTF8_Char (Str : String; Index : Integer) return Integer is type Unicode_Char is mod 2**32; C : constant Unicode_Char := Character'Pos (Str (Index)); begin -- Compute the length of the encoding given what was in the first byte if C < 128 then return Index + 1; elsif (C and 16#E0#) = 16#C0# then return Index + 2; elsif (C and 16#F0#) = 16#E0# then return Index + 3; elsif (C and 16#F8#) = 16#F0# then return Index + 4; elsif (C and 16#FC#) = 16#F8# then return Index + 5; elsif (C and 16#FE#) = 16#FC# then return Index + 6; else -- Invalid encoding return Index + 1; end if; end Forward_UTF8_Char; -------------------- -- Skip_To_Column -- -------------------- procedure Skip_To_Column (Str : String; Columns : Integer := 0; Index : in out Integer; Tab_Width : Integer := 8) is Current_Col : Integer := 1; begin if Str = "" then return; end if; while Current_Col < Columns and then Natural (Index) <= Str'Last and then Str (Natural (Index)) /= ASCII.LF loop if Natural (Index) < Str'Last and then Str (Natural (Index)) = ASCII.HT then Current_Col := Current_Col + (Tab_Width - (Current_Col - 1) mod Tab_Width); else Current_Col := Current_Col + 1; end if; Index := Forward_UTF8_Char (Str, Natural (Index)); end loop; end Skip_To_Column; end GNATCOLL.Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-utils.ads000066400000000000000000000261651425465243200225510ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Various utility subprograms used in GNATCOLL, and that can easily be reused -- elsewhere pragma Ada_2012; with Ada.Calendar.Time_Zones; use Ada.Calendar; with Ada.Strings.Unbounded; with GNAT.Calendar; with GNAT.Expect; with GNAT.Strings; package GNATCOLL.Utils is type Cst_String_Access is access constant String; No_Time : Ada.Calendar.Time renames GNAT.Calendar.No_Time; procedure Free (List : in out GNAT.Strings.String_List); -- Free the memory used by List. -- ??? This should be moved to GNAT.Strings itself in fact function Equal (S1, S2 : String; Case_Sensitive : Boolean) return Boolean; function Case_Insensitive_Equal (S1, S2 : String) return Boolean; pragma Inline (Equal, Case_Insensitive_Equal); -- Compare two strings function Image (Value : Integer; Min_Width : Integer; Force_Sign : Boolean := False; Padding : Character := '0') return String; -- Return Value as a string, using at least Width digits (padded with -- leading characters Padding if necessary); negative values will always -- have a leading minus sign; positive values will have a leading plus sign -- if Force_Sign is True. -- If you set Min_Width to 1, the result is similar to 'Image, without the -- leading space for positive numbers. procedure Replace (S : in out Ada.Strings.Unbounded.Unbounded_String; Pattern : String; Replacement : String) with Pre => Pattern /= ""; -- Return S, with all occurrences of Pattern replaced with Replacement function Replace (S : String; Pattern : String; Replacement : String) return String with Pre => Pattern /= ""; -- Return S, with all occurrences of Pattern replaced with Replacement procedure Split (Str : String; On : String; For_Each : access function (Item : String) return Boolean); -- Split the string on the given delimiter "On" and call function For_Each -- for all found substrings not including delimiter. If function For_Each -- returns False the string processing stops. function Split (Str : String; On : Character; Omit_Empty_Lines : Boolean := True) return GNAT.Strings.String_List_Access; -- Split the string on the given character. -- The result depends on the value of Omit_Empty_Lines. For instance, the -- string "a" & ASCII.LF & ASCII.LF & "b" will be split as: -- ["a", "b"] if Omit_Empty_Lines is true -- ["a", "", "b"] otherwise -- -- Result must be freed by caller. -- See also Split below -- -- For a more efficient version, see GNATCOLL.Strings type Unbounded_String_Array is array (Natural range <>) of Ada.Strings.Unbounded.Unbounded_String; function Split (Str : String; On : Character; Omit_Empty_Lines : Boolean := True) return Unbounded_String_Array; -- Same as Split above, returning an Unbounded_String_Array that does not -- need to be freed. -- For a more efficient version, see GNATCOLL.Strings function Capitalize (Name : String) return String; -- Capitalize a string, ie put in upper case the first character and all -- characters following '_' function Is_Whitespace (Char : Character) return Boolean; -- Returns True if Char is a space, new line, or tab; otherwise returns -- False. function Starts_With (Str : String; Prefix : String) return Boolean; -- Returns True if Str starts with Prefix -- See also GNATCOLL.Strings. function Ends_With (Str : String; Suffix : String) return Boolean; -- Returns True if Str ends with Suffix -- See also GNATCOLL.Strings. procedure Skip_Blanks (Str : String; Index : in out Natural); procedure Skip_Blanks_Backward (Str : String; Index : in out Natural); -- If Str(Index) is a white space, new line, or tab, then skip it and all -- following ones. On exit, Index points to the first non white space -- character, or after Str'Last. -- Skip_Blanks_Backward moves Index backward instead, and will leave it -- before Str'First if no non-whitespace was found. function Find_Char (Str : String; Char : Character) return Natural; -- Return the first occurrence of Char after Str'First (use substrings for -- later occurrences). -- See also GNATCOLL.Strings.Find function Join (Str : String; List : GNAT.Strings.String_List) return String; -- Return a string that is the concatenation of the list elements, -- separated by Str: (List(1) & Str & List(2) & Str & ...) -- null elements in list are skipped -- See also GNATCOLL.Strings.Join function EOL (Str : String) return Natural; pragma Inline (EOL); -- Return the first end-of-line after Str'First (use substrings for later -- lines). The result is either Str'Last+1 or pointing to the first -- ASCII.LF found. function Line_Start (Str : String; P : Natural) return Natural; -- Return the start of the line pointed by P -- See also GNATCOLL.Strings.Head function Line_End (Str : String; P : Natural) return Natural; -- Return the end of the line pointed by P -- See also GNATCOLL.Strings.Tail procedure Skip_Lines (Str : String; Lines : Integer; Index : in out Natural; Lines_Skipped : out Natural); -- Skip Lines forward or backward. Index is set to the beginning of a line. -- Lines_Skipped is the number of lines that have actually been skipped. -- Use with Skip_To_Column to go to a specific position in a buffer. procedure Skip_To_Column (Str : String; Columns : Integer := 0; Index : in out Integer; Tab_Width : Integer := 8); -- Assuming Index points to the begining of a line (as is the case after -- Skip_Lines for instance), jump to the specific column on that line. -- This procedure handles tabulations (ie Columns are columns visible to -- the user, after tab expansion). function Forward_UTF8_Char (Str : String; Index : Integer) return Integer; -- Moves Index one character forward, taking into account UTF8 encoding. function Next_Line (Str : String; P : Natural) return Natural; -- Return the start of the next line or Buffer'Last if the end of the -- buffer is reached. function Previous_Line (Str : String; P : Natural) return Natural; -- Return the start of the previous line or Buffer'First if P already -- points to the first line of Buffer. function Is_Blank_Line (Str : String; Index : Natural := 0) return Boolean; -- Return True if the line pointed by Index only contains blank characters -- (' ', HT, LF, CR). By default, if Index is 0, then the line considered -- is the first line of the buffer. procedure Skip_To_String (Str : String; Index : in out Natural; Substring : String); -- Skip every character until an occurence of Substring is found. -- Index is set to the first character of the occurence. function Strip_Character (Text : String; C : Character) return String; -- Return a version of Text after stripping all C's from the string function Strip_CR (Text : String) return String; pragma Inline (Strip_CR); -- Return a version of Text after stripping all the CR from the string. -- This function is used on Windows or when the Strip_CR preference is -- enabled (for systems that share dos files). -- CR/LF sequences are replaced by LF chars. ------------ -- Expect -- ------------ function Get_Command_Output (Command : access GNAT.Expect.Process_Descriptor'Class) return String; -- Runs Command until it finishes, and return its output. -- This automatically closes the process cleanly. ------------------ -- File systems -- ------------------ function Executable_Location return String; -- Return the name of the parent directory where the executable is stored -- (so if you are running "prefix"/bin/gps, you would get "prefix"). -- A special case is done for "bin" directories, which are skipped. -- The returned directory always ends up with a directory separator. function Is_Directory_Separator (C : Character) return Boolean; -- Returns True if C is a directory separator procedure Set_OpenVMS_Host (Setting : Boolean := True); -- Set whether the host is an OpenVMS host ----------- -- Dates -- ----------- function Time_Value (Str : String) return Ada.Calendar.Time; -- Check the validity of Str as a string representing a date -- using the same formats as in GNAT.Calendar.Time_IO.Value. In addition, -- it also supports timezones (as output for instance by PostgreSQL) -- 1970-01-01 12:00:00+01 -- and the ISO format -- 1970-01-01T12:00:00+01 or 1970-01-01T12:00:00Z -- All the above can start with the day spelled out, as in "thu, " -- -- The input date is assumed to be in UTC unless a timezone is specified -- as hours with a final "[+-]\d\d", or as hours and minutes with -- "[+-]\d\d\d\d" or "[+-]\d\d:\d\d" function Truncate (Date : Time; Time_Zone : Time_Zones.Time_Offset := 0) return Time; -- Remove time part from the date in specified timezone. -- For example, if we want to truncate "2015 May 10 05:00 GMT+6" time at -- UTC timezone we are going to get "2015 May 9, 00:00 UTC" because -- "2015 May 10 05:00 GMT+6" equal to "2015 May 9 23:00 UTC". end GNATCOLL.Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-vfs.adb000066400000000000000000001633061425465243200221650ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Calendar; use Ada.Calendar; with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Exceptions; use Ada.Exceptions; with Ada.Tags; use Ada.Tags; with Ada.Strings.Hash; with Ada.Strings.Hash_Case_Insensitive; with Ada.Text_IO; with Ada.Unchecked_Conversion; with System; with GNAT.Heap_Sort; use GNAT.Heap_Sort; with GNATCOLL.Utils; use GNATCOLL.Utils; with GNATCOLL.IO; use GNATCOLL.IO; with GNATCOLL.IO.Remote; use GNATCOLL.IO.Remote; with GNATCOLL.Path; use GNATCOLL.Path; with GNATCOLL.Remote; use GNATCOLL.Remote; with GNATCOLL.Remote.Db; use GNATCOLL.Remote.Db; with GNATCOLL.VFS_Types; use GNATCOLL.VFS_Types; -- Cannot use GNATCOLL.Traces, or we end up with elaboration cycle package body GNATCOLL.VFS is Empty_String : aliased Filesystem_String := ""; Handle_Symbolic_Links : Boolean := GNAT.OS_Lib.Directory_Separator /= '\'; -- If this variable is False, we assume there is never any symbolic link, -- and thus we do not spend time resolving them. function "+" (S : Filesystem_String) return FS_String; function "+" (S : FS_String) return Filesystem_String; function "+" (S : FS_String) return String; pragma Inline ("+"); -- FS_String and Filesystem_String are identical in their intent. -- We just have a visibility issue as it really should be defined in -- VFS's spec, so can't be used by underneath packages (GNATCOLL.IO and -- GNATCOLL.Path) function "+" is new Ada.Unchecked_Conversion (FS_String_Access, Filesystem_String_Access); procedure Ensure_Normalized (File : Virtual_File'Class; Resolve_Symlinks : Boolean); -- Make sure that File.Value.Normalized is filled --------- -- "+" -- --------- function "+" (S : Filesystem_String) return FS_String is begin return FS_String (S); end "+"; function "+" (S : FS_String) return Filesystem_String is begin return Filesystem_String (S); end "+"; function "+" (S : FS_String) return String is begin return String (S); end "+"; function "+" (S : Filesystem_String) return String is begin return String (S); end "+"; function "+" (S : String) return Filesystem_String is begin return Filesystem_String (S); end "+"; --------- -- "=" -- --------- function Equal (S1, S2 : Filesystem_String) return Boolean is begin return Equal (+S1, +S2, Is_Case_Sensitive (Local_FS)); end Equal; --------- -- "=" -- --------- function "=" (File1, File2 : Virtual_File) return Boolean is begin -- Test for the same pointer to actual value (or both null) if File1.Value = File2.Value then return True; -- Test if one of the values is null elsif File1.Value = null or else File2.Value = null or else File1.Value.all'Tag /= File2.Value.all'Tag then return False; -- Finally, we test the normalized paths else Ensure_Normalized (File1, Resolve_Symlinks => True); Ensure_Normalized (File2, Resolve_Symlinks => True); -- We also take care of potential trailing dir separator by enforcing -- them return Equal (File1.Value.Get_FS, Ensure_Directory (File1.Value.Get_FS, File1.Value.Normalized_And_Resolved.all), Ensure_Directory (File1.Value.Get_FS, File2.Value.Normalized_And_Resolved.all)); end if; end "="; --------- -- "<" -- --------- function "<" (File1, File2 : Virtual_File) return Boolean is C1, C2 : Character; Ind1, Ind2 : Integer; Case_Sensitive : Boolean; begin if File1 = File2 then return False; elsif File1.Value = null then return True; elsif File2.Value = null then return False; elsif Is_Local (File1.Value.all) /= Is_Local (File2.Value.all) then return Is_Local (File1.Value.all); elsif not Is_Local (File1.Value.all) and then Get_Host (File1) /= Get_Host (File2) then return Get_Host (File1) < Get_Host (File2); else Case_Sensitive := Is_Case_Sensitive (File1.Value.Get_FS) and then Is_Case_Sensitive (File2.Value.Get_FS); Ensure_Normalized (File1, Resolve_Symlinks => True); Ensure_Normalized (File2, Resolve_Symlinks => True); if Case_Sensitive then return File1.Value.Normalized_And_Resolved.all < File2.Value.Normalized_And_Resolved.all; else Ind1 := File1.Value.Normalized_And_Resolved'First; Ind2 := File2.Value.Normalized_And_Resolved'First; for C in 1 .. File1.Value.Normalized_And_Resolved'Length loop if Ind2 > File2.Value.Normalized_And_Resolved'Last then return False; end if; C1 := To_Lower (File1.Value.Normalized_And_Resolved (Ind1)); C2 := To_Lower (File2.Value.Normalized_And_Resolved (Ind2)); if C1 < C2 then return True; elsif C1 > C2 then return False; end if; Ind1 := Ind1 + 1; Ind2 := Ind2 + 1; end loop; return True; end if; end if; end "<"; ------------ -- Create -- ------------ function Create (Full_Filename : Filesystem_String; Host : String := Local_Host; Normalize : Boolean := False) return Virtual_File is function Internal_Get_Path (FS : FS_Type) return FS_String; -- Get Full_Filename according to Normalize setting ----------------------- -- Internal_Get_Path -- ----------------------- function Internal_Get_Path (FS : FS_Type) return FS_String is begin if not Normalize then return +Full_Filename; end if; return GNATCOLL.Path.Normalize (FS, +Full_Filename); end Internal_Get_Path; begin if Full_Filename = "" then return No_File; end if; if Host = Local_Host then return (Ada.Finalization.Controlled with Value => GNATCOLL.IO.Native.Create (Internal_Get_Path (GNATCOLL.Path.Local_FS))); else return (Ada.Finalization.Controlled with Value => GNATCOLL.IO.Remote.Create (Host, +Full_Filename, Normalize)); end if; end Create; ---------------------- -- Create_From_UTF8 -- ---------------------- function Create_From_UTF8 (Full_Filename : String; Host : String := Local_Host; Normalize : Boolean := False) return Virtual_File is begin if Host = Local_Host then return Create (+GNATCOLL.IO.Native.Codec.From_UTF8 (Full_Filename), Normalize => Normalize); else return Create (+GNATCOLL.IO.Remote.Codec.From_UTF8 (Full_Filename), Host, Normalize => Normalize); end if; end Create_From_UTF8; ---------------------- -- Create_From_Base -- ---------------------- function Create_From_Base (Base_Name : Filesystem_String; Base_Dir : Filesystem_String := ""; Host : String := Local_Host) return Virtual_File is FS : FS_Type; begin if Host = Local_Host then FS := Local_FS; else FS := Shell_FS (Get_Server (Host).all); end if; declare The_Name : constant FS_String := Path.From_Unix (FS, +Base_Name); The_Dir : constant FS_String := Path.From_Unix (FS, +Base_Dir); begin if Is_Absolute_Path (FS, The_Name) then return Create (+The_Name, Host); elsif The_Dir /= "" then return Create (+(Path.Ensure_Directory (FS, The_Dir) & The_Name), Host); else return Create_From_Dir (Get_Current_Dir (Host), +The_Name); end if; end; end Create_From_Base; --------------------- -- Create_From_Dir -- --------------------- function Create_From_Dir (Dir : Virtual_File; Base_Name : Filesystem_String; Normalize : Boolean := False) return Virtual_File is begin if Dir.Value = null then raise VFS_Invalid_File_Error; end if; Dir.Ensure_Directory; return (Ada.Finalization.Controlled with Dispatching_Create (Ref => Dir.Value, Full_Path => FS_String (Dir.Full_Name (Normalize).all) & From_Unix (Dir.Value.Get_FS, +Base_Name))); end Create_From_Dir; -------------------- -- Locate_On_Path -- -------------------- function Locate_On_Path (Base_Name : Filesystem_String; Host : String := Local_Host) return Virtual_File is Name : GNAT.OS_Lib.String_Access; Ret : Virtual_File; use type GNAT.OS_Lib.String_Access; begin if Host = Local_Host then if Is_Absolute_Path (Local_FS, +Base_Name) then return Create (Base_Name); end if; Name := GNAT.OS_Lib.Locate_Exec_On_Path (+Base_Name); if Name = null then return No_File; else Ret := Create (+Name.all); GNAT.OS_Lib.Free (Name); return Ret; end if; else declare Int : constant GNATCOLL.IO.File_Access := GNATCOLL.IO.Remote.Locate_On_Path (Host, +Base_Name); begin if Int = null then return No_File; else return (Ada.Finalization.Controlled with Int); end if; end; end if; end Locate_On_Path; ----------------------- -- Get_Tmp_Directory -- ----------------------- function Get_Tmp_Directory (Host : String := Local_Host) return Virtual_File is begin if Host = Local_Host then return (Ada.Finalization.Controlled with GNATCOLL.IO.Native.Get_Tmp_Directory); else return (Ada.Finalization.Controlled with GNATCOLL.IO.Remote.Get_Tmp_Directory (Host)); end if; end Get_Tmp_Directory; ------------------------ -- Get_Home_Directory -- ------------------------ function Get_Home_Directory (Host : String := Local_Host) return Virtual_File is begin if Host = Local_Host then return (Ada.Finalization.Controlled with GNATCOLL.IO.Native.Home_Dir); else return (Ada.Finalization.Controlled with GNATCOLL.IO.Remote.Home_Dir (Host)); end if; end Get_Home_Directory; ------------------------ -- Get_Logical_Drives -- ------------------------ function Get_Logical_Drives (Host : String := Local_Host) return File_Array_Access is function Get_IO_List return GNATCOLL.IO.File_Array; -- Get the IO list depending on Host ----------------- -- Get_IO_List -- ----------------- function Get_IO_List return GNATCOLL.IO.File_Array is begin if Host = Local_Host then return GNATCOLL.IO.Native.Get_Logical_Drives; else return GNATCOLL.IO.Remote.Get_Logical_Drives (Host); end if; end Get_IO_List; List : constant GNATCOLL.IO.File_Array := Get_IO_List; Ret : constant File_Array_Access := new File_Array (1 .. List'Length); begin for J in List'Range loop Ret (J - List'First + 1) := (Ada.Finalization.Controlled with List (J)); Ret (J - List'First + 1).Value.Kind := Directory; end loop; return Ret; end Get_Logical_Drives; --------------------- -- Get_Current_Dir -- --------------------- function Get_Current_Dir (Host : String := Local_Host) return Virtual_File is Ret : Virtual_File; begin if Host = Local_Host then Ret := (Ada.Finalization.Controlled with GNATCOLL.IO.Native.Current_Dir); else Ret := (Ada.Finalization.Controlled with GNATCOLL.IO.Remote.Current_Dir (Host)); end if; Ret.Value.Kind := Directory; return Ret; end Get_Current_Dir; --------------- -- Base_Name -- --------------- function Base_Name (File : Virtual_File; Suffix : Filesystem_String := ""; Normalize : Boolean := False) return Filesystem_String is begin if File.Value = null then return ""; end if; if Normalize then Ensure_Normalized (File, Resolve_Symlinks => True); return +Base_Name (File.Value.Get_FS, File.Value.Normalized_And_Resolved.all, +Suffix); else return +Base_Name (File.Value.Get_FS, File.Value.Full.all, +Suffix); end if; end Base_Name; ------------------- -- Base_Dir_Name -- ------------------- function Base_Dir_Name (File : Virtual_File) return Filesystem_String is begin if File.Value = null then return ""; end if; return +Base_Dir_Name (File.Value.Get_FS, File.Value.Full.all); end Base_Dir_Name; --------------- -- Full_Name -- --------------- function Full_Name (File : Virtual_File; Normalize : Boolean := False) return Filesystem_String is begin return File.Full_Name (Normalize).all; end Full_Name; --------------- -- Full_Name -- --------------- function Full_Name (File : Virtual_File; Normalize : Boolean := False; Resolve_Links : Boolean := False) return Cst_Filesystem_String_Access is begin if File.Value = null then return Empty_String'Access; elsif File.Value.Full /= null and then Normalize then Ensure_Normalized (File, Resolve_Links); if Resolve_Links then return Cst_Filesystem_String_Access (+File.Value.Normalized_And_Resolved.all'Access); else return Cst_Filesystem_String_Access (+File.Value.Normalized.all'Access); end if; elsif File.Value.Full = null and then Get_Host (File) /= Local_Host then GNATCOLL.IO.Remote.Ensure_Initialized (GNATCOLL.IO.Remote.Remote_File_Access (File.Value)); return Cst_Filesystem_String_Access (+File.Value.Full.all'Access); else return Cst_Filesystem_String_Access (+File.Value.Full.all'Access); end if; end Full_Name; -------------------- -- Full_Name_Hash -- -------------------- function Full_Name_Hash (Key : Virtual_File) return Ada.Containers.Hash_Type is F : FS_Type; begin if Key.Value = null then return 0; end if; Ensure_Normalized (Key, Resolve_Symlinks => True); -- We also take care of potential trailing dir separator by enforcing -- them. The goal is that we have the same hash whenever "=" returns -- True, so that we can instantiate hash tables by using "=" for the -- equivalent key function F := Key.Value.Get_FS; if Is_Case_Sensitive (F) then return Ada.Strings.Hash (+Ensure_Directory (F, Key.Value.Normalized_And_Resolved.all)); else return Ada.Strings.Hash_Case_Insensitive (+Ensure_Directory (F, Key.Value.Normalized_And_Resolved.all)); end if; end Full_Name_Hash; -------------- -- Dir_Name -- -------------- function Dir_Name (File : Virtual_File) return Filesystem_String is begin if File.Value = null then return ""; end if; return +Dir_Name (File.Value.Get_FS, File.Value.Full.all); end Dir_Name; --------- -- Dir -- --------- function Dir (File : Virtual_File) return Virtual_File is begin if File.Value = null then return VFS.No_File; end if; if Is_Dir_Name (File.Value.Get_FS, File.Value.Full.all) then return File; else return (Ada.Finalization.Controlled with Value => Dispatching_Create (File.Value, Dir_Name (File.Value.Get_FS, File.Value.Full.all))); end if; end Dir; ----------------------- -- Display_Full_Name -- ----------------------- function Display_Full_Name (File : Virtual_File; Normalize : Boolean := False) return String is begin if File.Value = null then return ""; else return File.Value.To_UTF8 (FS_String (File.Full_Name (Normalize).all)); end if; end Display_Full_Name; ----------------------- -- Display_Base_Name -- ----------------------- function Display_Base_Name (File : Virtual_File; Suffix : Filesystem_String := "") return String is begin if File.Value = null then return ""; else return File.Value.To_UTF8 (+File.Base_Name (Suffix)); end if; end Display_Base_Name; --------------------- -- Locale_Dir_Name -- --------------------- function Display_Dir_Name (File : Virtual_File) return String is begin if File.Value = null then return ""; else return File.Value.To_UTF8 (+File.Dir_Name); end if; end Display_Dir_Name; --------------------------- -- Display_Base_Dir_Name -- --------------------------- function Display_Base_Dir_Name (File : Virtual_File) return String is begin if File.Value = null then return ""; else return File.Value.To_UTF8 (+File.Base_Dir_Name); end if; end Display_Base_Dir_Name; -------------------------- -- Unix_Style_Full_Name -- -------------------------- function Unix_Style_Full_Name (File : Virtual_File; Cygwin_Style : Boolean := False; Normalize : Boolean := False; Casing : Boolean := False) return Filesystem_String is FS : FS_Type; function Auto_Case (Str : FS_String) return Filesystem_String; function Auto_Case (Str : FS_String) return Filesystem_String is begin if not Casing or else Is_Case_Sensitive (FS) then return +Str; else return +To_Lower (+Str); end if; end Auto_Case; begin if File.Value = null then return ""; else FS := File.Value.Get_FS; if Normalize then return Auto_Case (To_Unix (FS, +Full_Name (File, Normalize => Normalize, Resolve_Links => True).all, Cygwin_Style)); else return Auto_Case (To_Unix (FS, File.Value.Full.all, Cygwin_Style)); end if; end if; end Unix_Style_Full_Name; ------------------- -- Relative_Path -- ------------------- function Relative_Path (File : Virtual_File; From : Virtual_File) return Filesystem_String is begin -- Obviously, we need from to be a directory... if not Is_Directory (From) then return File.Full_Name; end if; if From.Value = null or else File.Value = null or else File.Value'Tag /= From.Value'Tag then return File.Full_Name; end if; return Filesystem_String (Relative_Path (File.Value.Get_FS, Ref => FS_String (From.Full_Name.all), Path => FS_String (File.Full_Name.all))); end Relative_Path; ---------------- -- Has_Suffix -- ---------------- function Has_Suffix (File : Virtual_File; Suffix : Filesystem_String) return Boolean is begin return File.Value /= null and then File.Full_Name.all'Length >= Suffix'Length and then Equal (File.Value.Get_FS, File.Value.Full (File.Value.Full'Last - Suffix'Length + 1 .. File.Value.Full'Last), +Suffix); end Has_Suffix; --------------- -- To_Remote -- --------------- function To_Remote (File : Virtual_File; To_Host : String) return Virtual_File is begin if File.Value = null then return No_File; end if; if File.Get_Host = To_Host then return File; end if; if not Is_Configured (To_Host) then raise VFS_Remote_Config_Error; end if; declare Server : constant Server_Access := Get_Server (To_Host); Local : Virtual_File; Remote : Virtual_File := No_File; begin for J in 1 .. Nb_Mount_Points (Server.Nickname) loop Local := Create (+Get_Mount_Point_Local_Root (Server.Nickname, J)); if Local.Is_Parent (File) then Remote := Create (+Get_Mount_Point_Host_Root (Server.Nickname, J), To_Host); exit; end if; end loop; if Remote = No_File then -- Simple conversion return Convert (File, To_Host); else return Convert (File, Local, Remote); end if; end; end To_Remote; -------------- -- To_Local -- -------------- function To_Local (File : Virtual_File) return Virtual_File is begin if File.Value = null then return No_File; end if; if File.Is_Local then return File; end if; if not Is_Configured (File.Get_Host) then raise VFS_Remote_Config_Error; end if; declare Server : constant Server_Access := Get_Server (File.Get_Host); Local : Virtual_File := No_File; Remote : Virtual_File; begin for J in 1 .. Nb_Mount_Points (Server.Nickname) loop Remote := Create (+Get_Mount_Point_Host_Root (Server.Nickname, J), File.Get_Host); if Remote.Is_Parent (File) then Local := Create (+Get_Mount_Point_Local_Root (Server.Nickname, J)); exit; end if; end loop; if Local = No_File then -- Simple conversion return Convert (File, Local_Host); else return Convert (File, Remote, Local); end if; end; end To_Local; ------------ -- To_Arg -- ------------ function To_Arg (File : Virtual_File; Host : String := Local_Host) return GNAT.Strings.String_Access is Host_File : Virtual_File; begin if Host /= File.Get_Host then if File.Get_Host /= Local_Host then Host_File := File.To_Local; else Host_File := File; end if; if Host /= Local_Host then Host_File := Host_File.To_Remote (Host); end if; return new String'(String (Host_File.Full_Name.all)); end if; return new String'(String (File.Full_Name.all)); end To_Arg; ------------- -- Convert -- ------------- function Convert (File : Virtual_File; To_Host : String) return Virtual_File is begin if File.Value = null then return No_File; end if; -- Create always handles both paths in Unix form, or paths in Host's -- form. So we first translate the path to unix (possible whatever the -- current path format is), then it's up to Create to correctly format -- the path. return Create (+To_Unix (File.Value.Get_FS, FS_String (File.Full_Name.all)), To_Host); end Convert; ------------- -- Convert -- ------------- function Convert (File : Virtual_File; From_Dir : Virtual_File; To_Dir : Virtual_File) return Virtual_File is begin if File.Value = null or else From_Dir.Value = null or else To_Dir.Value = null then return No_File; end if; if From_Dir.Value.Get_FS /= To_Dir.Value.Get_FS then return Create_From_Dir (To_Dir, +To_Unix (File.Value.Get_FS, +File.Relative_Path (From_Dir))); else return Create_From_Dir (To_Dir, File.Relative_Path (From_Dir)); end if; end Convert; -------------------- -- Unchecked_Free -- -------------------- procedure Unchecked_Free (Arr : in out File_Array_Access) is procedure Internal is new Ada.Unchecked_Deallocation (File_Array, File_Array_Access); begin Internal (Arr); end Unchecked_Free; -------------- -- Is_Local -- -------------- function Is_Local (File : Virtual_File) return Boolean is begin return File.Value = null or else File.Value.all in GNATCOLL.IO.Native.Native_File_Record'Class; end Is_Local; ---------- -- Host -- ---------- function Get_Host (File : Virtual_File) return String is begin if Is_Local (File) then return Local_Host; else return GNATCOLL.IO.Remote.Get_Host (Remote_File_Record (File.Value.all)'Access); end if; end Get_Host; --------------------- -- Is_Regular_File -- --------------------- function Is_Regular_File (File : Virtual_File) return Boolean is Ret : Boolean; begin if File.Value = null then return False; elsif File.Value.all not in GNATCOLL.IO.Native.Native_File_Record'Class and then File.Value.Kind /= Unknown -- Only use cache for remote files then return File.Value.Kind = GNATCOLL.IO.File; else Ret := File.Value.Is_Regular_File; if Ret then File.Value.Kind := GNATCOLL.IO.File; end if; return Ret; end if; end Is_Regular_File; ---------- -- Size -- ---------- function Size (File : Virtual_File) return Long_Integer is begin if File.Value = null then return 0; else return File.Value.Size; end if; end Size; ------------ -- Rename -- ------------ procedure Rename (File : Virtual_File; Full_Name : Virtual_File; Success : out Boolean) is begin if File.Value = null or else Full_Name.Value = null or else File.Value'Tag /= Full_Name.Value'Tag then Success := False; else Rename (File.Value, Full_Name.Value, Success); if Success then Full_Name.Value.Kind := File.Value.Kind; File.Value.Kind := Unknown; end if; end if; end Rename; ---------- -- Copy -- ---------- procedure Copy (File : Virtual_File; Target_Name : Filesystem_String; Success : out Boolean) is begin if File.Value = null then Success := False; end if; if Is_Directory (File) then File.Value.Copy_Dir (+Target_Name, Success); else File.Value.Copy (+Target_Name, Success); end if; end Copy; ------------ -- Delete -- ------------ procedure Delete (File : Virtual_File; Success : out Boolean) is begin if File.Value = null then Success := False; else File.Value.Delete (Success); end if; end Delete; ----------------- -- Is_Readable -- ----------------- function Is_Readable (File : Virtual_File) return Boolean is begin return File.Value /= null and then File.Value.Is_Readable; end Is_Readable; ----------------- -- Is_Writable -- ----------------- function Is_Writable (File : Virtual_File) return Boolean is begin return File.Value /= null and then File.Value.Is_Writable; end Is_Writable; ------------------ -- Is_Directory -- ------------------ function Is_Directory (VF : Virtual_File) return Boolean is Ret : Boolean; begin if VF.Value = null then return False; elsif VF.Value.all not in GNATCOLL.IO.Native.Native_File_Record'Class and then VF.Value.Kind /= Unknown -- Only use cache for remote files then return VF.Value.Kind = Directory; else Ret := VF.Value.Is_Directory; if Ret then VF.Ensure_Directory; VF.Value.Kind := Directory; end if; return Ret; end if; end Is_Directory; ---------------------- -- Is_Symbolic_Link -- ---------------------- function Is_Symbolic_Link (File : Virtual_File) return Boolean is begin return File.Value /= null and then File.Value.Is_Symbolic_Link; end Is_Symbolic_Link; ---------------------- -- Is_Absolute_Path -- ---------------------- function Is_Absolute_Path (File : Virtual_File) return Boolean is begin return File.Value /= null and then Is_Absolute_Path (File.Value.Get_FS, File.Value.Full.all); end Is_Absolute_Path; -------------------- -- File_Extension -- -------------------- function File_Extension (File : Virtual_File; Normalize : Boolean := False) return Filesystem_String is begin if File.Value = null then return ""; else return Filesystem_String (File_Extension (File.Value.Get_FS, FS_String (File.Full_Name (Normalize).all))); end if; end File_Extension; --------------- -- Read_File -- --------------- function Read_File (File : Virtual_File) return GNAT.Strings.String_Access is begin if File.Value = null then return null; elsif File.Value.Kind = Directory then return null; else return File.Value.Read_Whole_File; end if; end Read_File; --------------- -- Read_File -- --------------- function Read_File (File : Virtual_File) return GNATCOLL.Strings.XString is begin if File.Value = null or else File.Value.Kind = Directory then return GNATCOLL.Strings.Null_XString; else return File.Value.Read_Whole_File; end if; end Read_File; ---------------- -- Write_File -- ---------------- function Write_File (File : Virtual_File; Append : Boolean := False) return Writable_File is use type GNAT.OS_Lib.File_Descriptor; W : Writable_File; begin if File.Value = null then return Invalid_File; end if; W.File := File; W.Append := Append; W.Success := True; if not Append or else not File.Is_Regular_File then W.Tmp_File := Create (File.Full_Name.all & "~", Host => File.Get_Host); W.Tmp_File.Value.Open_Write (Append => False, FD => W.FD); else W.Tmp_File := No_File; -- append-mode, and the file already exists. File.Value.Open_Write (Append => True, FD => W.FD); end if; if W.FD = GNAT.OS_Lib.Invalid_FD then return Invalid_File; else return W; end if; end Write_File; ----------- -- Write -- ----------- procedure Write (File : in out Writable_File; Str : String) is Written : aliased Integer; begin if File.Success then Written := GNAT.OS_Lib.Write (File.FD, Str'Address, Str'Length); File.Success := Written = Str'Length; if Written > 0 then -- File has been overwritten on the disk anyway if File.Tmp_File /= No_File then File.Tmp_File.Value.Kind := GNATCOLL.IO.File; else File.File.Value.Kind := GNATCOLL.IO.File; end if; end if; end if; end Write; ----------- -- Write -- ----------- procedure Write (File : in out Writable_File; Str : chars_ptr) is Written : aliased Integer; Len : Integer; function To_Address is new Ada.Unchecked_Conversion (chars_ptr, System.Address); begin if File.Success then Len := Integer (Strlen (Str)); Written := GNAT.OS_Lib.Write (File.FD, To_Address (Str), Len); File.Success := Written = Len; if Written > 0 then File.File.Value.Kind := GNATCOLL.IO.File; end if; end if; end Write; ----------- -- Close -- ----------- procedure Close (File : in out Writable_File) is Norm : Virtual_File; Success : Boolean; -- We'll need to force the resolution of symbolic links, -- since we never want to transform a link into a regular -- file (which among other things breaks support for CM Synergy) Save_Handle_Symbolic_Links : constant Boolean := Handle_Symbolic_Links; begin if File.Success then if File.Tmp_File /= No_File then File.Tmp_File.Value.Close (File.FD, File.Success); if File.Success then -- Look past symbolic links. We do not want to impact the -- normalized name saved in File, so we need to use local -- copies. Handle_Symbolic_Links := True; Norm := Create (File.File.Full_Name.all); Norm := Create (Norm.Full_Name (Normalize => True, Resolve_Links => True).all); Handle_Symbolic_Links := Save_Handle_Symbolic_Links; -- Preserve permissions on the file Copy_File_Permissions (From => Norm.Value, To => File.Tmp_File.Value, Success => Success); -- ??? We ignore the value of success here. It is not a -- critical error, however, and we want to continue the -- process of saving here. It would be nice to log this, -- but we cannot use Traces in this package. -- We use to delete explicitly Norm. But in fact this is not a -- good idea, since the directory might allow us to delete the -- file (or not), but not to recreate it afterwards, as seem to -- be the case with CM Synergy. File.Tmp_File.Rename (Norm, File.Success); if not File.Success then -- Renaming failed. It might be because it could not -- remove the original (read-only directory for instance) -- so let's try with a simple copy instead File.Tmp_File.Copy (Norm.Full_Name (Normalize => True).all, File.Success); if File.Success then File.Tmp_File.Delete (Success); -- ignore Success, that's fine if the temp file is -- still there. end if; end if; end if; else File.File.Value.Close (File.FD, File.Success); end if; end if; if not File.Success then raise Ada.Text_IO.Use_Error with "Error while writing to the file"; end if; end Close; ------------------ -- Set_Writable -- ------------------ procedure Set_Writable (File : VFS.Virtual_File; Writable : Boolean) is begin if File.Value = null then raise VFS_Invalid_File_Error; end if; File.Value.Set_Writable (Writable); end Set_Writable; ------------------ -- Set_Readable -- ------------------ procedure Set_Readable (File : VFS.Virtual_File; Readable : Boolean) is begin if File.Value = null then raise VFS_Invalid_File_Error; end if; File.Value.Set_Readable (Readable); end Set_Readable; --------------------- -- File_Time_Stamp -- --------------------- function File_Time_Stamp (File : Virtual_File) return Ada.Calendar.Time is begin if File.Value = null then return GNATCOLL.Utils.No_Time; end if; return File.Value.File_Time_Stamp; end File_Time_Stamp; ---------------------- -- Ensure_Directory -- ---------------------- procedure Ensure_Directory (Dir : Virtual_File) is Full : FS_String_Access; begin if Dir.Value /= null then if not Is_Dir_Name (Dir.Value.Get_FS, Dir.Value.Full.all) then Full := new FS_String' (Ensure_Directory (Dir.Value.Get_FS, Dir.Value.Full.all)); Free (Dir.Value.Full); Dir.Value.Full := Full; end if; if Dir.Value.Normalized /= null and then not Is_Dir_Name (Dir.Value.Get_FS, Dir.Value.Normalized.all) then Full := new FS_String' (Ensure_Directory (Dir.Value.Get_FS, Dir.Value.Normalized.all)); if Dir.Value.Normalized /= Dir.Value.Normalized_And_Resolved then Free (Dir.Value.Normalized_And_Resolved); end if; Free (Dir.Value.Normalized); Dir.Value.Normalized_And_Resolved := null; Dir.Value.Normalized := Full; end if; end if; end Ensure_Directory; ----------------------- -- Ensure_Normalized -- ----------------------- procedure Ensure_Normalized (File : Virtual_File'Class; Resolve_Symlinks : Boolean) is begin if File.Value = null then return; end if; if File.Value.Normalized = null then File.Value.Normalized := new FS_String' (Path.Normalize (File.Value.Get_FS, File.Value.Full.all)); end if; if Resolve_Symlinks then if Handle_Symbolic_Links then GNATCOLL.IO.Resolve_Symlinks (File.Value); else if File.Value.Normalized_And_Resolved = null then File.Value.Normalized_And_Resolved := File.Value.Normalized; end if; end if; end if; end Ensure_Normalized; -------------------- -- Normalize_Path -- -------------------- procedure Normalize_Path (File : Virtual_File; Resolve_Symlinks : Boolean := False) is begin if File.Value = null then return; end if; Ensure_Normalized (File, Resolve_Symlinks); Free (File.Value.Full); if Resolve_Symlinks then File.Value.Full := new FS_String'(File.Value.Normalized_And_Resolved.all); else File.Value.Full := new FS_String'(File.Value.Normalized.all); end if; end Normalize_Path; -------------- -- Get_Root -- -------------- function Get_Root (File : Virtual_File) return Virtual_File is begin if File.Value = null then return No_File; end if; return (Ada.Finalization.Controlled with Dispatching_Create (File.Value, Get_Root (File.Value.Get_FS, File.Value.Full.all))); end Get_Root; ---------------- -- Get_Parent -- ---------------- function Get_Parent (Dir : Virtual_File) return Virtual_File is begin if Dir.Value = null then return No_File; end if; declare Parent : constant FS_String := Get_Parent (Dir.Value.Get_FS, Dir.Value.Full.all); begin if Parent = "" then return No_File; else return (Ada.Finalization.Controlled with Dispatching_Create (Dir.Value, Parent)); end if; end; end Get_Parent; ------------- -- Sub_Dir -- ------------- function Sub_Dir (Dir : Virtual_File; Name : Filesystem_String) return Virtual_File is New_Dir : Virtual_File; begin Ensure_Directory (Dir); New_Dir := (Ada.Finalization.Controlled with Dispatching_Create (Dir.Value, GNATCOLL.Path.Path (Dir.Value.Get_FS, "", FS_String (Dir.Full_Name.all), FS_String (Name)))); Ensure_Directory (New_Dir); if Is_Directory (New_Dir) and then True then return New_Dir; else return No_File; end if; end Sub_Dir; ---------------- -- Change_Dir -- ---------------- procedure Change_Dir (Dir : Virtual_File) is Success : Boolean; pragma Unreferenced (Success); begin if Dir.Value = null then Raise_Exception (VFS_Directory_Error'Identity, "Dir is No_File"); end if; Success := Dir.Value.Change_Dir; end Change_Dir; -------------- -- Make_Dir -- -------------- procedure Make_Dir (Dir : Virtual_File; Recursive : Boolean := True) is Result : Boolean; begin if Dir.Value = null then Raise_Exception (VFS_Directory_Error'Identity, "Dir is No_File"); end if; -- If Dir already exists and is a directory, then return if Is_Directory (Dir) then return; end if; Result := Dir.Value.Make_Dir (Recursive); if not Result then Dir.Value.Kind := Unknown; Raise_Exception (VFS_Directory_Error'Identity, "Dir cannot be created"); else Dir.Value.Kind := Directory; end if; exception when E : others => Raise_Exception (VFS_Directory_Error'Identity, Exception_Message (E)); end Make_Dir; ---------------- -- Remove_Dir -- ---------------- procedure Remove_Dir (Dir : Virtual_File; Recursive : Boolean := False; Success : out Boolean) is begin if Dir.Value = null then raise VFS_Directory_Error; end if; Dir.Value.Remove_Dir (Recursive, Success); if Success then Dir.Value.Kind := Unknown; end if; end Remove_Dir; -------------- -- Read_Dir -- -------------- function Read_Dir (Dir : Virtual_File; Filter : Read_Dir_Filter := All_Files) return File_Array_Access is F_Array : File_Array_Access; Tmp_File : Virtual_File; begin if Dir.Value = null then Raise_Exception (VFS_Directory_Error'Identity, "Dir is No_File"); end if; Ensure_Directory (Dir); if not Is_Directory (Dir) then Raise_Exception (VFS_Directory_Error'Identity, "Dir is not a directory"); end if; declare List : GNAT.Strings.String_List := Dir.Value.Read_Dir (Dirs_Only => Filter = Dirs_Only, Files_Only => Filter = Files_Only); begin F_Array := new File_Array (1 .. List'Length); for J in List'Range loop Tmp_File := Dir.Create_From_Dir (+List (J).all); case Filter is when Dirs_Only => Tmp_File.Value.Kind := Directory; when Files_Only => Tmp_File.Value.Kind := File; when others => null; end case; F_Array (F_Array'First + J - List'First) := Tmp_File; GNAT.Strings.Free (List (J)); end loop; end; return F_Array; exception when E : others => Unchecked_Free (F_Array); Raise_Exception (VFS_Directory_Error'Identity, Exception_Message (E)); end Read_Dir; ------------------------ -- Read_Dir_Recursive -- ------------------------ function Read_Dir_Recursive (Dir : Virtual_File; Extension : Filesystem_String := ""; Filter : Read_Dir_Filter := All_Files) return File_Array_Access is Result : File_Array_Access; procedure Internal (Directory : Virtual_File); -- process a directory recursively procedure Internal (Directory : Virtual_File) is Files : File_Array_Access := Directory.Read_Dir (Filter => All_Files); begin if Files = null then return; end if; for F in Files'Range loop declare B : constant Filesystem_String := Files (F).Base_Name; begin if B /= "." and then B /= ".." then if Extension = "" or else Files (F).File_Extension = Extension then case Filter is when Dirs_Only => if Files (F).Is_Directory then Append (Result, Files (F)); end if; when Files_Only => if Files (F).Is_Regular_File then Append (Result, Files (F)); end if; when All_Files => Append (Result, Files (F)); end case; end if; if Files (F).Is_Directory then Internal (Files (F)); end if; end if; end; end loop; Unchecked_Free (Files); end Internal; begin if Dir.Is_Directory then Internal (Dir); end if; return Result; end Read_Dir_Recursive; -------------------------- -- Read_Files_From_Dirs -- -------------------------- function Read_Files_From_Dirs (Dirs : File_Array) return File_Array_Access is Ret : File_Array_Access := null; Files : array (Dirs'Range) of File_Array_Access; Length : Natural := 0; Idx : Natural; begin for J in Dirs'Range loop begin Files (J) := Read_Dir (Dirs (J), Files_Only); if Files (J) /= null then Length := Length + Files (J)'Length; end if; exception when VFS_Directory_Error => Files (J) := null; end; end loop; if Length = 0 then return null; else Ret := new File_Array (1 .. Length); Idx := Ret'First; for J in Files'Range loop if Files (J) /= null then Ret (Idx .. Idx + Files (J)'Length - 1) := Files (J).all; Idx := Idx + Files (J)'Length; Unchecked_Free (Files (J)); end if; end loop; return Ret; end if; end Read_Files_From_Dirs; -------------- -- Open_Dir -- -------------- function Open_Dir (Dir : Virtual_File) return Virtual_Dir is VDir : Virtual_Dir; begin if Dir.Value = null then return Invalid_Dir; end if; VDir.File := Dir; VDir.Files_List := Read_Dir (Dir); if VDir.Files_List /= null then VDir.Current := VDir.Files_List'First - 1; end if; Dir.Value.Kind := Directory; return VDir; exception when VFS_Directory_Error => return Invalid_Dir; end Open_Dir; ---------- -- Read -- ---------- procedure Read (VDir : in out Virtual_Dir; File : out Virtual_File) is begin if VDir.Files_List /= null and then VDir.Current < VDir.Files_List'Last then VDir.Current := VDir.Current + 1; File := VDir.Files_List (VDir.Current); else File := No_File; end if; end Read; ----------- -- Close -- ----------- procedure Close (VDir : in out Virtual_Dir) is begin if VDir.Files_List /= null then Unchecked_Free (VDir.Files_List); end if; VDir := Invalid_Dir; end Close; -------------- -- Finalize -- -------------- procedure Finalize (File : in out Virtual_File) is Value : GNATCOLL.IO.File_Access := File.Value; begin File.Value := null; -- Make Finalize idempotent if Value /= null then Unref (Value); end if; end Finalize; ------------ -- Adjust -- ------------ procedure Adjust (File : in out Virtual_File) is begin if File.Value /= null then Ref (File.Value); end if; end Adjust; --------------- -- Is_Parent -- --------------- function Is_Parent (Parent, Child : Virtual_File) return Boolean is begin if Parent.Value = null or else Child.Value = null or else Parent.Value'Tag /= Child.Value'Tag then return False; end if; Ensure_Normalized (Parent, Resolve_Symlinks => True); Ensure_Normalized (Child, Resolve_Symlinks => True); if Parent.Value.Normalized_And_Resolved'Length > Child.Value.Normalized_And_Resolved'Length then return False; end if; return Equal (Parent.Value.Get_FS, Parent.Value.Normalized_And_Resolved.all, Child.Value.Normalized_And_Resolved (Child.Value.Normalized_And_Resolved'First .. Child.Value.Normalized_And_Resolved'First + Parent.Value.Normalized_And_Resolved'Length - 1)); end Is_Parent; ---------- -- Sort -- ---------- procedure Sort (Files : in out File_Array) is -- ??? Right now, this sorts only on the full name. Do we want to -- provide other choices for sorting ? procedure Xchg (Op1, Op2 : Natural); -- Exchanges two items in the array function Lt (Op1, Op2 : Natural) return Boolean; -- Return True if the first item is to be sorted before the second ---------- -- Xchg -- ---------- procedure Xchg (Op1, Op2 : Natural) is Buffer : Virtual_File; begin Buffer := Files (Files'First - 1 + Op1); Files (Files'First - 1 + Op1) := Files (Files'First - 1 + Op2); Files (Files'First - 1 + Op2) := Buffer; end Xchg; -------- -- Lt -- -------- function Lt (Op1, Op2 : Natural) return Boolean is begin return Files (Files'First - 1 + Op1) < Files (Files'First - 1 + Op2); end Lt; begin Sort (Files'Length, Xchg'Unrestricted_Access, Lt'Unrestricted_Access); end Sort; ------------ -- Append -- ------------ procedure Append (Files : in out File_Array_Access; F : Virtual_File) is begin Append (Files, File_Array'(1 => F)); end Append; ------------ -- Append -- ------------ procedure Append (Files : in out File_Array_Access; F : File_Array) is Tmp : File_Array_Access; begin if Files = null then Files := new File_Array'(F); else Tmp := new File_Array (1 .. Files'Length + F'Length); Tmp (1 .. Files'Length) := Files.all; Tmp (Files'Length + 1 .. Tmp'Last) := F; Unchecked_Free (Files); Files := Tmp; end if; end Append; ------------- -- Prepend -- ------------- procedure Prepend (Files : in out File_Array_Access; F : File_Array) is Tmp : File_Array_Access; begin if Files = null then Files := new File_Array'(F); else Tmp := new File_Array (1 .. Files'Length + F'Length); Tmp (1 + F'Length .. Tmp'Length) := Files.all; Tmp (1 .. F'Length) := F; Unchecked_Free (Files); Files := Tmp; end if; end Prepend; ------------ -- Remove -- ------------ procedure Remove (Files : in out File_Array_Access; F : Virtual_File) is Tmp : File_Array_Access; begin for J in Files'Range loop if Files (J) = F then for K in J + 1 .. Files'Last loop Files (K - 1) := Files (K); end loop; Tmp := new File_Array'(Files (Files'First .. Files'Last - 1)); Unchecked_Free (Files); Files := Tmp; return; end if; end loop; end Remove; ------------- -- To_Path -- ------------- function To_Path (Paths : File_Array) return Filesystem_String is Length : Natural := 0; begin if Paths'Length = 0 then return ""; end if; for J in Paths'Range loop Length := Length + Paths (J).Full_Name.all'Length; end loop; Length := Length + Paths'Length - 1; declare Ret : Filesystem_String (1 .. Length); Idx : Natural := Ret'First; begin for J in Paths'Range loop Ret (Idx .. Idx + Paths (J).Full_Name.all'Length - 1) := Paths (J).Full_Name.all; Idx := Idx + Paths (J).Full_Name.all'Length; if J /= Paths'Last then Ret (Idx) := GNAT.OS_Lib.Path_Separator; Idx := Idx + 1; end if; end loop; return Ret; end; end To_Path; --------------- -- From_Path -- --------------- function From_Path (Path : Filesystem_String) return File_Array is Ret : File_Array_Access; Last : Natural := Path'First; begin for J in Path'First .. Path'Last loop -- ??? Should define Path_Separator in FS (system-dependent) if Path (J) = GNAT.OS_Lib.Path_Separator then if Last < J then Append (Ret, Create (Path (Last .. J - 1))); end if; Last := J + 1; end if; end loop; if Last <= Path'Last then Append (Ret, Create (Path (Last .. Path'Last))); end if; if Ret = null then return (1 .. 0 => <>); end if; declare Final : constant File_Array := Ret.all; begin Unchecked_Free (Ret); return Final; end; end From_Path; -------------------- -- Locate_On_Path -- -------------------- function Locate_On_Path (Base_Name : Filesystem_String; Path : File_Array) return Virtual_File is File : Virtual_File; begin for J in Path'Range loop if Path (J) /= No_File then File := Create_From_Dir (Path (J), Base_Name); if Is_Regular_File (File) then return File; end if; File := Create_From_Dir (Path (J), Base_Name & (+Exe_Extension (Path (J).Value.Get_FS))); if Is_Regular_File (File) then return File; end if; end if; end loop; return No_File; end Locate_On_Path; -------------------------- -- Greatest_Common_Path -- -------------------------- function Greatest_Common_Path (L : GNATCOLL.VFS.File_Array) return Virtual_File is begin if L'Length = 0 then return GNATCOLL.VFS.No_File; end if; declare Greatest_Prefix : Virtual_File := L (L'First); Root : constant Virtual_File := Get_Root (Greatest_Prefix); begin for J in L'First + 1 .. L'Last loop -- Loop until GP is a parent of the current File while not Greatest_Prefix.Is_Parent (L (J)) loop -- If not a parent, and already at root, then there is no -- greatest prefix. if Greatest_Prefix = Root then return No_File; end if; Greatest_Prefix := Get_Parent (Greatest_Prefix); end loop; end loop; return Greatest_Prefix; end; end Greatest_Common_Path; ------------------------- -- Locate_Regular_File -- ------------------------- function Locate_Regular_File (File_Name : Filesystem_String; Path : File_Array) return Virtual_File is F : Virtual_File; begin for J in Path'Range loop F := Create_From_Dir (Path (J), File_Name); if F.Is_Regular_File then return F; end if; end loop; return No_File; end Locate_Regular_File; ---------------------------- -- Symbolic_Links_Support -- ---------------------------- procedure Symbolic_Links_Support (Active : Boolean) is begin Handle_Symbolic_Links := Active; end Symbolic_Links_Support; ---------- -- Join -- ---------- function Join (Self : Virtual_File; File : Virtual_File) return Virtual_File is begin return Create_From_Dir (Self, File.Full_Name.all); end Join; ---------- -- Join -- ---------- function Join (Self : Virtual_File; Path : Filesystem_String) return Virtual_File is begin return Create_From_Dir (Self, Path); end Join; --------- -- "/" -- --------- function "/" (Self : Virtual_File; File : Virtual_File) return Virtual_File is begin return Create_From_Dir (Self, File.Full_Name.all); end "/"; --------- -- "/" -- --------- function "/" (Self : Virtual_File; Path : Filesystem_String) return Virtual_File is begin return Create_From_Dir (Self, Path); end "/"; --------- -- "/" -- --------- function "/" (Dir : Filesystem_String; File : Virtual_File) return Virtual_File is begin return Create_From_Dir (Create (Dir), File.Full_Name.all); end "/"; end GNATCOLL.VFS; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-vfs.ads000066400000000000000000000651471425465243200222120ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2003-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This package abstracts file operations and names. -- It is a layer on top of GNATCOLL.Filesystem, which allows you to use the -- same code to manipulate (copy, rename, delete,...) files, independent of -- the actual system you are running on (or even if the files happen to be on -- a remote host). -- This package provides additional abstraction with regards to file names. -- Depending on the context, your application will sometime need to use base -- names (no directory), or full name to reference a file. It is not always -- clear from the API which type of name is expected, and this package allows -- you to pass a Virtual_File instead, from which you can extract either the -- base name or the full name, as needed. This package also abstracts whether -- file names are case-sensitive or not (in fact, all systems can be -- considered as case sensitive because file names should be displayed with -- the exact casing that the user has chosen -- but in some cases the files -- can be referenced through multiple casing). -- It also takes care of reference counting, and will therefore free memory as -- appropriate when it is no longer needed. That makes the type relatively -- light weight, all the more because most of the information is computed only -- when needed, and cached in some cases. -- There is however a cost associated with Virtual_File: they are controlled -- types, and as such generate a lot of extra code; and they require at least -- one memory allocation when the file is created to store the name. with Ada.Calendar; with Ada.Containers; with Ada.Unchecked_Deallocation; with Ada.Finalization; with Interfaces.C.Strings; use Interfaces.C.Strings; with GNAT.OS_Lib; with GNAT.Strings; private with GNATCOLL.IO; private with GNATCOLL.IO.Native; with GNATCOLL.Strings; package GNATCOLL.VFS is ------------------------ -- Filesystem strings -- ------------------------ type Filesystem_String is new String; type Filesystem_String_Access is access all Filesystem_String; -- A Filesystem_String represents an array of characters as they are -- represented on the filesystem, without any encoding consideration. function "+" (S : Filesystem_String) return String; pragma Inline ("+"); function "+" (S : String) return Filesystem_String; pragma Inline ("+"); function Equal (S1, S2 : Filesystem_String) return Boolean; pragma Inline (Equal); procedure Free is new Ada.Unchecked_Deallocation (Filesystem_String, Filesystem_String_Access); -- Conversion/Comparison/Concatenation functions type Cst_Filesystem_String_Access is access constant Filesystem_String; ---------------- -- Exceptions -- ---------------- VFS_Directory_Error : exception; VFS_Invalid_File_Error : exception; VFS_Remote_Config_Error : exception; ------------------------------ -- Virtual File definition -- ------------------------------ type Virtual_File is tagged private; No_File : aliased constant Virtual_File; -- Note: a default initialized Virtual_File object has the value No_File --------------- -- Constants -- --------------- Local_Host : aliased constant String; ------------------- -- Configuration -- ------------------- procedure Symbolic_Links_Support (Active : Boolean); -- Whether this package should do extra system calls to handle symbolic -- links. -- This is automatically False on platforms like Windows where this notion -- does not exist, but when you know you have no symbolic links manipulated -- by your application you can significantly reduce the number of system -- calls (which in turns speeds things up). If you set it to False, two -- symbolic links that point to the same physical file will be considered -- different by the "=" operator. If you set it to True they will be -- considered equal. -- Changing this is not thread safe. In fact, you should call this before -- manipulating any of the Virtual_File, because GNATCOLL.VFS caches the -- normalization of file names, and would not redo it for existing files -- after you call this function, so the results of "=" in particular might -- be unexpected. ---------------------------- -- Creating Virtual_File -- ---------------------------- -- The following subprograms are used to create instances of Virtual_File. -- On the disk, a filename is typically just a series of bytes, with no -- special interpretation in utf8, iso-8859-1 or other pagesets (on most -- systems, windows always uses utf8 these days but has other -- specificities). -- As a result, a filename passed to these Create subprograms will not be -- interpreted through an encoding or another, but will just be stored as -- is. However, when comes the time to display the file on the disk, the -- filename needs to be converted to a known encoding, generally utf8. -- See the "Retrieving names" section below. function Create (Full_Filename : Filesystem_String; Host : String := Local_Host; Normalize : Boolean := False) return Virtual_File; -- Return a file, given its full filename. -- The latter can be found, for source files, through the functions in -- projects-registry.ads. -- If Normalize is set, then the VFS is created using the normalized -- Full_Filename. function Create_From_Dir (Dir : Virtual_File; Base_Name : Filesystem_String; Normalize : Boolean := False) return Virtual_File; -- Creates a file from its directory and base name -- If Normalize is set, then Create_From_Dir will make sure that the -- path is normalized function Create_From_Base (Base_Name : Filesystem_String; Base_Dir : Filesystem_String := ""; Host : String := Local_Host) return Virtual_File; -- Create a file from its base name. -- if Base_Name is an absolute path, then the file is created as is -- else the file is created relative to Base_Dir or the Current Directory -- if provided. function Create_From_UTF8 (Full_Filename : String; Host : String := Local_Host; Normalize : Boolean := False) return Virtual_File; -- Creates a file from its display name -- If Normalize is set, then the VFS is created using the normalized -- Full_Filename. function Locate_On_Path (Base_Name : Filesystem_String; Host : String := Local_Host) return Virtual_File; -- Locate the file from its base name and the PATH environment variable function Join (Self : Virtual_File; File : Virtual_File) return Virtual_File; function Join (Self : Virtual_File; Path : Filesystem_String) return Virtual_File; function "/" (Self : Virtual_File; File : Virtual_File) return Virtual_File; function "/" (Self : Virtual_File; Path : Filesystem_String) return Virtual_File; function "/" (Dir : Filesystem_String; File : Virtual_File) return Virtual_File; pragma Inline (Join, "/"); -- Various ways to build paths from their elements. These are just -- convention functions on top of the Create_* functions, but might help -- make the code more concise. For instance: -- File : constant Virtual_File := -- Get_Current_Dir / "filename.txt"; ---------------------- -- Retrieving names -- ---------------------- -- As mentioned above, a filename is stored internally as a series of bytes -- and not interpreted in anyway for an encoding. However, when you -- retrieve the name of a file for display, you will have to convert it to -- a known encoding. -- There are two sets of functions for retrieving names: Display_* will -- return the name converted through the Locale_To_Display function of the -- filesystem. -- All other functions will return the name as passed to the Create -- functions above, and therefore make no guarantee on the encoding of the -- file name. function Base_Name (File : Virtual_File; Suffix : Filesystem_String := ""; Normalize : Boolean := False) return Filesystem_String; -- Return the base name of the file function Base_Dir_Name (File : Virtual_File) return Filesystem_String; -- Return the base name of the directory or the file function Full_Name (File : Virtual_File; Normalize : Boolean := False; Resolve_Links : Boolean := False) return Cst_Filesystem_String_Access; -- Return the full path to File. -- If Normalize is True, the file name is first normalized, note that links -- are not resolved there by default, unless you specify Resolve_Links to -- True. -- The returned value can be used to recreate a Virtual_File instance. function Full_Name (File : Virtual_File; Normalize : Boolean := False) return Filesystem_String; -- Same as above, returning a filesystem_string function Full_Name_Hash (Key : Virtual_File) return Ada.Containers.Hash_Type; -- Return a Hash_Type computed from the full name of the given VFS. -- Could be used to instantiate an Ada 2005 container that uses a VFS as -- key and requires a hash function. function File_Extension (File : Virtual_File; Normalize : Boolean := False) return Filesystem_String; -- Return the extension of the file, or the empty string if there is no -- extension. This extension includes the last dot and all the following -- characters. -- If Normalize is true, the casing is normalized (depending on whether the -- platform uses case insensitive file names). function Dir_Name (File : Virtual_File) return Filesystem_String; -- Return the directory name for File. This includes any available -- on the protocol, so that relative files names are properly found. function Display_Full_Name (File : Virtual_File; Normalize : Boolean := False) return String; -- Same as Full_Name function Display_Base_Name (File : Virtual_File; Suffix : Filesystem_String := "") return String; -- Same as Base_Name function Display_Dir_Name (File : Virtual_File) return String; -- Same as Dir_Name function Display_Base_Dir_Name (File : Virtual_File) return String; -- Same as Base_Dir_Name function Unix_Style_Full_Name (File : Virtual_File; Cygwin_Style : Boolean := False; Normalize : Boolean := False; Casing : Boolean := False) return Filesystem_String; -- Returns the file path using a unix-style path. -- The casing of the filename is not impacted unless Casing is True -- (i.e. we do not convert to lower-cases on case-insensitive systems), -- because applications should preserve the original casing as much as -- possible. function Relative_Path (File : Virtual_File; From : Virtual_File) return Filesystem_String; -- Return the path of File relative to From. Return the full_name in case -- From and File are not on the same drive. function Has_Suffix (File : Virtual_File; Suffix : Filesystem_String) return Boolean; -- Tell if File has suffix Suffix function To_Remote (File : Virtual_File; To_Host : String) return Virtual_File; -- Convert the file format of File to the convention used on To_Host, -- using all available mount points defined for To_Host. function To_Local (File : Virtual_File) return Virtual_File; -- Convert the file format of File to the local filesystem's convention, -- potentially using mount points defined between File's host and local -- host. function To_Arg (File : Virtual_File; Host : String := Local_Host) return GNAT.Strings.String_Access; -- Convert the File to a String Access that can be used as argument for -- spawning a process on "Host". The returned value needs to be freeed by -- the caller. ------------------------ -- Getting attributes -- ------------------------ function Is_Local (File : Virtual_File) return Boolean; -- Whether File is local to the host or is a remote file function Get_Host (File : Virtual_File) return String; -- Retrieve the host of the file, or Local_Host if the file is local to the -- host. function Is_Regular_File (File : Virtual_File) return Boolean; -- Whether File corresponds to an actual file on the disk. -- This also works for remote files. function Size (File : Virtual_File) return Long_Integer; -- The size of the file function "=" (File1, File2 : Virtual_File) return Boolean; -- Overloading of the standard operator function "<" (File1, File2 : Virtual_File) return Boolean; -- Compare two files, possibly case insensitively on file systems that -- require this. function Is_Parent (Parent, Child : Virtual_File) return Boolean; -- Compare Parent and Child directory and determines if Parent contains -- Child directory function Is_Readable (File : Virtual_File) return Boolean; -- Return True if File is readable function Is_Writable (File : Virtual_File) return Boolean; -- Return True if File is writable function Is_Directory (VF : Virtual_File) return Boolean; -- Return True if File is in fact a directory function Is_Symbolic_Link (File : Virtual_File) return Boolean; -- Return True if File is a symbolic link function Is_Absolute_Path (File : Virtual_File) return Boolean; -- Return True if File contains an absolute path name, False if it only -- contains the base name or a relative name. procedure Set_Writable (File : VFS.Virtual_File; Writable : Boolean); -- If Writable is True, make File writable, otherwise make File unwritable procedure Set_Readable (File : VFS.Virtual_File; Readable : Boolean); -- If Readable is True, make File readable, otherwise make File unreadable. -- Note that this is not supported on Windows. function File_Time_Stamp (File : Virtual_File) return Ada.Calendar.Time; -- Return the timestamp for this file. This is GMT time, not local time. -- Note: we do not return GNAT.OS_Lib.OS_Time, since the latter cannot be -- created by anyone, and is just a private type. -- If the file doesn't exist, No_Time is returned. procedure Normalize_Path (File : Virtual_File; Resolve_Symlinks : Boolean := False); -- Resolve '..' and '.' directories in path. -- If Resolve_Symlinks is set, then also resolve the symbolic links in -- path. -------------------- -- Array of files -- -------------------- type File_Array is array (Positive range <>) of aliased Virtual_File; type File_Array_Access is access all File_Array; procedure Unchecked_Free (Arr : in out File_Array_Access); Empty_File_Array : constant File_Array; procedure Sort (Files : in out File_Array); -- Sort the array of files, in the order given by the full names procedure Append (Files : in out File_Array_Access; F : Virtual_File); procedure Append (Files : in out File_Array_Access; F : File_Array); procedure Prepend (Files : in out File_Array_Access; F : File_Array); -- Appends one or more files to Files. Files can be null, in which case a -- new File_Array is created. procedure Remove (Files : in out File_Array_Access; F : Virtual_File); -- Remove F from Files function To_Path (Paths : File_Array) return Filesystem_String; -- Translates a list of Paths into a path string (e.g. the same format as -- $PATH) function From_Path (Path : Filesystem_String) return File_Array; -- Translate a PATH string into a list of Virtual_File function Locate_On_Path (Base_Name : Filesystem_String; Path : File_Array) return Virtual_File; -- Locate the file from its base name and the furnished list of -- directories. function Greatest_Common_Path (L : GNATCOLL.VFS.File_Array) return Virtual_File; -- Return the greatest common path to a list of files or directories -- No_File is returned if some files do not have the same root directory. function Locate_Regular_File (File_Name : Filesystem_String; Path : File_Array) return Virtual_File; -- Locate a regular file from its base name and a list of paths ------------------------- -- Manipulating files -- ------------------------- procedure Rename (File : Virtual_File; Full_Name : Virtual_File; Success : out Boolean); -- Rename a file or directory. This does not work for remote files procedure Copy (File : Virtual_File; Target_Name : Filesystem_String; Success : out Boolean); -- Copy a file or directory. This does not work for remote files procedure Delete (File : Virtual_File; Success : out Boolean); -- Remove file from the disk. This also works for remote files function Read_File (File : Virtual_File) return GNAT.Strings.String_Access; function Read_File (File : Virtual_File) return GNATCOLL.Strings.XString; -- Return the contents of an entire file, encoded with the locale encoding. -- If the file cannot be found, return null. -- The caller is responsible for freeing the returned memory. -- This works transparently for remote files. -- The second version returning a XString is in general more efficient, -- especially if you need to do operations like Split() on the resulting -- string. -------------------------- -- Directory operations -- -------------------------- Local_Root_Dir : constant Virtual_File; function Dir (File : Virtual_File) return Virtual_File; -- Return the virtual file corresponding to the directory of the file -- If File denotes a directory, then it is returned. -- To retrieve the container of File (e.g. get the parent of File, even if -- it is a directory), use Get_Parent instead. function Get_Current_Dir (Host : String := Local_Host) return Virtual_File; -- Current dir on host function Get_Tmp_Directory (Host : String := Local_Host) return Virtual_File; -- Tmp dir on host function Get_Home_Directory (Host : String := Local_Host) return Virtual_File; -- Home dir on host function Get_Logical_Drives (Host : String := Local_Host) return File_Array_Access; -- List of all logical drives on host, or null if none. The list needs to -- be freed by the caller. procedure Ensure_Directory (Dir : Virtual_File); -- Ensures that the file is a directory: add directory separator if -- needed. function Get_Root (File : Virtual_File) return Virtual_File; -- Return root directory of the file function Get_Parent (Dir : Virtual_File) return Virtual_File; -- Return the parent directory if it exists, else No_File is returned function Sub_Dir (Dir : Virtual_File; Name : Filesystem_String) return Virtual_File; -- Return sub directory Name if it exists, else No_File is returned procedure Change_Dir (Dir : Virtual_File); -- Changes working directory. Raises Directory_Error if Dir_Name does not -- exist or is not a readable directory procedure Make_Dir (Dir : Virtual_File; Recursive : Boolean := True); -- Create a new directory named Dir_Name. Raises Directory_Error if -- Dir_Name cannot be created. -- If Recursive, create all intermediary directories needed. type Read_Dir_Filter is (All_Files, Dirs_Only, Files_Only); function Read_Dir (Dir : Virtual_File; Filter : Read_Dir_Filter := All_Files) return File_Array_Access; -- Reads all entries from the directory and returns a File_Array containing -- those entries, according to filter. The list of files returned -- includes directories in systems providing a hierarchical directory -- structure, including . (the current directory) and .. (the parent -- directory) in systems providing these entries. -- The result must be freed by the caller. function Read_Dir_Recursive (Dir : Virtual_File; Extension : Filesystem_String := ""; Filter : Read_Dir_Filter := All_Files) return File_Array_Access; -- Reads all entries from the directory, recursively, and returns all -- files with the given extension (if specified) that match the filter. -- The entries "." and ".." are never returned. -- The result must be freed by the caller. procedure Remove_Dir (Dir : Virtual_File; Recursive : Boolean := False; Success : out Boolean); -- Delete the directory Dir. If recursive is True, this also removes all -- files or subdirectories contained in it. function Read_Files_From_Dirs (Dirs : File_Array) return File_Array_Access; -- Read all files from the list of directories Dirs type Virtual_Dir is private; Invalid_Dir : constant Virtual_Dir; function Open_Dir (Dir : Virtual_File) return Virtual_Dir; -- Opens for reading a file procedure Read (VDir : in out Virtual_Dir; File : out Virtual_File); -- Returns next file or No_File is no file is left for current directory procedure Close (VDir : in out Virtual_Dir); -- Closes the Virtual_Dir ------------------- -- Writing files -- ------------------- -- Writing is more complex than reading, since generally the whole buffer -- to write down is not available immediately, but the user wants to be -- able to write characters in a series of calls. -- The interface in this package will also support remote files. In this -- case, writing the small chunks is done in a temporary file, which is -- sent to the remote host only when the file is closed. type Writable_File is private; Invalid_File : constant Writable_File; -- Used when a file couldn't be open function Write_File (File : Virtual_File; Append : Boolean := False) return Writable_File; -- Open File for writing. The returned handler can be used for writting. -- You must close it, otherwise the file will not actually be written in -- some cases. If Append is True then writting will be done at the end of -- the file if the file exists otherwise the file is created. -- Return Invalid_File is the file couldn't be open for writing -- -- For safety, the actual writes will occur in a temporary file unless -- Append is true, which will be renamed when calling Close. This ensures -- that the original file (if there was one) is not destroyed if for some -- reason the write fails. procedure Write (File : in out Writable_File; Str : String); procedure Write (File : in out Writable_File; Str : chars_ptr); -- Write a string to File. The contents of Str are written as-is procedure Close (File : in out Writable_File); -- Closes File, and write the file to disk. -- Use_Error is raised if the file could not be saved. ---------------------------------- -- Some internally used methods -- ---------------------------------- function Convert (File : Virtual_File; To_Host : String) return Virtual_File; function Convert (File : Virtual_File; From_Dir : Virtual_File; To_Dir : Virtual_File) return Virtual_File; -- Used in mount path conversions. These should be private, but can't -- as of RM 3.9.3(10) private -- This type is implemented as a controlled type, to ease the memory -- management (so that we can have gtk+ callbacks that take a Virtual -- File in argument, without caring who has to free the memory). -- Other solutions (using Name_Id to store the strings for instance) do -- not work properly, since the functions above cannot modify File -- itself, although they do compute some information lazily). type Virtual_File is new Ada.Finalization.Controlled with record Value : GNATCOLL.IO.File_Access; end record; pragma Finalize_Storage_Only (Virtual_File); procedure Finalize (File : in out Virtual_File); procedure Adjust (File : in out Virtual_File); type Writable_File is record File : Virtual_File; Tmp_File : Virtual_File; FD : GNAT.OS_Lib.File_Descriptor := GNAT.OS_Lib.Invalid_FD; Append : Boolean; Success : Boolean; end record; Invalid_File : constant Writable_File := (File => (Ada.Finalization.Controlled with Value => null), Tmp_File => (Ada.Finalization.Controlled with Value => null), FD => GNAT.OS_Lib.Invalid_FD, Append => False, Success => False); type Virtual_Dir is record File : Virtual_File; Files_List : File_Array_Access; Current : Natural; end record; No_File : aliased constant Virtual_File := (Ada.Finalization.Controlled with Value => null); Local_Host : aliased constant String := ""; Local_Root_Dir : constant Virtual_File := (Ada.Finalization.Controlled with Value => GNATCOLL.IO.Native.Local_Root_Dir); Empty_File_Array : constant File_Array := File_Array'(1 .. 0 => No_File); Invalid_Dir : constant Virtual_Dir := ((Ada.Finalization.Controlled with Value => null), null, 0); end GNATCOLL.VFS; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-vfs_types.ads000066400000000000000000000040421425465243200234210ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Unchecked_Deallocation; package GNATCOLL.VFS_Types is type FS_String is new String; type FS_String_Access is access all FS_String; procedure Free is new Ada.Unchecked_Deallocation (FS_String, FS_String_Access); type FS_Type is (FS_Unknown, FS_Unix, FS_Unix_Case_Insensitive, FS_Windows); end GNATCOLL.VFS_Types; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-vfs_utils.adb000066400000000000000000000202611425465243200233750ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Unchecked_Conversion; with Ada.Directories; use Ada.Directories; with GNATCOLL.Remote; use GNATCOLL.Remote; with GNATCOLL.Remote.Db; use GNATCOLL.Remote.Db; with GNATCOLL.Utils; with GNATCOLL.VFS_Types; package body GNATCOLL.VFS_Utils is function Unchecked is new Ada.Unchecked_Conversion (String_Access, Filesystem_String_Access); ------------------------ -- Normalize_Pathname -- ------------------------ function Normalize_Pathname (Name : Filesystem_String; Directory : Filesystem_String := ""; Resolve_Links : Boolean := True; Case_Sensitive : Boolean := True) return Filesystem_String is begin return +Normalize_Pathname (+Name, +Directory, Resolve_Links, Case_Sensitive); end Normalize_Pathname; ---------------------- -- Is_Absolute_Path -- ---------------------- function Is_Absolute_Path (Name : Filesystem_String) return Boolean is begin return Is_Absolute_Path (+Name); end Is_Absolute_Path; --------------------- -- Is_Regular_File -- --------------------- function Is_Regular_File (Name : Filesystem_String) return Boolean is begin return Is_Regular_File (+Name); end Is_Regular_File; ------------------ -- Is_Directory -- ------------------ function Is_Directory (Name : Filesystem_String) return Boolean is begin return Is_Directory (+Name); end Is_Directory; --------------- -- Copy_File -- --------------- procedure Copy_File (Name : Filesystem_String; Pathname : Filesystem_String; Success : out Boolean; Mode : Copy_Mode := Copy; Preserve : Attribute := Time_Stamps) is begin Copy_File (+Name, +Pathname, Success, Mode, Preserve); end Copy_File; ------------------ -- Set_Writable -- ------------------ procedure Set_Writable (Name : Filesystem_String) is begin Set_Writable (+Name); end Set_Writable; ---------------------- -- Set_Non_Writable -- ---------------------- procedure Set_Non_Writable (Name : Filesystem_String) is begin Set_Non_Writable (+Name); end Set_Non_Writable; ---------------------- -- Create_Temp_File -- ---------------------- procedure Create_Temp_File (FD : out File_Descriptor; Name : out Filesystem_String_Access) is R : String_Access; begin Create_Temp_File (FD, R); Name := Unchecked (R); end Create_Temp_File; -------------------- -- File_Extension -- -------------------- function File_Extension (Path : Filesystem_String) return Filesystem_String is begin return +File_Extension (+Path); end File_Extension; --------------------- -- Get_Current_Dir -- --------------------- function Get_Current_Dir return Filesystem_String is begin return +Get_Current_Dir; end Get_Current_Dir; ----------------------- -- Name_As_Directory -- ----------------------- function Name_As_Directory (Name : Filesystem_String) return Filesystem_String is begin if +Name = "" then return ""; end if; return Filesystem_String (GNATCOLL.Path.Ensure_Directory (GNATCOLL.Path.Local_FS, GNATCOLL.VFS_Types.FS_String (Name))); end Name_As_Directory; -------------- -- Dir_Name -- -------------- function Dir_Name (Path : Filesystem_String) return Filesystem_String is begin return +Dir_Name (+Path); end Dir_Name; --------------- -- Base_Name -- --------------- function Base_Name (Path : Filesystem_String; Suffix : Filesystem_String := "") return Filesystem_String is begin return +Base_Name (+Path, +Suffix); end Base_Name; ---------------- -- Change_Dir -- ---------------- procedure Change_Dir (Dir_Name : Filesystem_String) is begin Change_Dir (+Dir_Name); end Change_Dir; --------------------- -- Format_Pathname -- --------------------- function Format_Pathname (Path : Filesystem_String; Style : Path_Style := System_Default) return Filesystem_String is begin return +Format_Pathname (+Path, Style); end Format_Pathname; ---------- -- Open -- ---------- procedure Open (Dir : out Dir_Type; Dir_Name : Filesystem_String) is begin Open (Dir, +Dir_Name); end Open; ------------------------- -- Locate_Exec_On_Path -- ------------------------- function Locate_Exec_On_Path (Exec_Name : Filesystem_String) return Filesystem_String_Access is Val : String_Access := Locate_Exec_On_Path (+Exec_Name); begin if Val /= null then declare Ret : constant Filesystem_String_Access := new Filesystem_String'(+Val.all); begin Free (Val); return Ret; end; end if; return null; end Locate_Exec_On_Path; ------------------------- -- Locate_Regular_File -- ------------------------- function Locate_Regular_File (File_Name : Filesystem_String; Path : Filesystem_String) return Filesystem_String_Access is Val : String_Access := Locate_Regular_File (+File_Name, +Path); Ret : Filesystem_String_Access; begin if Val /= null then Ret := new Filesystem_String'(+Val.all); Free (Val); return Ret; else return null; end if; end Locate_Regular_File; ------------- -- Compose -- ------------- function Compose (Containing_Directory : Filesystem_String := ""; Name : Filesystem_String; Extension : Filesystem_String := "") return Filesystem_String is begin return +Compose (+Containing_Directory, +Name, +Extension); end Compose; ----------------------- -- Is_Case_Sensitive -- ----------------------- function Is_Case_Sensitive (Host : String) return Boolean is FS : GNATCOLL.VFS_Types.FS_Type; begin if Host = Local_Host then FS := GNATCOLL.Path.Local_FS; else FS := Get_Server (Host).Shell_FS; end if; return GNATCOLL.Path.Is_Case_Sensitive (FS); end Is_Case_Sensitive; ---------------- -- File_Equal -- ---------------- function File_Equal (F1, F2 : Filesystem_String; Host : String) return Boolean is begin return GNATCOLL.Utils.Equal (+F1, +F2, Is_Case_Sensitive (Host)); end File_Equal; end GNATCOLL.VFS_Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll-vfs_utils.ads000066400000000000000000000120111425465243200234100ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2009-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.Directory_Operations; use GNAT.Directory_Operations; with GNAT.OS_Lib; use GNAT.OS_Lib; with GNATCOLL.VFS; use GNATCOLL.VFS; private with GNATCOLL.Path; package GNATCOLL.VFS_Utils is -------------- -- Wrappers -- -------------- Local_Host_Is_Case_Sensitive : constant Boolean; -- These subprograms wrap around their equivalents in System.OS_Lib, and -- use Filesystem_String for better type safety. function Normalize_Pathname (Name : Filesystem_String; Directory : Filesystem_String := ""; Resolve_Links : Boolean := True; Case_Sensitive : Boolean := True) return Filesystem_String; function Is_Absolute_Path (Name : Filesystem_String) return Boolean; function Is_Regular_File (Name : Filesystem_String) return Boolean; function Is_Directory (Name : Filesystem_String) return Boolean; procedure Copy_File (Name : Filesystem_String; Pathname : Filesystem_String; Success : out Boolean; Mode : Copy_Mode := Copy; Preserve : Attribute := Time_Stamps); procedure Set_Writable (Name : Filesystem_String); procedure Set_Non_Writable (Name : Filesystem_String); procedure Set_Read_Only (Name : Filesystem_String) renames Set_Non_Writable; procedure Create_Temp_File (FD : out File_Descriptor; Name : out Filesystem_String_Access); function Locate_Exec_On_Path (Exec_Name : Filesystem_String) return Filesystem_String_Access; function Locate_Regular_File (File_Name : Filesystem_String; Path : Filesystem_String) return Filesystem_String_Access; -- These subprograms wrap around their equivalents in -- GNAT.Directory_Operations, and use Filesystem_String for better type -- safety. function File_Extension (Path : Filesystem_String) return Filesystem_String; function Get_Current_Dir return Filesystem_String; function Dir_Name (Path : Filesystem_String) return Filesystem_String; function Base_Name (Path : Filesystem_String; Suffix : Filesystem_String := "") return Filesystem_String; procedure Change_Dir (Dir_Name : Filesystem_String); function Format_Pathname (Path : Filesystem_String; Style : Path_Style := System_Default) return Filesystem_String; function Name_As_Directory (Name : Filesystem_String) return Filesystem_String; procedure Open (Dir : out Dir_Type; Dir_Name : Filesystem_String); -- These subprograms wrap around their equivalents in Ada.Directories, and -- use Filesystem_String for better type safety. function Compose (Containing_Directory : Filesystem_String := ""; Name : Filesystem_String; Extension : Filesystem_String := "") return Filesystem_String; ------------------------------------ -- Remote hosts handling of Files -- ------------------------------------ function Is_Case_Sensitive (Host : String) return Boolean; -- Tell if host's filesystem is case sensitive function File_Equal (F1, F2 : Filesystem_String; Host : String) return Boolean; private Local_Host_Is_Case_Sensitive : constant Boolean := GNATCOLL.Path.Is_Case_Sensitive (GNATCOLL.Path.Local_FS); end GNATCOLL.VFS_Utils; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll.ads000066400000000000000000000033761425465243200214120ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2005-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ package GNATCOLL is pragma Pure; end GNATCOLL; alire-1.2.1/deps/gnatcoll-slim/src/gnatcoll_support.c000066400000000000000000000121571425465243200226560ustar00rootroot00000000000000/*---------------------------------------------------------------------------- -- G N A T C O L L -- -- -- -- Copyright (C) 2008-2017, AdaCore -- -- -- -- This is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 3, or (at your option) any later ver- -- -- sion. This software is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- -- License for more details. You should have received a copy of the GNU -- -- General Public License distributed with this software; see file -- -- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy -- -- of the license. -- ----------------------------------------------------------------------------*/ #include #include #include #ifdef _WIN32 #include #endif #ifdef HAVE_SYSLOG #include void syslog_wrapper(int priority, const char* msg) { syslog(priority, "%s", msg); } #endif // From adaint.h extern int __gnat_is_directory (char *); #ifdef HAVE_MMAP #include int gnatcoll_has_mmap() { return 1; } void * gnatcoll_mmap (void *start, long length, int prot, int flags, int fd, long offset) { return mmap (start, (size_t)length, prot, flags, fd, (off_t)offset); } int gnatcoll_munmap (void *start, long length) { return munmap (start, (size_t)length); } #ifdef HAVE_MADVISE void gnatcoll_madvise(void* addr, size_t len, int advice) { int adv = (advice == 1 ? MADV_NORMAL : advice == 2 ? MADV_RANDOM : advice == 4 ? MADV_SEQUENTIAL : MADV_NORMAL); madvise(addr, len, adv); } #else /* not HAVE_MADVISE */ void gnatcoll_madvise(void* addr, size_t len, int advice) { } #endif /* HAVE_MADVISE */ #else /* No mmap support, so no madvise support either */ int gnatcoll_has_mmap () { return 0; } void gnatcoll_madvise(void* addr, size_t len, int advice) { } void *gnatcoll_mmap (void *start, long length, int prot, int flags, int fd, long offset) { return (void*)0; } int gnatcoll_munmap (void *start, long length) { return 0; } #endif int __gnatcoll_get_logical_drive_strings (char *buffer, int len) { #ifdef _WIN32 return GetLogicalDriveStringsA ((DWORD)len, (LPSTR)buffer); #else return 0; #endif } void __gnatcoll_set_readable (char *file, int set) { #ifdef _WIN32 /* ??? NOT CURRENTLY SUPPORTED. There is no support for setting a file as unreadable using the standard chmod routine on Windows. With this routine it is only possible to set a file as read-only. To set a file as unreadable it is required to use the more complex [Get|Set]FileSecurity Win32 API by setting the proper ACL. */ #elif defined (__VMS__) /* ??? NOT CURRENTLY SUPPORTED. */ #else struct stat statbuf; if (!stat (file, &statbuf)) { if (set) chmod (file, statbuf.st_mode | S_IREAD); else chmod (file, statbuf.st_mode & (~S_IREAD)); } #endif } /********************************************************** ** __gnatcoll_get_tmp_dir () ** Return the tmp directory. ** Return value must be freed by caller **********************************************************/ char* __gnatcoll_get_tmp_dir (void) { static char *result = NULL; /* test static result to see if result has already been found */ if (result != NULL) return strdup (result); #ifdef _WIN32 { DWORD dwRet; result = malloc ((MAX_PATH + 1) * sizeof (char)); dwRet = GetTempPath (MAX_PATH, result); if (dwRet > 0) { result[dwRet] = '\0'; if (__gnat_is_directory (result)) return strdup (result); } free (result); } #endif result = getenv ("TMPDIR"); if (result) if (__gnat_is_directory (result)) return strdup (result); result = getenv ("TMP"); if (result) if (__gnat_is_directory (result)) return strdup (result); /* On Windows systems, this is the documented way of retrieving the tmp dir. * However, the TMP env variable should also be defined */ result = getenv ("TEMP"); if (result) if (__gnat_is_directory (result)) return strdup (result); /* need to duplicate twice: one is for caching, the second one will be freed * by user */ result = strdup ("/tmp"); return strdup (result); } /************************************************************************ * Support for atomic operations ************************************************************************/ #ifdef ATOMIC_INTRINSICS int gnatcoll_sync_bool_compare_and_swap_access (void** ptr, void* oldval, void* newval) { return __sync_bool_compare_and_swap(ptr, oldval, newval); } #endif alire-1.2.1/deps/gnatcoll-slim/src/link_max.c000066400000000000000000000026441425465243200210610ustar00rootroot00000000000000/********************************************************************* * G P S * * * * Copyright (C) 2007 * * AdaCore * * * * GPS 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 2 of the License, or * * (at your option) any later version. * * * * This program 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. You should have received * * a copy of the GNU General Public License along with this program; * * if not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ /* Dummy version of __gnat_link_max (needed by mlib-utl.adb) */ int __gnat_link_max = 8192; alire-1.2.1/deps/gnatcoll-slim/src/objlist_file.c000066400000000000000000000031341425465243200217170ustar00rootroot00000000000000/********************************************************************* * G P S * * * * Copyright (C) 2007 * * AdaCore * * * * GPS 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 2 of the License, or * * (at your option) any later version. * * * * This program 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. You should have received * * a copy of the GNU General Public License along with this program; * * if not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ /* Dummy versions of __gnat_objlist_file_supported, __gnat_object_file_option and __gnat_using_gnu_linker (needed by mlib-utl.adb) */ unsigned char __gnat_objlist_file_supported = 0; const char *__gnat_object_file_option = ""; unsigned char __gnat_using_gnu_linker = 0; alire-1.2.1/deps/gnatcoll-slim/src/paragraph_filling/000077500000000000000000000000001425465243200225565ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/src/paragraph_filling/gnatcoll-paragraph_filling-badnesses.adb000066400000000000000000000106171425465243200324520ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This software was originally contributed by William A. Duff package body GNATCOLL.Paragraph_Filling.Badnesses is ---------- -- "**" -- ---------- function "**" (X : Natural; Y : Positive) return Badness_Value is pragma Unsuppress (All_Checks); begin return Badness_Value (Integer'(X ** Y)); exception when Constraint_Error => return Infinity; end "**"; --------- -- "+" -- --------- overriding function "+" (X, Y : Badness_Value) return Badness_Value is pragma Unsuppress (All_Checks); begin return Badness_Value (Integer (X) + Integer (Y)); exception when Constraint_Error => return Infinity; end "+"; --------- -- "<" -- --------- overriding function "<" (X, Y : Badness_Value) return Boolean is begin return Integer (X) < Integer (Y); end "<"; ----------- -- Image -- ----------- function Image (Badness : Badness_Value) return String is begin if Badness = Infinity then return "Inf"; else declare Result : constant String := Badness_Value'Image (Badness); begin -- Slicing removes the superfluous space return Result (Result'First + 1 .. Result'Last); end; end if; end Image; ------------------ -- Line_Badness -- ------------------ function Line_Badness (W : Paragraph_Filling.Words.Words; X, Y : Word_Index; Max_Line_Length : Positive; Format_Last_Line : Boolean := False) return Badness_Value is Distance : constant Integer := Max_Line_Length - Line_Length (W, X, Y); begin -- Line is too long if Distance < 0 then -- One word line, meaning nothing can be done to shorten it if X = Y then return 0; -- Not one word line, meaning it can be split into two pieces else return Infinity; end if; -- Last line is not bad if unless Format_Last_Line = True elsif Y = Last_Word (W) and then not Format_Last_Line then return 0; -- Otherwise, normal line. Return the badness of distance to the end -- of the line squared. else return Distance ** 2; end if; end Line_Badness; ------------------ -- Line_Badness -- ------------------ function Line_Badness (Line_Length : Positive; Max_Line_Length : Positive) return Badness_Value is begin if Line_Length > Max_Line_Length then return Infinity; else return (Max_Line_Length - Line_Length) ** 2; end if; end Line_Badness; end GNATCOLL.Paragraph_Filling.Badnesses; alire-1.2.1/deps/gnatcoll-slim/src/paragraph_filling/gnatcoll-paragraph_filling-badnesses.ads000066400000000000000000000101741425465243200324710ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This software was originally contributed by William A. Duff with GNATCOLL.Paragraph_Filling.Words; use GNATCOLL.Paragraph_Filling.Words; private package GNATCOLL.Paragraph_Filling.Badnesses is type Badness_Value is private; Zero : constant Badness_Value; Infinity : constant Badness_Value; -- It's a non-negative number that represents how bad the formatting of a -- line or paragraph is, with Zero meaning perfectly good, and Infinity -- representing "too long to fit on a line". The term 'badness' comes from -- Knuth's TeX. function "+" (X, Y : Badness_Value) return Badness_Value; -- Adds two Badnesses. If the result is greater than infinity, it returns -- infinity. function "<" (X, Y : Badness_Value) return Boolean; -- Returns true if X is less than Y. Else returns False function "**" (X : Natural; Y : Positive) return Badness_Value; -- Raise X to the Y power and returns the result as a Badness_Value. If the -- result is greater that infinity, returns infinity. function Image (Badness : Badness_Value) return String; function Line_Badness (W : Paragraph_Filling.Words.Words; X, Y : Word_Index; Max_Line_Length : Positive; Format_Last_Line : Boolean := False) return Badness_Value; -- Returns badness as determined by a formula invented by Knuth. This -- formula calculates the square of the difference between the Line_Length -- (calculated by the Line_Length function in Paragraph_Filling.Words) and -- the Max_Line_Length. If the line length is greater than the -- Max_Line_Length then the function returns Infinity. -- -- ??? Currently, Format_Last_Line is always defaulted to false. However, -- the calls could be changes to allow a user option of whether to include -- the last line in badness calculations. function Line_Badness (Line_Length : Positive; Max_Line_Length : Positive) return Badness_Value; -- Returns badness as determined by a formula invented by Knuth. -- This formula calculates the square of the difference between the -- Line_Length and the Max_Line_Length. If the line length is greater -- than the Max_Line_Length then the function returns Infinity. private type Badness_Value is new Natural; Zero : constant Badness_Value := 0; Infinity : constant Badness_Value := Badness_Value'Last; end GNATCOLL.Paragraph_Filling.Badnesses; alire-1.2.1/deps/gnatcoll-slim/src/paragraph_filling/gnatcoll-paragraph_filling-words.adb000066400000000000000000000141741425465243200316430ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Containers; use Ada.Containers; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with GNATCOLL.Utils; use GNATCOLL.Utils; package body GNATCOLL.Paragraph_Filling.Words is ----------------- -- Merge_Lines -- ----------------- function Merge_Lines (W : Words; Split_Before_Word : Word_Vector; Line_Prefix : String := "") return Ada.Strings.Unbounded.Unbounded_String is Result : Unbounded_String; From : Integer := 1; Start : Integer; To : Integer; Before_Word : Word_Index; begin for Count in reverse 2 .. Length (Split_Before_Word) - 1 loop Before_Word := Element (Split_Before_Word, Word_Index (Count)); Start := Integer (W.Starts (Before_Word)); To := Start - 1; while Is_Whitespace (Element (W.Paragraph, To)) loop To := To - 1; end loop; Append (Result, Line_Prefix); Append (Result, Slice (W.Paragraph, From, To)); Append (Result, ASCII.LF); From := Start; end loop; To := Length (W.Paragraph); while Is_Whitespace (Element (W.Paragraph, To)) loop To := To - 1; end loop; Append (Result, Line_Prefix); Append (Result, Slice (W.Paragraph, From, To)); Append (Result, ASCII.LF); return Result; end Merge_Lines; --------------------- -- Index_Paragraph -- --------------------- function Index_Paragraph (Paragraph : String) return Words is Fixed_Para : Unbounded_String; Count : Positive := Paragraph'First; Result : Word_Vector; begin Append (Result, 1); -- First word always starts on first character -- Takes out all spaces, tabs, and new line characters and creates a -- string with exactly one space between each word, plus one space at -- the end. if Paragraph /= "" then -- Skip leading whitespaces while Is_Whitespace (Paragraph (Count)) loop Count := Count + 1; end loop; while Count <= Paragraph'Last loop if Is_Whitespace (Paragraph (Count)) then loop Count := Count + 1; exit when Count > Paragraph'Last or else not Is_Whitespace (Paragraph (Count)); end loop; Append (Fixed_Para, ' '); Append (Result, Word_Index (Length (Fixed_Para) + 1)); if Count <= Paragraph'Last then Append (Fixed_Para, Paragraph (Count)); end if; else -- ??? Might be more efficient to find the longuest substring -- with no multiple-space sequence, and append it at once. If -- the paragraph is already correct, we avoid a whole copy. Append (Fixed_Para, Paragraph (Count)); end if; Count := Count + 1; end loop; if Element (Fixed_Para, Length (Fixed_Para)) /= ' ' then Append (Fixed_Para, ' '); end if; end if; -- Avoid extra copies of Starts array by building the result in place return W : Words (After_Last_Word => Word_Index (Length (Result))) do W.Paragraph := Fixed_Para; for Count in 1 .. Length (Result) loop W.Starts (Word_Index (Count)) := Word_Vectors.Element (Result, Word_Index (Count)); end loop; end return; end Index_Paragraph; --------------- -- Last_Word -- --------------- function Last_Word (W : Words) return Word_Count is begin return W.After_Last_Word - 1; end Last_Word; ----------------- -- Line_Length -- ----------------- function Line_Length (W : Words; X, Y : Word_Index) return Positive is begin return Positive (W.Starts (Y + 1) - W.Starts (X) - 1); end Line_Length; -------------- -- Nth_Word -- -------------- function Nth_Word (W : Words; N : Word_Index) return String is begin return Slice (W.Paragraph, Low => Integer (W.Starts (N)), High => Integer (W.Starts (N + 1) - 2)); end Nth_Word; ----------------- -- Word_Length -- ----------------- function Word_Length (W : Words; N : Word_Index) return Positive is begin return Integer (W.Starts (N + 1) - W.Starts (N) - 1); end Word_Length; end GNATCOLL.Paragraph_Filling.Words; alire-1.2.1/deps/gnatcoll-slim/src/paragraph_filling/gnatcoll-paragraph_filling-words.ads000066400000000000000000000101671425465243200316620ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This software was originally contributed by William A. Duff with Ada.Containers.Vectors; with Ada.Strings.Unbounded; private package GNATCOLL.Paragraph_Filling.Words is -- Provides ways of differentiating words by reformatting a paragraph and -- pointing to the first character of each word in that paragraph. type Word_Index is new Positive; package Word_Vectors is new Ada.Containers.Vectors ( Index_Type => Word_Index, Element_Type => Word_Index); use Word_Vectors; subtype Word_Vector is Word_Vectors.Vector; subtype Word_Count is Word_Index'Base range 0 .. Word_Index'Last; type Words (After_Last_Word : Word_Count) is limited private; function Index_Paragraph (Paragraph : String) return Words; -- Creates a record with an array of the indexes to the first character of -- each word in Paragraph, plus an index pointing one past the end of the -- Paragraph. function Nth_Word (W : Words; N : Word_Index) return String; -- Returns the Nth word in W.PAragraph function Last_Word (W : Words) return Word_Count; -- Returns the word number of the last word (in other words the number of -- words) in W.Paragraph. function Word_Length (W : Words; N : Word_Index) return Positive; pragma Inline (Word_Length); -- Returns the length of the Nth word in W.Paragraph function Line_Length (W : Words; X, Y : Word_Index) return Positive; -- Returns the length of a line beginning with the Xth word and ending with -- the Yth word. function Merge_Lines (W : Words; Split_Before_Word : Word_Vector; Line_Prefix : String := "") return Ada.Strings.Unbounded.Unbounded_String; -- Return the formatted paragraph, by splitting lines before each word -- in Split_Before_Word. -- Each created line will start with Line_Prefix. private type Word_Starts is array (Word_Index range <>) of Word_Index; type Words (After_Last_Word : Word_Count) is limited record Paragraph : Ada.Strings.Unbounded.Unbounded_String; Starts : Word_Starts (1 .. After_Last_Word); end record; -- Paragraph is the actual text of the Words. Starts contains indexes to -- the first character of each word in Paragraph. This facilitates the -- formatting algorithms in Paragraph_Filling because some only need to -- know the word lengths and positions most of the time. end GNATCOLL.Paragraph_Filling.Words; alire-1.2.1/deps/gnatcoll-slim/src/paragraph_filling/gnatcoll-paragraph_filling.adb000066400000000000000000000372351425465243200305120ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This software was originally contributed by William A. Duff with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Strings; use Ada.Strings; with GNATCOLL.Paragraph_Filling.Words; use GNATCOLL.Paragraph_Filling.Words; with GNATCOLL.Paragraph_Filling.Badnesses; use GNATCOLL.Paragraph_Filling.Badnesses; package body GNATCOLL.Paragraph_Filling is use Word_Vectors; type Badness_Values is array (Word_Index range <>) of Badness_Value; type Word_Indexes is array (Word_Index range <>) of Word_Index; function Greedy_Fill (Paragraph : Paragraph_Filling.Words.Words; Max_Line_Length : Positive; Line_Prefix : String := "") return Unbounded_String; -- Formats a paragraph with the greedy algorithm (by putting as many words -- as possible on each line). function Nth_Index (Source : Unbounded_String; Pattern : String; N : Natural) return Natural; -- Returns the Nth instance of Pattern within Source. If the Nth index does -- not exist returns 0. function Can_And_Should_Move_A_Word (Max_Line_Length : Positive; Length_Of_First_Line : Positive; Length_Of_Second_Line : Positive; Length_Of_Last_Word : Positive) return Boolean; -- Decides whether the last word of the first line can fit on the second -- line and if so whether the badness is reduced by moving the word. function Count_Lines (Source : Unbounded_String) return Natural; -- Number of lines in Source -------------------------------- -- Can_And_Should_Move_A_Word -- -------------------------------- function Can_And_Should_Move_A_Word (Max_Line_Length : Positive; Length_Of_First_Line : Positive; Length_Of_Second_Line : Positive; Length_Of_Last_Word : Positive) return Boolean is begin if Length_Of_Second_Line + Length_Of_Last_Word <= Max_Line_Length and then not (Line_Badness (Length_Of_First_Line, Max_Line_Length) + Line_Badness (Length_Of_Second_Line, Max_Line_Length) < Line_Badness (Length_Of_First_Line - Length_Of_Last_Word, Max_Line_Length) + Line_Badness (Length_Of_Second_Line + Length_Of_Last_Word, Max_Line_Length)) then return True; else return False; end if; end Can_And_Should_Move_A_Word; ----------------- -- Count_Lines -- ----------------- function Count_Lines (Source : Unbounded_String) return Natural is Result : Natural := 0; begin for J in 1 .. Length (Source) loop if Element (Source, J) = ASCII.LF then Result := Result + 1; end if; end loop; return Result; end Count_Lines; ----------------- -- Greedy_Fill -- ----------------- function Greedy_Fill (Paragraph : Paragraph_Filling.Words.Words; Max_Line_Length : Positive; Line_Prefix : String := "") return Unbounded_String is Max : constant Integer := Max_Line_Length - Line_Prefix'Length; Result : Unbounded_String; Current : Natural; -- current line length begin if Paragraph.After_Last_Word /= 1 then Result := To_Unbounded_String (Line_Prefix) & Nth_Word (Paragraph, 1); Current := Length (Result); -- Go through the rest of the words, and for each one check if it -- fits on the current line. for Count in 2 .. Paragraph.After_Last_Word - 1 loop declare W : constant String := Nth_Word (Paragraph, Count); begin if Current + W'Length + 1 <= Max then Current := Current + 1; Append (Result, ' '); else Append (Result, ASCII.LF); Append (Result, Line_Prefix); Current := Line_Prefix'Length; end if; Current := Current + W'Length; Append (Result, W); end; end loop; Append (Result, ASCII.LF); end if; return Result; end Greedy_Fill; ----------------- -- Greedy_Fill -- ----------------- function Greedy_Fill (Paragraph : String; Max_Line_Length : Positive := Default_Max_Line_Length; Line_Prefix : String := "") return Ada.Strings.Unbounded.Unbounded_String is Para : String renames Paragraph; W : GNATCOLL.Paragraph_Filling.Words.Words := Index_Paragraph (Para); begin return Greedy_Fill (W, Max_Line_Length, Line_Prefix); end Greedy_Fill; ---------------- -- Knuth_Fill -- ---------------- function Knuth_Fill (Paragraph : String; Max_Line_Length : Positive := Default_Max_Line_Length; Line_Prefix : String := "") return Unbounded_String is Para : Paragraph_Filling.Words.Words := Index_Paragraph (Paragraph); function Calculate_Best (Paragraph : Paragraph_Filling.Words.Words; Max_Line_Length : Positive) return Word_Indexes; -- Determines the best division of lines and returns the word that -- begins each line in this setup as an array. function Determine_First_Words (Last_Word : Word_Count; Best_Words : Word_Indexes) return Word_Vector; -- Takes an array of the first words, reverses it, and stores it in a -- vector. -------------------- -- Calculate_Best -- -------------------- function Calculate_Best (Paragraph : Paragraph_Filling.Words.Words; Max_Line_Length : Positive) return Word_Indexes is Minimum_Badnesses : Badness_Values (1 .. Last_Word (Paragraph) + 1); Result : Word_Indexes (1 .. Last_Word (Paragraph)); begin Minimum_Badnesses (1) := Zero; for Y in 1 .. Last_Word (Paragraph) loop Minimum_Badnesses (Y + 1) := Infinity; for X in reverse 1 .. Y loop declare Badness : constant Badness_Value := Line_Badness (Paragraph, X, Y, Max_Line_Length) + Minimum_Badnesses (X); begin exit when Badness = Infinity; -- ??? Badness might be uninitialized here if Badness < Minimum_Badnesses (Y + 1) then Minimum_Badnesses (Y + 1) := Badness; Result (Y) := X; end if; end; end loop; end loop; for Count in Result'First .. Result'Last - 1 loop pragma Assert (Result (Count) <= Result (Count + 1)); null; end loop; return Result; end Calculate_Best; --------------------------- -- Determine_First_Words -- --------------------------- function Determine_First_Words (Last_Word : Word_Count; Best_Words : Word_Indexes) return Word_Vector is X : Word_Index; Y : Word_Index := Last_Word; Result : Word_Vector; begin Append (Result, Word_Index'Last); loop X := Best_Words (Y); Append (Result, X); exit when X = 1; pragma Assert (Y /= X - 1); Y := X - 1; end loop; return Result; end Determine_First_Words; -- Start of processing for Knuth_Fill begin if Paragraph = "" then return To_Unbounded_String (Paragraph); end if; return Merge_Lines (W => Para, Split_Before_Word => Determine_First_Words (Last_Word (Para), Calculate_Best (Para, Max_Line_Length)), Line_Prefix => Line_Prefix); end Knuth_Fill; -------------------- -- No_Fill -- -------------------- function No_Fill (Paragraph : String; Max_Line_Length : Positive := Default_Max_Line_Length; Line_Prefix : String := "") return Unbounded_String is pragma Unreferenced (Max_Line_Length, Line_Prefix); begin return To_Unbounded_String (Paragraph); end No_Fill; --------------- -- Nth_Index -- --------------- function Nth_Index (Source : Unbounded_String; Pattern : String; N : Natural) return Natural is Result : Natural := 0; begin for Count in 1 .. N loop Result := Index (Source, Pattern, Result + 1); -- If there are > N instances the next intstance after the last -- existing instance will return 0. If the loop continues to -- run Index will start from the beginning and will end on an -- arbitrary instance. exit when Result = 0; end loop; return Result; end Nth_Index; ----------------- -- Pretty_Fill -- ----------------- function Pretty_Fill (Paragraph : String; Max_Line_Length : Positive := Default_Max_Line_Length) return Unbounded_String is -- Since we will be changing the lines afterward, this is not compatible -- with the use of Line_Prefix. Result : Unbounded_String := Greedy_Fill (Paragraph, Max_Line_Length, Line_Prefix => ""); Number_Of_Lines : constant Natural := Count_Lines (Result); Did_Something : Boolean; Count : Natural := 0; begin -- Compares adjacent lines, starting with the first and second line -- and ending with the third to last and second to last lines. If -- Badness after moving the last word of the upper line to the next -- line is less than or equal to Badness of leaving the paragraph alone, -- then the word is moved. This is repeated through the whole paragraph -- (Max_Line_Length / 2) * Number_Of_Lines times or until nothing is -- changed in a loop of the paragraph. loop Count := Count + 1; Did_Something := False; for Line_Number in 1 .. Number_Of_Lines - 2 loop declare -- ??? Very inefficient, we keep searching the same pattern -- over and over. Index_0 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Line_Number - 1); Index_1 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Line_Number); Index_2 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Line_Number + 1); Length_1 : constant Positive := Index_1 - Index_0 - 1; Length_2 : constant Positive := Index_2 - Index_1 - 1; Word_Start : constant Natural := Index (Result, " ", Index_1, Backward); Word_Length : constant Positive := Index_1 - Word_Start; begin if Can_And_Should_Move_A_Word (Max_Line_Length, Length_1, Length_2, Word_Length) then Replace_Element (Result, Word_Start, ASCII.LF); Replace_Element (Result, Index_1, ' '); Did_Something := True; end if; end; end loop; exit when not Did_Something; end loop; if Number_Of_Lines >= 4 then declare Index_0 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Number_Of_Lines - 3); Index_1 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Number_Of_Lines - 2); Index_2 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Number_Of_Lines - 1); Index_3 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Number_Of_Lines); Length_1 : constant Positive := Index_1 - Index_0 - 1; Length_2 : constant Positive := Index_2 - Index_1 - 1; Length_3 : constant Positive := Index_3 - Index_2 - 1; Word_Start : constant Natural := Index (Result, " ", Index_2, Backward); Word_Length : constant Positive := Index_2 - Word_Start; begin if Length_3 + Word_Length <= Max_Line_Length and then abs (Length_2 - Length_1) > abs (Length_2 - Length_1 - Word_Length) then Replace_Element (Result, Word_Start, ASCII.LF); Replace_Element (Result, Index_2, ' '); Did_Something := True; end if; end; elsif Number_Of_Lines = 3 then declare Index_0 : constant Natural := 0; Index_1 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Number_Of_Lines - 2); Index_2 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Number_Of_Lines - 1); Index_3 : constant Natural := Nth_Index (Result, "" & ASCII.LF, Number_Of_Lines); Length_1 : constant Positive := Index_1 - Index_0 - 1; Length_2 : constant Positive := Index_2 - Index_1 - 1; Length_3 : constant Positive := Index_3 - Index_2 - 1; Word_Start : constant Natural := Index (Result, " ", Index_2, Backward); Word_Length : constant Positive := Index_2 - Word_Start; begin if Length_3 + Word_Length <= Max_Line_Length and then abs (Length_2 - Length_1) > abs (Length_2 - Length_1 - Word_Length) then Replace_Element (Result, Word_Start, ASCII.LF); Replace_Element (Result, Index_2, ' '); Did_Something := True; end if; end; end if; return Result; end Pretty_Fill; end GNATCOLL.Paragraph_Filling; alire-1.2.1/deps/gnatcoll-slim/src/paragraph_filling/gnatcoll-paragraph_filling.ads000066400000000000000000000116251425465243200305260ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2011-2017, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- This software was originally contributed by William A. Duff with Ada.Strings.Unbounded; package GNATCOLL.Paragraph_Filling is -- This purpose of this package is to format paragraphs to take up the -- minimal number of lines and to look better. -- Note: All subprograms in this package that take or return a String -- representing a paragraph represent multiple lines by using ASCII.LF -- as the line terminator. -- They return an unbounded_string to avoid extra copies (since internally -- they manipulate an unbounded_string). Default_Max_Line_Length : Positive := 79; -- This value is used as a default for the Max_Line_Length parameter of -- various subprograms. Note that 79 is the standard max line length used -- at AdaCore. function Greedy_Fill (Paragraph : String; Max_Line_Length : Positive := Default_Max_Line_Length; Line_Prefix : String := "") return Ada.Strings.Unbounded.Unbounded_String; -- Formats a paragraph with the greedy algorithm (by putting as many words -- as possible on each line). -- Line_Prefix is added at the beginning of each line. function Pretty_Fill (Paragraph : String; Max_Line_Length : Positive := Default_Max_Line_Length) return Ada.Strings.Unbounded.Unbounded_String; -- Formats a paragraph by first performing Greedy_Fill and then comparing -- adjacent lines and deciding whether a word should be moved to the next -- line to make the lines more even. For example: -- -- Reads Ada source code from the file named by Input_Name. Calls Format on -- each block comment, and sends the output to the file named by -- Output_Name. Text that is not part of a comment, and comments appearing -- after other non-whitespace text on the same line, is sent to the output -- unchanged. -- -- would be changed to: -- -- Reads Ada source code from the file named by Input_Name. Calls Format -- on each block comment, and sends the output to the file named by -- Output_Name. Text that is not part of a comment, and comments appearing -- after other non-whitespace text on the same line, is sent to the output -- unchanged. -- -- if the max line length is set to 72. function Knuth_Fill (Paragraph : String; Max_Line_Length : Positive := Default_Max_Line_Length; Line_Prefix : String := "") return Ada.Strings.Unbounded.Unbounded_String; -- Fill the paragraph in the best possible way, based on an algorithm -- invented by Knuth. This algorithm uses dynamic programming techniques in -- order to fill paragraphs so that they have the lowest possible badness -- and line count. Badness is calculated by the Line_Badness function in -- Paragraph_Filling.Badnesses. For details see the paper, "Breaking -- Paragraphs into Lines", by Donald E. Knuth and Michael F. Plass, -- Software Practice and Experience, 11 (1981). function No_Fill (Paragraph : String; Max_Line_Length : Positive := Default_Max_Line_Length; Line_Prefix : String := "") return Ada.Strings.Unbounded.Unbounded_String; -- Return Paragraph unchanged end GNATCOLL.Paragraph_Filling; alire-1.2.1/deps/gnatcoll-slim/src/run_path_option.c000066400000000000000000000026551425465243200224710ustar00rootroot00000000000000/********************************************************************* * G P S * * * * Copyright (C) 2002-2004 * * ACT-Europe * * * * GPS 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 2 of the License, or * * (at your option) any later version. * * * * This program 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. You should have received * * a copy of the GNU General Public License along with this program; * * if not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ /* Dummy version of run_path_option, needed by mlib.adb */ const char *__gnat_run_path_option = ""; alire-1.2.1/deps/gnatcoll-slim/src/separate_run_path_option.c000066400000000000000000000025771425465243200243600ustar00rootroot00000000000000/********************************************************************* * G P S * * * * Copyright (C) 2009-2017, AdaCore * * * * GPS 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 2 of the License, or * * (at your option) any later version. * * * * This program 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. You should have received * * a copy of the GNU General Public License along with this program; * * if not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ /* Dummy version of __gnat_separate_run_path_options, needed by mlib.adb */ const char __gnat_separate_run_path_options = 0; alire-1.2.1/deps/gnatcoll-slim/src/set_std_prefix.c000066400000000000000000000026621425465243200223010ustar00rootroot00000000000000/********************************************************************* * G P S * * * * Copyright (C) 2002-2004 * * ACT-Europe * * * * GPS 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 2 of the License, or * * (at your option) any later version. * * * * This program 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. You should have received * * a copy of the GNU General Public License along with this program; * * if not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ /* Dummy version of set_std_prefix (needed by osint.adb) */ void set_std_prefix (char *path, int len) { } alire-1.2.1/deps/gnatcoll-slim/src/terminals.c000066400000000000000000000105101425465243200212440ustar00rootroot00000000000000/*---------------------------------------------------------------------------- -- G N A T C O L L -- -- -- -- Copyright (C) 2014-2017, AdaCore -- -- -- -- This is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 3, or (at your option) any later ver- -- -- sion. This software is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- -- License for more details. You should have received a copy of the GNU -- -- General Public License distributed with this software; see file -- -- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy -- -- of the license. -- ----------------------------------------------------------------------------*/ #ifdef _WIN32 #include #include #include #else #include #ifdef HAVE_TERMIOS_H #include // for TIOCGWINSZ on some systems #endif #include #include #endif int gnatcoll_get_console_screen_buffer_info(int forStderr) { #ifdef _WIN32 const HANDLE handle = GetStdHandle (forStderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbiInfo; if (GetConsoleScreenBufferInfo (handle, &csbiInfo)) { return csbiInfo.wAttributes; } #else return -1; #endif } void gnatcoll_set_console_text_attribute(int forStderr, int attrs) { #ifdef _WIN32 const HANDLE handle = GetStdHandle (forStderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE); SetConsoleTextAttribute (handle, (WORD)attrs); #endif } int gnatcoll_terminal_has_colors(int fd) { #ifdef _WIN32 return _isatty(fd); #else // Ideally, we should check the terminfo database and check the // max_colors fields (from the command line, this is done with // "tput colors"). However, this is fairly complex, and would // drag in the curses library. // For now, let's just assume that a tty always supports colors, // which is true in this day and age for interactive terminals on // all Unix platforms. A pipe will return 0 below, so will not have // colors by default. // ??? We could also check the value of the TERM environment variable, // but this is very approximate at best. return isatty(fd); #endif } void gnatcoll_beginning_of_line(int forStderr) { #ifdef _WIN32 const HANDLE handle = GetStdHandle (forStderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbiInfo; if (GetConsoleScreenBufferInfo (handle, &csbiInfo)) { csbiInfo.dwCursorPosition.X = 0; SetConsoleCursorPosition(handle, csbiInfo.dwCursorPosition); } #else // struct winsize ws; // ioctl(forStderr ? 2 : 1, TIOCGWINSZ, &ws); if (write(forStderr ? 2 : 1, "\r", 1) != 1) { // Ignore failure for now } #endif } void gnatcoll_clear_to_end_of_line(int forStderr) { #ifdef _WIN32 const HANDLE handle = GetStdHandle (forStderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbiInfo; if (GetConsoleScreenBufferInfo (handle, &csbiInfo)) { DWORD numberOfCharsWritten; FillConsoleOutputCharacter( handle, ' ', csbiInfo.dwSize.X - csbiInfo.dwCursorPosition.X + 1, // length csbiInfo.dwCursorPosition, // dWriteCoord &numberOfCharsWritten); } #else if (write(forStderr ? 2 : 1, "\033[0K", 4) != 4) { // Ignore failure for now } #endif } int gnatcoll_terminal_width(int forStderr) { #ifdef _WIN32 const HANDLE handle = GetStdHandle (forStderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbiInfo; if (GetConsoleScreenBufferInfo (handle, &csbiInfo)) { return (int)csbiInfo.dwSize.X; } return -1; #else #ifdef TIOCGWINSZ struct winsize w; ioctl(forStderr ? 1 : 0, TIOCGWINSZ, &w); return w.ws_col; #else return -1; #endif #endif } alire-1.2.1/deps/gnatcoll-slim/src/update_path.c000066400000000000000000000026771425465243200215630ustar00rootroot00000000000000/********************************************************************* * G P S * * * * Copyright (C) 2002-2004 * * ACT-Europe * * * * GPS 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 2 of the License, or * * (at your option) any later version. * * * * This program 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. You should have received * * a copy of the GNU General Public License along with this program; * * if not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ /* Dummy version of update_path (needed by osint.adb) */ char * update_path (char *path, char *key) { return path; } alire-1.2.1/deps/gnatcoll-slim/testsuite/000077500000000000000000000000001425465243200203475ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/README.md000066400000000000000000000010451425465243200216260ustar00rootroot00000000000000Running GNATcoll Testsuite ========================== `The testsuite is currently under construction !` To run it you need to have Python installed along with the package e3-testsuite. To install e3-testsuite: ```sh pip install git+https://github.com/AdaCore/e3-testsuite.git ``` Then do ```sh ./run-tests ``` In order to have coverage information with gcov, just add `--gcov`. In that case a summary of the coverage information is displayed at the end of the testsuite. Full coverage information can be found in `gcov/results` subdirectory. alire-1.2.1/deps/gnatcoll-slim/testsuite/drivers/000077500000000000000000000000001425465243200220255ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/drivers/__init__.py000066400000000000000000000065761425465243200241540ustar00rootroot00000000000000from e3.env import Env from e3.fs import mkdir from e3.os.process import Run from e3.testsuite.process import check_call import os import logging TESTSUITE_ROOT_DIR = os.path.dirname( os.path.dirname(os.path.abspath(__file__))) GNATCOLL_ROOT_DIR = os.path.dirname(TESTSUITE_ROOT_DIR) def make_gnatcoll_for_gcov(work_dir): """Build gnatcoll core with gcov instrumentation. :param work_dir: working directory. gnatcoll is built in `build` subdir and installed in `install` subdir :type work_dir: str :return: a triplet (project path, source path, object path) :rtype: (str, str, str) :raise AssertError: in case compilation of installation fails """ logging.info('Compiling gnatcoll with gcov instrumentation') build_dir = os.path.join(work_dir, 'build') install_dir = os.path.join(work_dir, 'install') mkdir(build_dir) mkdir(install_dir) make_gnatcoll_cmd = [ 'make', '-f', os.path.join(GNATCOLL_ROOT_DIR, 'Makefile'), 'BUILD=DEBUG', 'GPRBUILD_OPTIONS=-cargs -fprofile-arcs -ftest-coverage -gargs', 'ENABLE_SHARED=no'] p = Run(make_gnatcoll_cmd, cwd=build_dir) assert p.status == 0, "gnatcoll build failed:\n%s" % p.out p = Run(make_gnatcoll_cmd + ['prefix=%s' % install_dir, 'install'], cwd=build_dir) assert p.status == 0, "gnatcoll installation failed:\n%s" % p.out # Add the resulting library into the GPR path Env().add_search_path('GPR_PROJECT_PATH', os.path.join(install_dir, 'share', 'gpr')) return (os.path.join(install_dir, 'share', 'gpr'), os.path.join(install_dir, 'include', 'gnatcoll'), os.path.join(build_dir, 'obj', 'gnatcoll', 'static')) def gprbuild(driver, project_file=None, cwd=None, gcov=False, scenario=None, **kwargs): """Launch gprbuild. :param project_file: project file to compile. If None, we looks first for a test.gpr in the test dir and otherwise fallback on the common test.gpr project of the support subdir of the testsuite. :type project_file: str :param cwd: directory in which to run gprbuild. If None the gprbuild build is run in the default working dir for the test. :type cwd: str | None :param gcov: if True link with gcov libraries :type gcov: bool :param scenario: scenario variable values :type scenario: dict """ if scenario is None: scenario = {} if project_file is None: project_file = os.path.join(driver.test_env['test_dir'], 'test.gpr') if not os.path.isfile(project_file): project_file = os.path.join(TESTSUITE_ROOT_DIR, 'support', 'test.gpr') scenario['TEST_SOURCES'] = driver.test_env['test_dir'] if cwd is None: cwd = driver.test_env['working_dir'] mkdir(cwd) gprbuild_cmd = [ 'gprbuild', '--relocate-build-tree', '-p', '-P', project_file] for k, v in scenario.iteritems(): gprbuild_cmd.append('-X%s=%s' % (k, v)) if gcov: gprbuild_cmd += ['-largs', '-lgcov', '-cargs', '-fprofile-arcs', '-ftest-coverage'] check_call( driver, gprbuild_cmd, cwd=cwd, **kwargs) # If we get there it means the build succeeded. return True alire-1.2.1/deps/gnatcoll-slim/testsuite/drivers/basic.py000066400000000000000000000036741425465243200234720ustar00rootroot00000000000000from e3.fs import cp from e3.testsuite.driver import TestDriver from e3.testsuite.process import check_call from e3.testsuite.result import TestStatus from drivers import gprbuild import os class BasicTestDriver(TestDriver): """Default GNATcoll testsuite driver. In order to declare a test: 1- Create a directory with a test.yaml inside 2- Add test sources in that directory 3- Add a main called test.adb that use support/test_assert.ads package. 4- Do not put test.gpr there, it breaks the test, if you need a project file for testing, name it something else. 5- If you need additional files for you test, list them in test.yaml: data: - "your_file1" - "your_file2" """ def add_test(self, dag): """Declare test workflow. The workflow is the following:: build --> check status :param dag: tree of test fragment to amend :type dag: e3.collection.dag.DAG """ self.add_fragment(dag, 'build') self.add_fragment(dag, 'check_run', after=['build']) if 'test_exe' not in self.test_env: self.test_env['test_exe'] = 'obj/test' def build(self, previous_values): """Build fragment.""" return gprbuild(self, gcov=self.env.gcov) def check_run(self, previous_values): """Check status fragment.""" if not previous_values['build']: return for data in self.test_env.get('data', []): cp(os.path.join(self.test_env['test_dir'], data), self.test_env['working_dir'], recursive=True) process = check_call( self, [os.path.join(self.test_env['working_dir'], self.test_env['test_exe'])]) if '<=== TEST PASSED ===>' not in process.out: self.result.set_status(TestStatus.FAIL) else: self.result.set_status(TestStatus.PASS) self.push_result() alire-1.2.1/deps/gnatcoll-slim/testsuite/drivers/data_validation.py000066400000000000000000000046201425465243200255240ustar00rootroot00000000000000from e3.fs import rm from e3.testsuite.driver import TestDriver from e3.testsuite.process import check_call from e3.testsuite.result import TestStatus, TestResult from drivers import gprbuild import os class DataValidationDriver(TestDriver): """Data validation driver. For each test program call the program with data file defined in data_files key of the test. If the program returns 0 assume that the test passed. """ def add_test(self, dag): self.add_fragment(dag, 'build') tear_down_deps = [] for data_file, description in self.test_env['data_files'].iteritems(): tear_down_deps.append(data_file) self.add_fragment( dag, data_file, fun=lambda x, d=data_file, m=description: self.run_subtest(d, m, x), after=['build']) self.add_fragment(dag, 'tear_down', after=tear_down_deps) def run_subtest(self, data_file, description, previous_values): test_name = self.test_name + '.' + data_file result = TestResult(test_name, env=self.test_env) if not previous_values['build']: return TestStatus.FAIL process = check_call( self, [os.path.join(self.test_env['working_dir'], self.test_env.get('validator', 'obj/test')), os.path.join(self.test_env['test_dir'], data_file)], result=result) return self.validate_result(process, data_file, result) def validate_result(self, process, data_file, result): # Read data file if '<=== TEST PASSED ===>' in process.out: return TestStatus.PASS else: result.set_status(TestStatus.FAIL) self.push_result(result) return TestStatus.FAIL def tear_down(self, previous_values): failures = [v for v in previous_values.values() if not isinstance(v, TestStatus) or v != TestStatus.PASS] if failures: self.result.set_status(TestStatus.FAIL, msg="%s subtests failed" % len(failures)) else: self.result.set_status(TestStatus.PASS) self.push_result() if self.env.enable_cleanup: rm(self.test_env['working_dir'], recursive=True) def build(self, previous_values): return gprbuild(self, gcov=self.env.gcov) alire-1.2.1/deps/gnatcoll-slim/testsuite/drivers/json_validation.py000066400000000000000000000012471425465243200255660ustar00rootroot00000000000000from e3.testsuite.result import TestStatus from drivers.data_validation import DataValidationDriver import os import json import logging class JSONValidationDriver(DataValidationDriver): def validate_result(self, process, data_file, result): # Read data file with open(os.path.join(self.test_env['test_dir'], data_file)) as fd: expected = json.load(fd) got = json.loads(process.out) if got != expected: logging.debug('%s\n<=>\n%s', got, expected) result.set_status(TestStatus.FAIL) self.push_result(result) return TestStatus.FAIL else: return TestStatus.PASS alire-1.2.1/deps/gnatcoll-slim/testsuite/e3-test.yaml000066400000000000000000000000411425465243200225120ustar00rootroot00000000000000main: run-tests default_args: [] alire-1.2.1/deps/gnatcoll-slim/testsuite/run-tests000077500000000000000000000074471425465243200222550ustar00rootroot00000000000000#!/usr/bin/env python from drivers import make_gnatcoll_for_gcov, TESTSUITE_ROOT_DIR from drivers.basic import BasicTestDriver from drivers.json_validation import JSONValidationDriver from drivers.data_validation import DataValidationDriver from e3.testsuite import Testsuite from e3.fs import mkdir, ls, find from e3.os.process import Run import re import os import logging class MyTestsuite(Testsuite): CROSS_SUPPORT = True TEST_SUBDIR = 'tests' DRIVERS = { 'json_validation': JSONValidationDriver, 'data_validation': DataValidationDriver, 'default': BasicTestDriver} def add_options(self): self.main.argument_parser.add_argument( '--gcov', help="compute testsuite coverage of gnatcoll", default=False, action="store_true") def tear_up(self): self.env.gcov = self.main.args.gcov self.env.enable_cleanup = self.main.args.enable_cleanup if self.main.args.gcov: work_dir = os.path.join(TESTSUITE_ROOT_DIR, 'gcov') gpr_dir, src_dir, obj_dir = make_gnatcoll_for_gcov(work_dir) self.env.gnatcoll_gpr_dir = gpr_dir self.env.gnatcoll_src_dir = src_dir self.env.gnatcoll_obj_dir = obj_dir def tear_down(self): if self.main.args.gcov: wd = TESTSUITE_ROOT_DIR # We need to call gcov on gcda present both in gnatcoll itself and # tests (for generics coverage). gcda_files = \ find(os.path.join(self.env.gnatcoll_obj_dir), '*.gcda') + \ find(os.path.join(self.env.working_dir), '*.gcda') mkdir(os.path.join(wd, 'gcov', 'results')) gcr = os.path.join(wd, 'gcov', 'results') Run(['gcov'] + gcda_files, cwd=os.path.join(wd, 'gcov', 'results')) total_sources = 0 total_covered = 0 for source_file in ls( os.path.join(self.env.gnatcoll_src_dir, '*')): base_file = os.path.basename(source_file) if not os.path.isfile(os.path.join(gcr, base_file + '.gcov')): total = 1 covered = 0 with open(source_file) as fd: total = len([line for line in fd if line.strip() and not re.match(r' *--', line)]) else: with open(os.path.join(gcr, base_file + '.gcov')) as fd: total = 0 covered = 0 for line in fd: if re.match(r' *-:', line): pass elif re.match(r' *[#=]{5}:', line): total += 1 else: total += 1 covered += 1 total_sources += total total_covered += covered logging.info('%6.2f %% %8d/%-8d %s', float(covered) * 100.0 / float(total), covered, total, os.path.basename(source_file)) logging.info('%6.2f %% %8d/%-8d %s', float(total_covered) * 100.0 / float(total_sources), total_covered, total_sources, 'TOTAL') super(MyTestsuite, self).tear_down() @property def default_driver(self): return 'default' if __name__ == '__main__': suite = MyTestsuite(os.path.dirname(__file__)) suite.testsuite_main() for k, v in suite.test_status_counters.iteritems(): print '%-24s: %d' % (k, v) alire-1.2.1/deps/gnatcoll-slim/testsuite/support/000077500000000000000000000000001425465243200220635ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/support/test.gpr000066400000000000000000000005571425465243200235630ustar00rootroot00000000000000-- Default project use for tests -- -- The scenario variable TEST_SOURCES is automatically set by the -- driver to point to the test sources. with "gnatcoll"; project Test is Test_Sources := External("TEST_SOURCES"); for Source_Dirs use (".", Test_Sources); for Main use ("test.adb"); for Languages use ("Ada"); for Object_Dir use "obj"; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/support/test_assert.adb000066400000000000000000000073271425465243200251040ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Text_IO; package body Test_Assert is package IO renames Ada.Text_IO; ------------ -- Assert -- ------------ procedure Assert (Success : Boolean; Msg : String := ""; Location : String := SI.Source_Location) is begin IO.Put (Location & ": "); if Success then IO.Put ("PASSED:"); else IO.Put ("FAILED:"); Final_Status := 1; end if; if Msg'Length > 0 then IO.Put (" "); IO.Put (Msg); end if; IO.New_Line; end Assert; ------------ -- Assert -- ------------ procedure Assert (Left, Right : String; Msg : String := ""; Location : String := SI.Source_Location) is Success : constant Boolean := Left = Right; begin Assert (Success, Msg, Location); if not Success then if Right'Length > 0 then IO.Put_Line ("expected: " & Right); else IO.Put_Line ("expected empty string"); end if; if Left'Length > 0 then IO.Put_Line ("got: " & Left); else IO.Put_Line ("got empty string"); end if; end if; end Assert; ------------ -- Assert -- ------------ procedure Assert (Left, Right : VFS.Virtual_File; Msg : String := ""; Location : String := SI.Source_Location) is use type VFS.Virtual_File; Success : constant Boolean := Left = Right; begin Assert (Success, Msg, Location); if not Success then IO.Put_Line ("expected: " & VFS.Display_Full_Name (Right)); IO.Put_Line ("got: " & VFS.Display_Full_Name (Left)); end if; end Assert; ------------ -- Report -- ------------ function Report return Natural is begin if Final_Status = 0 then IO.Put_Line ("<=== TEST PASSED ===>"); else IO.PUT_Line ("<=== TEST FAILED ===>"); end if; return Final_Status; end Report; end Test_Assert; alire-1.2.1/deps/gnatcoll-slim/testsuite/support/test_assert.ads000066400000000000000000000063061425465243200251210ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Helper package to implement tests that comply with the expectations -- of the default test driver. with GNAT.Source_Info; with GNATCOLL.VFS; package Test_Assert is package SI renames GNAT.Source_Info; package VFS renames GNATCOLL.VFS; Final_Status : Natural := 0; procedure Assert (Success : Boolean; Msg : String := ""; Location : String := SI.Source_Location); -- If Success is True then test case is considered PASSED, otherwise -- the test status is FAILED and Final_Status set to 1. procedure Assert (Left, Right : String; Msg : String := ""; Location : String := SI.Source_Location); -- If Left = Right then test case is considered PASSED, otherwise -- the test status is FAILED and Final_Status set to 1. procedure Assert (Left, Right : VFS.Virtual_File; Msg : String := ""; Location : String := SI.Source_Location); -- If Left = Right then test case is considered PASSED, otherwise -- the test status is FAILED and Final_Status set to 1. function Report return Natural; -- Report should be called the following way at the end of a test -- program main function: -- -- return Report; -- -- Testsuite driver will consider a test to PASS if all the -- following conditions are met: -- -- * test program exit with status 0 -- * all assert calls did succeed -- * test program display the message "<=== TEST PASSED ===>" end Test_Assert; alire-1.2.1/deps/gnatcoll-slim/testsuite/support/test_assert.ads.orig000066400000000000000000000063061425465243200260600ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- Helper package to implement tests that comply with the expectations -- of the default test driver. with GNAT.Source_Info; with GNATCOLL.VFS; package Test_Assert is package SI renames GNAT.Source_Info; package VFS renames GNATCOLL.VFS; Final_Status : Natural := 0; procedure Assert (Success : Boolean; Msg : String := ""; Location : String := SI.Source_Location); -- If Success is True then test case is considered PASSED, otherwise -- the test status is FAILED and Final_Status set to 1. procedure Assert (Left, Right : String; Msg : String := ""; Location : String := SI.Source_Location); -- If Left = Right then test case is considered PASSED, otherwise -- the test status is FAILED and Final_Status set to 1. procedure Assert (Left, Right : VFS.Virtual_File; Msg : String := ""; Location : String := SI.Source_Location); -- If Left = Right then test case is considered PASSED, otherwise -- the test status is FAILED and Final_Status set to 1. function Report return Natural; -- Report should be called the following way at the end of a test -- program main procedure: -- -- return Report; -- -- Testsuite driver will consider a test to PASS if all the -- following conditions are met: -- -- * test program exit with status 0 -- * all assert calls did succeed -- * test program display the message "<=== TEST PASSED ===>" end Test_Assert; alire-1.2.1/deps/gnatcoll-slim/testsuite/support/test_remote.adb000066400000000000000000000145721425465243200250760ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with GNAT.OS_Lib; with GNAT.Directory_Operations; with GNAT.Expect; with GNAT.Expect.TTY; with Ada.Text_IO; with GNATCOLL.Utils; package body Test_Remote is package Expect renames GNAT.Expect; package OS renames GNAT.OS_Lib; package OS_Path renames GNAT.Directory_Operations; package IO renames Ada.Text_IO; use type GVT.FS_String; -------------- -- Nickname -- -------------- function Nickname (Server : Local_Transport) return String is begin return "local"; end Nickname; -------------- -- Shell_FS -- -------------- function Shell_FS (Server : Local_Transport) return GVT.FS_Type is begin return GVT.FS_Unix; end Shell_FS; ---------------------- -- Execute_Remotely -- ---------------------- procedure Execute_Remotely (Server : access Local_Transport; Args : GNAT.Strings.String_List; Status : out Boolean; Execution_Directory : GVT.FS_String := "") is CWD : constant String := OS_Path.Get_Current_Dir; Script : constant String := GNATCOLL.Utils.Join (" ", Args); Program_Name : constant String := "/bin/bash"; Program_Args : GNAT.Strings.String_List (1 .. 2) := (1 => new String'("-c"), 2 => new String'(Script)); begin if Execution_Directory /= "" then OS_Path.Change_Dir (String (Execution_Directory)); end if; OS.Spawn (Program_Name, Program_Args, Status); if Execution_Directory /= "" then OS_Path.Change_Dir (String (CWD)); end if; end Execute_Remotely; ---------------------- -- Execute_Remotely -- ---------------------- procedure Execute_Remotely (Server : access Local_Transport; Args : GNAT.Strings.String_List; Result : out GNAT.Strings.String_Access; Status : out Boolean; Execution_Directory : GVT.FS_String := "") is CWD : constant String := OS_Path.Get_Current_Dir; Program_Name : constant String := Args (1).all; Program_Args : constant GNAT.Strings.String_List := Args (2 .. Args'Last); Int_Status : aliased Integer; begin if Execution_Directory /= "" then OS_Path.Change_Dir (String (Execution_Directory)); end if; IO.Put_Line (Program_Name); Result := new String' (Expect.Get_Command_Output (Program_Name, Program_Args, "", Int_Status'Access, True)); if Int_Status = 0 then Status := True; else Status := False; end if; if Execution_Directory /= "" then OS_Path.Change_Dir (String (CWD)); end if; end Execute_Remotely; -------------------- -- Spawn_Remotely -- -------------------- procedure Spawn_Remotely (Server : access Local_Transport; Descriptor : out GNAT.Expect.Process_Descriptor_Access; Args : GNAT.Strings.String_List) is Program_Name : constant String := Args (1).all; Program_Args : constant GNAT.Strings.String_List := Args (2 .. Args'Last); begin Descriptor := new GNAT.Expect.TTY.TTY_Process_Descriptor; IO.Put_Line (Program_Name); Expect.Non_Blocking_Spawn (Descriptor.all, Program_Name, Program_Args); end Spawn_Remotely; ------------------- -- Is_Configured -- ------------------- function Is_Configured (Config : Local_DB; Nickname : String) return Boolean is begin if Nickname = "local_test" then return True; else return False; end if; end Is_Configured; ---------------- -- Get_Server -- ---------------- function Get_Server (Config : Local_DB; Nickname : String) return GR.Server_Access is begin return new Local_Transport; end Get_Server; --------------------- -- Nb_Mount_Points -- --------------------- function Nb_Mount_Points (Config : Local_DB; Nickname : String) return Natural is begin return 1; end Nb_Mount_Points; -------------------------------- -- Get_Mount_Point_Local_Root -- -------------------------------- function Get_Mount_Point_Local_Root (Config : Local_DB; Nickname : String; Index : Natural) return GVT.FS_String is begin return "/tmp/local_vfs"; end Get_Mount_Point_Local_Root; ------------------------------- -- Get_Mount_Point_Host_Root -- ------------------------------- function Get_Mount_Point_Host_Root (Config : Local_DB; Nickname : String; Index : Natural) return GVT.FS_String is begin return "/tmp/remote_vfs"; end Get_Mount_Point_Host_Root; end Test_Remote; alire-1.2.1/deps/gnatcoll-slim/testsuite/support/test_remote.ads000066400000000000000000000074351425465243200251170ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ -- The package provides remote support using only local resources. This -- allows to test remote functionalities without the need for a remote host. with GNAT.Expect; with GNAT.Strings; with GNATCOLL.Remote; with GNATCOLL.VFS_Types; with GNATCOLL.Remote.DB; package Test_Remote is package GR renames GNATCOLL.Remote; package GRDB renames GNATCOLL.Remote.DB; package GVT renames GNATCOLL.VFS_Types; -- Declare local transport protocol (basically spawn /bin/bash) type Local_Transport is new GR.Server_Record with null record; function Nickname (Server : Local_Transport) return String; function Shell_FS (Server : Local_Transport) return GVT.FS_Type; procedure Execute_Remotely (Server : access Local_Transport; Args : GNAT.Strings.String_List; Status : out Boolean; Execution_Directory : GVT.FS_String := ""); procedure Execute_Remotely (Server : access Local_Transport; Args : GNAT.Strings.String_List; Result : out GNAT.Strings.String_Access; Status : out Boolean; Execution_Directory : GVT.FS_String := ""); procedure Spawn_Remotely (Server : access Local_Transport; Descriptor : out GNAT.Expect.Process_Descriptor_Access; Args : GNAT.Strings.String_List); -- Declare local remote database which holds only one host nickname -- called local_test type Local_DB is new GRDB.Remote_Db_Interface with null record; function Is_Configured (Config : Local_DB; Nickname : String) return Boolean; function Get_Server (Config : Local_DB; Nickname : String) return GR.Server_Access; function Nb_Mount_Points (Config : Local_DB; Nickname : String) return Natural; function Get_Mount_Point_Local_Root (Config : Local_DB; Nickname : String; Index : Natural) return GVT.FS_String; function Get_Mount_Point_Host_Root (Config : Local_DB; Nickname : String; Index : Natural) return GVT.FS_String; end Test_Remote; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/000077500000000000000000000000001425465243200215115ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/000077500000000000000000000000001425465243200227565ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/test.adb000066400000000000000000000143341425465243200244120ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Text_IO; with GNATCOLL.Config; with Test_Assert; function Test return Integer is package IO renames Ada.Text_IO; package A renames Test_Assert; package Cfg renames GNATCOLL.Config; Ini : Cfg.INI_Parser; Ini2 : Cfg.INI_Parser; Ini3 : Cfg.INI_Parser; Pool : Cfg.Config_Pool; begin -- Open non existing file begin Ini.Open ("non_existent.ini"); A.Assert (False, "Name_Error should be raised"); exception when IO.Name_Error => A.Assert (True, "Name_Error raised if ini file does not exist"); when others => A.Assert (False, "Name_Error should have been raised"); end; -- Open a simple file IO.Put_Line ("Loading test1.ini"); Ini.Open ("test1.ini"); Pool.Fill (Ini); A.Assert (Pool.Get ("key1"), "value1", "check that key1=value1"); A.Assert (Pool.Get ("key2", Section => "section1"), "value2", "check that key2=value2 in section1"); A.Assert (Pool.Get ("key3", Section => "section1"), "value 3", "check that trailing spaces are ignored"); A.Assert (Pool.Get ("section1.key2", Section=> Cfg.Section_From_Key), "value2", "check that sections1.key2=value2 (dot notation)"); A.Assert (Pool.Get ("section1.key4"), "value4", "check that comments around key " & "declaration do not have impacts"); A.Assert (Pool.Get ("section1.key[5"), "value5", "key can contain ["); A.Assert (Pool.Get ("section1.[key6"), "value6", "key can start with ["); -- Try to read invalid file (parser is very laxist and does not crash) Ini.Open ("test2.ini"); Pool.Fill (Ini); A.Assert (Pool.Get ("key1"), "value1", "check if key1=value1 is preserved"); A.Assert (Pool.Get ("invalid"), "", "check if invalid key exist"); -- Check if we can override values. -- The test reuse the same INI_Parser instance and thus check that on -- call to Open parser state is reset IO.Put_Line ("Loading test3.ini (parser reuse)"); Ini.Open ("test3.ini"); Pool.Fill (Ini); A.Assert (Pool.Get ("key1"), "value1_2", "check if key1 is overwritten"); A.Assert (Pool.Get ("key7"), "value7", "check addition of new key key7"); A.Assert (Pool.Get ("section1.key2"), "value2", "check if section1.key2=value2 is preserved"); -- Check if we can override values -- Use a new parser instance IO.Put_Line ("Loading test3.ini (new parser)"); Ini2.Open ("test3.ini"); Pool.Fill (Ini2); A.Assert (Pool.Get ("key1"), "value1_2", "check if key1 value is overwritten"); A.Assert (Pool.Get ("key7"), "value7", "check addtion of new key key7"); A.Assert (Pool.Get ("section1.key2"), "value2", "check if section1.key2=value2 is preserved"); -- Test non string values A.Assert (Pool.Get_Boolean ("bool1"), "boolean value (true)"); A.Assert (not Pool.Get_Boolean ("bool2"), "boolean value (false)"); A.Assert (Pool.Get_Integer ("int1") = 1, "integer value"); -- Test Config_Key creation declare CK1 : Cfg.Config_Key := Cfg.Create ("key1"); begin A.Assert (CK1.Get (Pool), "value1_2", "basic config_key test"); end; -- Check that introducing invalid gnatcoll templates strings do -- not crash the parser. IO.Put_Line ("Loading test4.ini (crashing the gnatcoll-template)"); begin Ini3.Open ("test4.ini"); Pool.Fill (Ini3); A.Assert (True, "parsing test4.ini"); exception when others => A.Assert (False, "parsing test4.ini"); end; -- Check some corner cases involving leading whitespaces for example IO.Put_Line ("Loading test5.ini"); begin Ini3.Open ("test5.ini"); Pool.Fill (Ini3); A.Assert (True, "parsing test5.ini"); A.Assert (Pool.Get("#comment") /= "key", "ensure comment was parsed correctly"); A.Assert (Pool.Get("key5_1") /= "value2", "ensure section was parsed correctly"); A.Assert (Pool.Get("tion#key5_2", Section => "sec") /= "value3", "ensure # is not considered as a special character"); exception when others => A.Assert (False, "parsing test5.ini"); end; -- Check that a line containing only [ will not crash the parser begin Ini3.Open ("test6.ini"); Pool.Fill (Ini3); A.Assert (True, "parsing test6.ini"); exception when others => A.Assert (False, "parsing test6.ini"); end; return A.Report; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/test.yaml000066400000000000000000000000721425465243200246200ustar00rootroot00000000000000description: Test for GNATCOLL.Config data: - "*.ini" alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/test1.ini000066400000000000000000000003211425465243200245130ustar00rootroot00000000000000key1=value1 section1.key2 = value2_no_section int1 = 1 bool1=true bool2=False [section1] key2 = value2 key3 =value 3 # This is a comment = key4=value4 # This is another comment key[5=value5 [key6=value6 alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/test2.ini000066400000000000000000000000101425465243200245070ustar00rootroot00000000000000invalid alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/test3.ini000066400000000000000000000000341425465243200245160ustar00rootroot00000000000000key1 = value1_2 key7=value7 alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/test4.ini000066400000000000000000000000731425465243200245220ustar00rootroot00000000000000key8 = $e key9 = $: key10 = $( key11 = ${a =value12 key12= alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/test5.ini000066400000000000000000000001321425465243200245170ustar00rootroot00000000000000 #comment=key key5_1 = value [section5_1] key5_1 = value2 [sec#tion] key5_2 = value3 alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/config/test6.ini000066400000000000000000000000141425465243200245170ustar00rootroot00000000000000[ key=value alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/geometry/000077500000000000000000000000001425465243200233445ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/geometry/test.adb000066400000000000000000000415651425465243200250060ustar00rootroot00000000000000------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2010-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ with Ada.Text_IO; with GNATCOLL.Geometry; with Test_Assert; function Test return Integer is package IO renames Ada.Text_IO; package A renames Test_Assert; generic type Coordinate is digits <>; with package G is new GNATCOLL.Geometry (Coordinate); package Asserts is use type G.Point; Tolerance : constant G.Distance_Type := 1.0E-5; -- Tolerance when comparing distances procedure Put (P : G.Point); -- Put image of a point on stdout procedure Put (C : G.Circle); -- Put image of a circle on stdout procedure Assert (P1, P2 : G.Point; Error : String); -- Check if two points are equals procedure Assert_Inside (P : G.Point; S : G.Segment; On_Line : Boolean := True; On_Segment : Boolean := True; Error : String := ""); procedure Assert_Inside_Triangle (P : G.Point; T : G.Triangle; Result : Boolean := True; Error : String := ""); procedure Assert_Intersection (S1, S2 : G.Segment; On_Line, On_Segment : G.Point; Error : String); procedure Assert_Intersect_Triangle (T1, T2 : G.Triangle; Result : Boolean; Error : String); procedure Assert_Intersect_Rectangle (R1, R2 : G.Rectangle; Result : Boolean; Error : String); procedure Assert_Same_Side (P1, P2 : G.Point; S : G.Segment; Result : Boolean; Error : String); procedure Assert (D1, D2 : Coordinate'Base; Error : String); procedure Assert_Distance (P : G.Point; S : G.Segment; On_Line, On_Segment : Coordinate; Error : String); procedure Assert_Area (P : G.Polygon; D : Coordinate; Error : String); procedure Assert (C1, C2 : G.Circle; Error : String); end Asserts; package body Asserts is --------- -- Put -- --------- procedure Put (P : G.Point) is begin if P = G.No_Point then IO.Put ("(No point)"); elsif P = G.Infinity_Points then IO.Put ("(Infinity of points)"); else IO.Put ("(" & P.X'Img & "," & P.Y'Img & ")"); end if; end Put; --------- -- Put -- --------- procedure Put (C : G.Circle) is begin IO.Put ("(c="); Put (C.Center); IO.Put (" r=" & C.Radius'Img); end Put; ------------ -- Assert -- ------------ procedure Assert (P1, P2 : G.Point; Error : String) is Success : constant Boolean := P1 = P2; begin A.Assert (Success, Error); if not Success then IO.Put ("expected: "); Put (P1); IO.New_Line; IO.Put ("got: "); Put (P2); IO.New_Line; end if; end Assert; procedure Assert_Inside (P : G.Point; S : G.Segment; On_Line : Boolean := True; On_Segment : Boolean := True; Error : String := "") is SR : constant G.Segment := (S (2), S (1)); begin A.Assert (G.Inside (P, G.To_Line (S)) = On_Line, Error & " (line test)"); A.Assert (G.Inside (P, G.To_Line (SR)) = On_Line, Error & " (reverse line test)"); A.Assert (G.Inside (P, S) = On_Segment, Error & " (segment test)"); A.Assert (G.Inside (P, SR) = On_Segment, Error & " (reverse segment test)"); end Assert_Inside; procedure Assert_Inside_Triangle (P : G.Point; T : G.Triangle; Result : Boolean := True; Error : String := "") is T2 : constant G.Triangle := (T (3), T (2), T (1)); begin A.Assert (G.Inside (P, T) = Result, Error & " (triangle test)"); A.Assert (G.Inside (P, T2) = Result, Error & " (reverse triangle test)"); A.Assert (G.Inside (P, G.Polygon (T)) = Result, Error & " (polygon test)"); A.Assert (G.Inside (P, G.Polygon (T2)) = Result, Error & " (reverse polygon test)"); end Assert_Inside_Triangle; procedure Assert_Intersection (S1, S2 : G.Segment; On_Line : G.Point; On_Segment : G.Point; Error : String) is begin A.Assert (G.Intersection (G.To_Line (S1), G.To_Line (S2)) = On_Line, Error & " (line test)"); A.Assert (G.Intersection (G.To_Line (S2), G.To_Line (S1)) = On_Line, Error & " (reverse line test)"); A.Assert (G.Intersection (S1, S2) = On_Segment, Error & " (segment test)"); A.Assert (G.Intersection (S2, S1) = On_Segment, Error & " (reverse segment test)"); end Assert_Intersection; procedure Assert_Intersect_Triangle (T1, T2 : G.Triangle; Result : Boolean; Error : String) is T3 : constant G.Triangle := (T1 (2), T1 (3), T1 (1)); begin A.Assert (G.Intersect (T1, T2) = Result, Error & " (test1)"); A.Assert (G.Intersect (T2, T1) = Result, Error & " (test2)"); A.Assert (G.Intersect (T3, T2) = Result, Error & " (test3)"); A.Assert (G.Intersect (T2, T3) = Result, Error & " (test4)"); end Assert_Intersect_Triangle; procedure Assert_Intersect_Rectangle (R1, R2 : G.Rectangle; Result : Boolean; Error : String) is begin A.Assert (G.Intersect (R1, R2) = Result, Error); end Assert_Intersect_Rectangle; procedure Assert_Same_Side (P1, P2 : G.Point; S : G.Segment; Result : Boolean; Error : String) is begin A.Assert (G.Same_Side (P1, P2, S) = Result, Error & " (segment test)"); A.Assert (G.Same_Side (P1, P2, G.To_Line (S)) = Result, Error & " (line test)"); end Assert_Same_Side; procedure Assert (D1, D2 : Coordinate'Base; Error : String) is Success : constant Boolean := abs (D1 - D2) <= Tolerance; begin A.Assert (Success, Error); if not Success then IO.Put_Line ("expected: " & D1'Img); IO.Put_Line ("got: " & D2'Img); end if; end Assert; procedure Assert_Distance (P : G.Point; S : G.Segment; On_Line, On_Segment : Coordinate; Error : String) is SR : constant G.Segment := (S (2), S (1)); begin A.Assert (G.Distance (P, G.To_Line (S)) = On_Line, Error & " (line test)"); A.Assert (G.Distance (P, G.To_Line (SR)) = On_Line, Error & " (reverse line test)"); A.Assert (G.Distance (P, S) = On_Segment, Error & " (segment test)"); A.Assert (G.Distance (P, SR) = On_Segment, Error & " (reverse segment test)"); end Assert_Distance; procedure Assert_Area (P : G.Polygon; D : Coordinate; Error : String) is begin Assert (G.Area (P), abs (D), Error & " (poly test)"); if P'Length = 3 then Assert (G.Area (G.Triangle (P)), D, Error & " (triangle test)"); end if; end Assert_Area; procedure Assert (C1, C2 : G.Circle; Error : String) is use type G.Circle; Success : constant Boolean := C1 = C2; begin A.Assert (Success, Error); if not Success then IO.Put ("expected: "); Put (C1); IO.New_Line; IO.Put ("got: "); Put (C2); IO.New_Line; end if; end Assert; end Asserts; generic type Coordinate is digits <>; procedure Tests; procedure Tests is package G is new GNATCOLL.Geometry (Coordinate); package Assertions is new Asserts (Coordinate, G); use Assertions, G, G.Coordinate_Elementary_Functions; begin Assert_Inside ((2.0, 0.0), ((0.0, 0.0), (10.0, 0.0)), True, True, "Point on vertical line"); Assert_Inside ((-1.0, 0.0), ((0.0, 0.0), (10.0, 0.0)), True, False, "Point on vertical line, but not on segment"); Assert_Inside ((0.0, 0.0), ((0.0, 0.0), (10.0, 0.0)), True, True, "Point on vertical line at one end"); Assert_Inside ((0.0, 2.0), ((0.0, 0.0), (0.0, 10.0)), True, True, "Point on horizontal line"); Assert_Inside ((0.0, -1.0), ((0.0, 0.0), (0.0, 10.0)), True, False, "Point on horizontal line, but not on segment"); Assert_Inside ((0.0, 0.0), ((0.0, 0.0), (0.0, 10.0)), True, True, "Point on horizontal line at one end"); Assert_Inside ((0.0, 0.0), ((-2.0, 2.0), (2.0, 2.0)), False, False, "Not on line nor segment"); Assert_Intersection (((0.0, 0.0), (10.0, 0.0)), ((0.0, 0.0), (10.0, 0.0)), Infinity_Points, Infinity_Points, "Intersection of same horizontal line is infinite"); Assert_Intersection (((0.0, 0.0), (10.0, 0.0)), ((0.0, 0.0), (5.0, 0.0)), Infinity_Points, Infinity_Points, "Intersection of overlapping horizontal line is infinite"); Assert_Intersection (((0.0, 0.0), (0.0, 10.0)), ((0.0, 0.0), (0.0, 10.0)), Infinity_Points, Infinity_Points, "Intersection of same vertical line is infinite"); Assert_Intersection (((0.0, 0.0), (0.0, 10.0)), ((0.0, 0.0), (0.0, 5.0)), Infinity_Points, Infinity_Points, "Intersection of overlapping vertical vectors is infinite"); Assert_Intersection (((0.0, 0.0), (10.0, 0.0)), ((-2.0, 2.0), (2.0, 2.0)), No_Point, No_Point, "No intersection of parallel vectors"); Assert_Intersection (((0.0, 0.0), (10.0, 0.0)), ((11.0, 0.0), (20.0, 0.0)), Infinity_Points, No_Point, "Intersection of aligned vectors"); Assert_Intersection (((0.0, 0.0), (0.0, 10.0)), ((-2.0, 2.0), (2.0, 2.0)), Point'(0.0, 2.0), Point'(0.0, 2.0), "Simple segment intersection"); Assert_Intersection (((0.0, 0.0), (0.0, 10.0)), ((-2.0, 0.0), (2.0, 0.0)), Point'(0.0, 0.0), Point'(0.0, 0.0), "Intersection at one end of the vectors"); Assert_Intersection (((0.0, 0.0), (10.0, 0.0)), ((-2.0, 2.0), (2.0, 2.0)), No_Point, No_Point, "Parallel lines have no intersection"); Assert_Distance ((0.0, 0.0), ((-2.0, 2.0), (2.0, 2.0)), 2.0, 2.0, "Simple distance to line"); Assert_Distance ((0.0, 2.0), ((-2.0, 2.0), (2.0, 2.0)), 0.0, 0.0, "Distance when point on line"); Assert_Distance ((-3.0, 2.0), ((-2.0, 2.0), (2.0, 2.0)), 0.0, 1.0, "Distance when point on line, not on segment"); Assert_Distance ((-3.0, 0.0), ((-2.0, 2.0), (2.0, 2.0)), 2.0, Sqrt (5.0), "Distance when orthogonal projection not on segment"); Assert_Area (((0.0, 0.0), (4.0, 0.0), (0.0, 3.0)), 6.0, "Area of a counter-clockwise triangle"); Assert_Area (((0.0, 0.0), (0.0, 3.0), (4.0, 0.0)), 6.0, "Area of clockwise triangle"); Assert_Area (((0.0, 0.0), (0.0, 3.0), (2.0, 3.0), (2.0, 4.0), (3.0, 4.0), (3.0, 0.0)), 10.0, "Area for two squares (non-convex)"); Assert (To_Circle ((0.0, 0.0), (1.0, 0.0), (0.0, 1.0)), ((0.5, 0.5), Sqrt (0.5)), "Circle from point"); Assert_Inside_Triangle ((0.0, 0.0), ((0.0, 0.0), (0.0, 1.0), (1.0, 0.0)), True, "Point on boundary of triangle"); Assert_Inside_Triangle ((0.1, 0.1), ((0.0, 0.0), (0.0, 1.0), (1.0, 0.0)), True, "Point inside triangle"); Assert_Inside_Triangle ((0.5, 1.0), ((0.0, 0.0), (0.0, 1.0), (1.0, 0.0)), False, "Point outside triangle"); A.Assert (G.Inside ((2.5, 3.5), Poly => ((0.0, 0.0), (0.0, 3.0), (2.0, 3.0), (2.0, 4.0), (3.0, 4.0), (3.0, 0.0))), "Point inside non-convex polygon"); A.Assert (G.Inside ((2.0, 2.5), Poly => ((0.0, 0.0), (0.0, 3.0), (2.0, 3.0), (2.0, 4.0), (3.0, 4.0), (3.0, 0.0))), "Point inside non-convex polygon, vertically below vertex"); Assert_Same_Side ((0.0, 0.0), (4.0, 0.0), ((-2.0, 2.0), (2.0, 2.0)), True, "Same side of horizontal line"); Assert_Same_Side ((0.0, 0.0), (0.0, 4.0), ((-2.0, 2.0), (-2.0, -2.0)), True, "Same side of vertical line"); Assert_Same_Side ((0.0, 0.0), (4.0, 0.0), ((2.0, 2.0), (2.0, -2.0)), False, "Not same side of vertical line"); Assert (Centroid (((0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0))), (0.5, 0.5), "Centroid of rectangle"); Assert (Centroid (((0.0, 0.0), (1.0, 0.0), (0.0, 1.0))), (1.0 / 3.0, 1.0 / 3.0), "Centroid of triangle"); Assert_Intersect_Triangle (((0.0, 0.0), (1.0, 0.0), (0.0, 1.0)), ((0.5, 0.0), (1.5, 0.0), (0.5, 1.0)), True, "Intersection of two triangles"); Assert_Intersect_Triangle (((0.0, 0.0), (1.0, 0.0), (0.0, 1.0)), ((1.0, 0.0), (2.0, 0.0), (1.0, 1.0)), True, "Intersection with one common vertex"); Assert_Intersect_Triangle (((0.0, 0.0), (1.0, 0.0), (0.0, 1.0)), ((1.1, 0.0), (2.1, 0.0), (1.1, 1.0)), False, "No Intersection"); Assert_Intersect_Rectangle (((0.0, 0.0), (1.0, 1.0)), ((0.5, 0.0), (1.5, 2.0)), True, "Intersection of rectangles"); Assert_Intersect_Rectangle (((0.0, 0.0), (1.0, 1.0)), ((0.5, 1.0), (1.5, 2.0)), True, "Intersection of rectangles with common edge"); Assert_Intersect_Rectangle (((0.0, 0.0), (1.0, 1.0)), ((0.5, 1.1), (1.5, 2.0)), False, "No intersection of rectangles"); -- From the documentation of Boost geometry -- http://geometrylibrary.geodan.nl/ declare P1 : constant Point := (1.0, 1.0); P2 : constant Point := (2.0, 3.0); P3 : constant Point := (3.7, 2.0); P : constant Polygon := ((2.0, 1.3), (4.1, 3.0), (5.3, 2.6), (2.9, 0.7)); begin Assert (2.23607, Distance (P1, P2), "Distance P1-P2"); Assert (3.015, Area (P), "Area of polygon"); A.Assert (Inside (P3, P), "Point inside polygon"); Assert (1.04403, Distance (P1, P), "Distance point-polygon"); end; end Tests; begin declare subtype Coordinate is Float; procedure Float_Tests is new Tests (Coordinate); begin Float_Tests; end; -- Check we can instantiate with more restricted types declare type Coordinate is digits 1 range -500.0 .. 500.0; procedure Float_Tests is new Tests (Coordinate); begin Float_Tests; end; declare type Coordinate is digits 1 range -500.0 .. -200.0; package Geom is new GNATCOLL.Geometry (Coordinate); package Assertions is new Asserts (Coordinate, Geom); use Geom, Assertions; P1 : constant Point := (-401.0, -401.0); P2 : constant Point := (-402.0, -403.0); begin Assert (2.23607, Distance (P1, P2), "Distance P1-P2"); end; return A.Report; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/geometry/test.yaml000066400000000000000000000000501425465243200252020ustar00rootroot00000000000000description: Test for GNATCOLL.Geometry alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/000077500000000000000000000000001425465243200224625ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/integer_number/000077500000000000000000000000001425465243200254675ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/integer_number/test.adb000066400000000000000000000013511425465243200271160ustar00rootroot00000000000000with Ada.Text_IO; with GNATCOLL.JSON; with Test_Assert; function Test return Integer is package A renames Test_Assert; package JSON renames GNATCOLL.JSON; use type JSON.JSON_Value_Type; Content : constant String := "14"; begin declare Value : JSON.JSON_Value := JSON.Read (Strm => Content, Filename => ""); Result : Integer; Result2 : JSON.JSON_Value; begin A.Assert (True, "passed"); A.Assert (JSON.Kind (Value) = JSON.JSON_Int_Type, "check if type is JSON_Int_Type (got " & JSON.Kind (Value)'Img & ")"); Result := JSON.Get (Value); A.Assert (Result = 14, "check that result is equal to 14"); end; return A.Report; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/integer_number/test.yaml000066400000000000000000000001051425465243200273260ustar00rootroot00000000000000Description: Ensure that obvious integers are not converted to float alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/000077500000000000000000000000001425465243200241105ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_1_true_without_comma.json000066400000000000000000000000101425465243200326430ustar00rootroot00000000000000[1 true]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_a_invalid_utf8.json000066400000000000000000000000041425465243200314040ustar00rootroot00000000000000[aå]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_colon_instead_of_comma.json000066400000000000000000000000071425465243200331740ustar00rootroot00000000000000["": 1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_comma_after_close.json000066400000000000000000000000051425465243200321530ustar00rootroot00000000000000[""],alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_comma_and_number.json000066400000000000000000000000041425465243200317760ustar00rootroot00000000000000[,1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_double_comma.json000066400000000000000000000000061425465243200311400ustar00rootroot00000000000000[1,,2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_double_extra_comma.json000066400000000000000000000000071425465243200323440ustar00rootroot00000000000000["x",,]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_extra_close.json000066400000000000000000000000061425465243200310220ustar00rootroot00000000000000["x"]]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_extra_comma.json000066400000000000000000000000051425465243200310100ustar00rootroot00000000000000["",]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_incomplete.json000066400000000000000000000000041425465243200306470ustar00rootroot00000000000000["x"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_incomplete_invalid_value.json000066400000000000000000000000021425465243200335470ustar00rootroot00000000000000[xalire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_inner_array_no_comma.json000066400000000000000000000000061425465243200326730ustar00rootroot00000000000000[3[4]]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_invalid_utf8.json000066400000000000000000000000031425465243200311030ustar00rootroot00000000000000[ÿ]n_array_items_separated_by_semicolon.json000066400000000000000000000000051425465243200343450ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[1:2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_just_comma.json000066400000000000000000000000031425465243200306500ustar00rootroot00000000000000[,]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_just_minus.json000066400000000000000000000000031425465243200307070ustar00rootroot00000000000000[-]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_missing_value.json000066400000000000000000000000111425465243200313530ustar00rootroot00000000000000[ , ""]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_newlines_unclosed.json000066400000000000000000000000131425465243200322300ustar00rootroot00000000000000["a", 4 ,1,alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_number_and_comma.json000066400000000000000000000000041425465243200317760ustar00rootroot00000000000000[1,]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_number_and_several_commas.json000066400000000000000000000000051425465243200337030ustar00rootroot00000000000000[1,,]n_array_spaces_vertical_tab_formfeed.json000066400000000000000000000000101425465243200342720ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[" a"\f]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_star_inside.json000066400000000000000000000000031425465243200310130ustar00rootroot00000000000000[*]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_unclosed.json000066400000000000000000000000031425465243200303230ustar00rootroot00000000000000[""alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_unclosed_trailing_comma.json000066400000000000000000000000031425465243200333700ustar00rootroot00000000000000[1,alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_unclosed_with_new_lines.json000066400000000000000000000000101425465243200334170ustar00rootroot00000000000000[1, 1 ,1alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_array_unclosed_with_object_inside.json000066400000000000000000000000031425465243200342370ustar00rootroot00000000000000[{}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_incomplete_false.json000066400000000000000000000000061425465243200306250ustar00rootroot00000000000000[fals]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_incomplete_null.json000066400000000000000000000000051425465243200305040ustar00rootroot00000000000000[nul]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_incomplete_null_token.json000066400000000000000000000000021425465243200317010ustar00rootroot00000000000000nualire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_incomplete_true.json000066400000000000000000000000051425465243200305110ustar00rootroot00000000000000[tru]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_multidigit_number_then_00.json000066400000000000000000000000041425465243200323520ustar00rootroot00000000000000123alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_multiple_tokens.json000066400000000000000000000000111425465243200305260ustar00rootroot00000000000000truetrue alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_++.json000066400000000000000000000000101425465243200270640ustar00rootroot00000000000000[++1234]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_+1.json000066400000000000000000000000041425465243200270750ustar00rootroot00000000000000[+1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_+Inf.json000066400000000000000000000000061425465243200274530ustar00rootroot00000000000000[+Inf]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_-.json000066400000000000000000000000011425465243200270130ustar00rootroot00000000000000-alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_-01.json000066400000000000000000000000051425465243200271600ustar00rootroot00000000000000[-01]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_-1.0..json000066400000000000000000000000071425465243200273160ustar00rootroot00000000000000[-1.0.]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_-2..json000066400000000000000000000000051425465243200271570ustar00rootroot00000000000000[-2.]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_-NaN.json000066400000000000000000000000061425465243200274150ustar00rootroot00000000000000[-NaN]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_.-1.json000066400000000000000000000000051425465243200271560ustar00rootroot00000000000000[.-1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_.2e-3.json000066400000000000000000000000071425465243200274110ustar00rootroot00000000000000[.2e-3]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_0.1.2.json000066400000000000000000000000071425465243200273230ustar00rootroot00000000000000[0.1.2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_0.3e+.json000066400000000000000000000000071425465243200274050ustar00rootroot00000000000000[0.3e+]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_0.3e.json000066400000000000000000000000061425465243200273310ustar00rootroot00000000000000[0.3e]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_0.e1.json000066400000000000000000000000061425465243200273270ustar00rootroot00000000000000[0.e1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_0_capital_E+.json000066400000000000000000000000051425465243200310360ustar00rootroot00000000000000[0E+]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_0_capital_E.json000066400000000000000000000000041425465243200307620ustar00rootroot00000000000000[0E]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_0e+.json000066400000000000000000000000051425465243200272420ustar00rootroot00000000000000[0e+]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_0e.json000066400000000000000000000000041425465243200271660ustar00rootroot00000000000000[0e]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_1.0e+.json000066400000000000000000000000071425465243200274030ustar00rootroot00000000000000[1.0e+]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_1.0e-.json000066400000000000000000000000071425465243200274050ustar00rootroot00000000000000[1.0e-]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_1.0e.json000066400000000000000000000000061425465243200273270ustar00rootroot00000000000000[1.0e]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_1_000.json000066400000000000000000000000111425465243200273770ustar00rootroot00000000000000[1 000.0]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_1eE2.json000066400000000000000000000000061425465243200273600ustar00rootroot00000000000000[1eE2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_2.e+3.json000066400000000000000000000000071425465243200274070ustar00rootroot00000000000000[2.e+3]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_2.e-3.json000066400000000000000000000000071425465243200274110ustar00rootroot00000000000000[2.e-3]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_2.e3.json000066400000000000000000000000061425465243200273330ustar00rootroot00000000000000[2.e3]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_2E.json000066400000000000000000000000021425465243200271260ustar00rootroot000000000000002Ealire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_2e-.json000066400000000000000000000000031425465243200272440ustar00rootroot000000000000002e-alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_9.e+.json000066400000000000000000000000061425465243200273320ustar00rootroot00000000000000[9.e+]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_Inf.json000066400000000000000000000000051425465243200273770ustar00rootroot00000000000000[Inf]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_NaN.json000066400000000000000000000000051425465243200273370ustar00rootroot00000000000000[NaN]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_U+FF11_fullwidth_digit_one.json000066400000000000000000000000051425465243200336230ustar00rootroot00000000000000[1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_expression.json000066400000000000000000000000051425465243200310620ustar00rootroot00000000000000[1+2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_hex_1_digit.json000066400000000000000000000000051425465243200310470ustar00rootroot00000000000000[0x1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_hex_2_digits.json000066400000000000000000000000061425465243200312340ustar00rootroot00000000000000[0x42]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_infinity.json000066400000000000000000000000121425465243200305120ustar00rootroot00000000000000[Infinity]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_invalid+-.json000066400000000000000000000000071425465243200304430ustar00rootroot00000000000000[0e+-1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_invalid-negative-real.json000066400000000000000000000000151425465243200330330ustar00rootroot00000000000000[-123.123foo]n_number_invalid-utf-8-in-bigger-int.json000066400000000000000000000000061425465243200336250ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[123å]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_invalid-utf-8-in-exponent.json000066400000000000000000000000061425465243200335150ustar00rootroot00000000000000[1e1å]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_invalid-utf-8-in-int.json000066400000000000000000000000051425465243200324460ustar00rootroot00000000000000[0å] alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_minus_infinity.json000066400000000000000000000000131425465243200317260ustar00rootroot00000000000000[-Infinity]n_number_minus_sign_with_trailing_garbage.json000066400000000000000000000000061425465243200353540ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[-foo]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_minus_space_1.json000066400000000000000000000000051425465243200314110ustar00rootroot00000000000000[- 1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_neg_int_starting_with_zero.json000066400000000000000000000000061425465243200343140ustar00rootroot00000000000000[-012]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_neg_real_without_int_part.json000066400000000000000000000000071425465243200341240ustar00rootroot00000000000000[-.123]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_neg_with_garbage_at_end.json000066400000000000000000000000051425465243200334510ustar00rootroot00000000000000[-1x]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_real_garbage_after_e.json000066400000000000000000000000051425465243200327430ustar00rootroot00000000000000[1ea]n_number_real_with_invalid_utf8_after_e.json000066400000000000000000000000051425465243200347230ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[1eå]n_number_real_without_fractional_part.json000066400000000000000000000000041425465243200345410ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[1.]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_starting_with_dot.json000066400000000000000000000000061425465243200324200ustar00rootroot00000000000000[.123]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_with_alpha.json000066400000000000000000000000101425465243200307770ustar00rootroot00000000000000[1.2a-3]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_with_alpha_char.json000066400000000000000000000000311425465243200317770ustar00rootroot00000000000000[1.8011670033376514H-308]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_number_with_leading_zero.json000066400000000000000000000000051425465243200323600ustar00rootroot00000000000000[012]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_bad_value.json000066400000000000000000000000141425465243200305630ustar00rootroot00000000000000["x", truth]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_bracket_key.json000066400000000000000000000000111425465243200311210ustar00rootroot00000000000000{[: "x"} alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_comma_instead_of_colon.json000066400000000000000000000000131425465243200333210ustar00rootroot00000000000000{"x", null}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_double_colon.json000066400000000000000000000000121425465243200313030ustar00rootroot00000000000000{"x"::"b"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_emoji.json000066400000000000000000000000121425465243200277420ustar00rootroot00000000000000{🇨🇭}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_garbage_at_end.json000066400000000000000000000000151425465243200315440ustar00rootroot00000000000000{"a":"a" 123}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_key_with_single_quotes.json000066400000000000000000000000161425465243200334270ustar00rootroot00000000000000{key: 'value'}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_missing_colon.json000066400000000000000000000000071425465243200315060ustar00rootroot00000000000000{"a" b}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_missing_key.json000066400000000000000000000000061425465243200311630ustar00rootroot00000000000000{:"b"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_missing_semicolon.json000066400000000000000000000000111425465243200323570ustar00rootroot00000000000000{"a" "b"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_missing_value.json000066400000000000000000000000051425465243200315060ustar00rootroot00000000000000{"a":alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_no-colon.json000066400000000000000000000000041425465243200303640ustar00rootroot00000000000000{"a"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_non_string_key.json000066400000000000000000000000051425465243200316710ustar00rootroot00000000000000{1:1}n_object_non_string_key_but_huge_number_instead.json000066400000000000000000000000151425465243200365540ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{9999E9999:1}n_object_pi_in_key_and_trailing_comma.json000066400000000000000000000000121425465243200344150ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{"¹":"0",}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_repeated_null_null.json000066400000000000000000000000251425465243200325200ustar00rootroot00000000000000{null:null,null:null}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_several_trailing_commas.json000066400000000000000000000000151425465243200335330ustar00rootroot00000000000000{"id":0,,,,,}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_single_quote.json000066400000000000000000000000071425465243200313410ustar00rootroot00000000000000{'a':0}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_trailing_comma.json000066400000000000000000000000111425465243200316230ustar00rootroot00000000000000{"id":0,}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_trailing_comment.json000066400000000000000000000000151425465243200321750ustar00rootroot00000000000000{"a":"b"}/**/alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_trailing_comment_open.json000066400000000000000000000000161425465243200332170ustar00rootroot00000000000000{"a":"b"}/**//n_object_trailing_comment_slash_open.json000066400000000000000000000000131425465243200343270ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{"a":"b"}//n_object_trailing_comment_slash_open_incomplete.json000066400000000000000000000000121425465243200365450ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{"a":"b"}/alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_two_commas_in_a_row.json000066400000000000000000000000221425465243200326650ustar00rootroot00000000000000{"a":"b",,"c":"d"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_unquoted_key.json000066400000000000000000000000101425465243200313510ustar00rootroot00000000000000{a: "b"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_unterminated-value.json000066400000000000000000000000071425465243200324540ustar00rootroot00000000000000{"a":"aalire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_with_single_string.json000066400000000000000000000000261425465243200325460ustar00rootroot00000000000000{ "foo" : "bar", "a" }alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_object_with_trailing_garbage.json000066400000000000000000000000121425465243200331530ustar00rootroot00000000000000{"a":"b"}#alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_single_space.json000066400000000000000000000000011425465243200277430ustar00rootroot00000000000000 alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_1_surrogate_then_escape.json000066400000000000000000000000131425465243200334710ustar00rootroot00000000000000["\uD800\"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_1_surrogate_then_escape_u.json000066400000000000000000000000141425465243200340160ustar00rootroot00000000000000["\uD800\u"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_1_surrogate_then_escape_u1.json000066400000000000000000000000151425465243200341000ustar00rootroot00000000000000["\uD800\u1"]n_string_1_surrogate_then_escape_u1x.json000066400000000000000000000000161425465243200342120ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid["\uD800\u1x"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_accentuated_char_no_quotes.json000066400000000000000000000000041425465243200342510ustar00rootroot00000000000000[é]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_backslash_00.json000066400000000000000000000000061425465243200311340ustar00rootroot00000000000000["\"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_escape_x.json000066400000000000000000000000101425465243200304640ustar00rootroot00000000000000["\x00"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_escaped_backslash_bad.json000066400000000000000000000000071425465243200331300ustar00rootroot00000000000000["\\\"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_escaped_ctrl_char_tab.json000066400000000000000000000000061425465243200331550ustar00rootroot00000000000000["\ "]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_escaped_emoji.json000066400000000000000000000000111425465243200314650ustar00rootroot00000000000000["\🌀"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_incomplete_escape.json000066400000000000000000000000051425465243200323600ustar00rootroot00000000000000["\"]n_string_incomplete_escaped_character.json000066400000000000000000000000111425465243200344560ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid["\u00A"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_incomplete_surrogate.json000066400000000000000000000000161425465243200331350ustar00rootroot00000000000000["\uD834\uDd"]n_string_incomplete_surrogate_escape_invalid.json000066400000000000000000000000221425465243200361010ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid["\uD800\uD800\x"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_invalid-utf-8-in-escape.json000066400000000000000000000000071425465243200331340ustar00rootroot00000000000000["\uå"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_invalid_backslash_esc.json000066400000000000000000000000061425465243200331750ustar00rootroot00000000000000["\a"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_invalid_unicode_escape.json000066400000000000000000000000121425465243200333530ustar00rootroot00000000000000["\uqqqq"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_invalid_utf8_after_escape.json000066400000000000000000000000061425465243200337770ustar00rootroot00000000000000["\å"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_leading_uescaped_thinspace.json000066400000000000000000000000151425465243200342140ustar00rootroot00000000000000[\u0020"asd"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_no_quotes_with_bad_escape.json000066400000000000000000000000041425465243200340750ustar00rootroot00000000000000[\n]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_single_doublequote.json000066400000000000000000000000011425465243200325660ustar00rootroot00000000000000"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_single_quote.json000066400000000000000000000000201425465243200313740ustar00rootroot00000000000000['single quote']n_string_single_string_no_double_quotes.json000066400000000000000000000000031425465243200351150ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalidabcalire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_start_escape_unclosed.json000066400000000000000000000000031425465243200332500ustar00rootroot00000000000000["\alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_unescaped_crtl_char.json000066400000000000000000000000071425465243200326730ustar00rootroot00000000000000["aa"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_unescaped_newline.json000066400000000000000000000000141425465243200323710ustar00rootroot00000000000000["new line"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_unescaped_tab.json000066400000000000000000000000051425465243200314760ustar00rootroot00000000000000[" "]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_unicode_CapitalU.json000066400000000000000000000000101425465243200321050ustar00rootroot00000000000000"\UA66D"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_string_with_trailing_garbage.json000066400000000000000000000000031425465243200332130ustar00rootroot00000000000000""xalire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_100000_opening_arrays.json000066400000000000000000003032401425465243200332620ustar00rootroot00000000000000[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_U+2060_word_joined.json000066400000000000000000000000051425465243200326050ustar00rootroot00000000000000[â ]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_UTF8_BOM_no_data.json000066400000000000000000000000031425465243200323410ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_angle_bracket_..json000066400000000000000000000000031425465243200324270ustar00rootroot00000000000000<.>alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_angle_bracket_null.json000066400000000000000000000000101425465243200332420ustar00rootroot00000000000000[]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_array_trailing_garbage.json000066400000000000000000000000041425465243200341110ustar00rootroot00000000000000[1]xn_structure_array_with_extra_array_close.json000066400000000000000000000000041425465243200353120ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[1]]n_structure_array_with_unclosed_string.json000066400000000000000000000000061425465243200350100ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid["asd]n_structure_ascii-unicode-identifier.json000066400000000000000000000000031425465243200342060ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalidaÃ¥alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_capitalized_True.json000066400000000000000000000000061425465243200327240ustar00rootroot00000000000000[True]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_close_unopened_array.json000066400000000000000000000000021425465243200336300ustar00rootroot000000000000001]n_structure_comma_instead_of_closing_brace.json000066400000000000000000000000131425465243200355140ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{"x": true,alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_double_array.json000066400000000000000000000000041425465243200321020ustar00rootroot00000000000000[][]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_end_array.json000066400000000000000000000000011425465243200313730ustar00rootroot00000000000000]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_incomplete_UTF8_BOM.json000066400000000000000000000000041425465243200330740ustar00rootroot00000000000000ï»{}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_lone-invalid-utf-8.json000066400000000000000000000000011425465243200327510ustar00rootroot00000000000000åalire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_lone-open-bracket.json000066400000000000000000000000011425465243200327340ustar00rootroot00000000000000[alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_no_data.json000066400000000000000000000000001425465243200310330ustar00rootroot00000000000000n_structure_null-byte-outside-string.json000066400000000000000000000000031425465243200342430ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[]n_structure_number_with_trailing_garbage.json000066400000000000000000000000021425465243200352350ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid2@n_structure_object_followed_by_closing_object.json000066400000000000000000000000031425465243200362510ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{}}n_structure_object_unclosed_no_value.json000066400000000000000000000000041425465243200344050ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{"":alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_object_with_comment.json000066400000000000000000000000241425465243200334570ustar00rootroot00000000000000{"a":/*comment*/"b"}n_structure_object_with_trailing_garbage.json000066400000000000000000000000171425465243200352210ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{"a": true} "x"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_array_apostrophe.json000066400000000000000000000000021425465243200340330ustar00rootroot00000000000000['alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_array_comma.json000066400000000000000000000000021425465243200327430ustar00rootroot00000000000000[,alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_array_object.json000066400000000000000000007502211425465243200331340ustar00rootroot00000000000000[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"": alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_array_open_object.json000066400000000000000000000000021425465243200341360ustar00rootroot00000000000000[{alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_array_open_string.json000066400000000000000000000000031425465243200341770ustar00rootroot00000000000000["aalire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_array_string.json000066400000000000000000000000041425465243200331570ustar00rootroot00000000000000["a"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_object.json000066400000000000000000000000011425465243200317160ustar00rootroot00000000000000{alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_object_close_array.json000066400000000000000000000000021425465243200343020ustar00rootroot00000000000000{]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_object_comma.json000066400000000000000000000000021425465243200330730ustar00rootroot00000000000000{,alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_object_open_array.json000066400000000000000000000000021425465243200341360ustar00rootroot00000000000000{[alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_object_open_string.json000066400000000000000000000000031425465243200343270ustar00rootroot00000000000000{"an_structure_open_object_string_with_apostrophes.json000066400000000000000000000000041425465243200367120ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid{'a'alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_open_open.json000066400000000000000000000000201425465243200314120ustar00rootroot00000000000000["\{["\{["\{["\{alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_single_eacute.json000066400000000000000000000000011425465243200322360ustar00rootroot00000000000000éalire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_single_star.json000066400000000000000000000000011425465243200317410ustar00rootroot00000000000000*alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_trailing_#.json000066400000000000000000000000141425465243200314460ustar00rootroot00000000000000{"a":"b"}#{}n_structure_uescaped_LF_before_string.json000066400000000000000000000000121425465243200344340ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[\u000A""]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_unclosed_array.json000066400000000000000000000000021425465243200324420ustar00rootroot00000000000000[1n_structure_unclosed_array_partial_null.json000066400000000000000000000000141425465243200351340ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[ false, nuln_structure_unclosed_array_unfinished_false.json000066400000000000000000000000141425465243200357540ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[ true, falsn_structure_unclosed_array_unfinished_true.json000066400000000000000000000000141425465243200356410ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[ false, trualire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_unclosed_object.json000066400000000000000000000000141425465243200325750ustar00rootroot00000000000000{"asd":"asd"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_unicode-identifier.json000066400000000000000000000000021425465243200331760ustar00rootroot00000000000000Ã¥n_structure_whitespace_U+2060_word_joiner.json000066400000000000000000000000051425465243200347600ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid[â ]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/n_structure_whitespace_formfeed.json000066400000000000000000000000031425465243200334340ustar00rootroot00000000000000[ ]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/test.adb000066400000000000000000000017711425465243200255450ustar00rootroot00000000000000with Test_Assert; with GNATCOLL.JSON; with GNATCOLL.VFS; with GNAT.Strings; with Ada.Command_Line; with Ada.Exceptions; function Test return Integer is package A renames Test_Assert; package JSON renames GNATCOLL.JSON; package VFS renames GNATCOLL.VFS; procedure Test (JSON_String : String); procedure Test (JSON_String : String) is begin declare V : JSON.JSON_Value; begin V := JSON.Read(JSON_String); A.Assert (False, "invalid json (exception not raised)"); exception when JSON.Invalid_JSON_Stream => A.Assert (True, "failed with Invalid_JSON_Stream"); when E : others => A.Assert (False, "invalid json: (wrong exception)" & ASCII.LF & Ada.Exceptions.Exception_Information (E)); end; end Test; File_Content : GNAT.Strings.String_Access := VFS.Read_File (VFS.Create(VFS."+"(Ada.Command_Line.Argument (1)))); begin Test (File_Content.all); return A.Report; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/invalid/test.yaml000066400000000000000000000314551425465243200257630ustar00rootroot00000000000000description: Check behavior of JSON parser on invalid JSON driver: data_validation data_files: "n_array_1_true_without_comma.json": "n array 1 true without comma" "n_array_a_invalid_utf8.json": "n array a invalid utf8" "n_array_colon_instead_of_comma.json": "n array colon instead of comma" "n_array_comma_after_close.json": "n array comma after close" "n_array_comma_and_number.json": "n array comma and number" "n_array_double_comma.json": "n array double comma" "n_array_double_extra_comma.json": "n array double extra comma" "n_array_extra_close.json": "n array extra close" "n_array_extra_comma.json": "n array extra comma" "n_array_incomplete.json": "n array incomplete" "n_array_incomplete_invalid_value.json": "n array incomplete invalid value" "n_array_inner_array_no_comma.json": "n array inner array no comma" "n_array_invalid_utf8.json": "n array invalid utf8" "n_array_items_separated_by_semicolon.json": "n array items separated by semicolon" "n_array_just_comma.json": "n array just comma" "n_array_just_minus.json": "n array just minus" "n_array_missing_value.json": "n array missing value" "n_array_newlines_unclosed.json": "n array newlines unclosed" "n_array_number_and_comma.json": "n array number and comma" "n_array_number_and_several_commas.json": "n array number and several commas" "n_array_spaces_vertical_tab_formfeed.json": "n array spaces vertical tab formfeed" "n_array_star_inside.json": "n array star inside" "n_array_unclosed.json": "n array unclosed" "n_array_unclosed_trailing_comma.json": "n array unclosed trailing comma" "n_array_unclosed_with_new_lines.json": "n array unclosed with new lines" "n_array_unclosed_with_object_inside.json": "n array unclosed with object inside" "n_incomplete_false.json": "n incomplete false" "n_incomplete_null.json": "n incomplete null" "n_incomplete_true.json": "n incomplete true" "n_multidigit_number_then_00.json": "n multidigit number then 00" "n_number_++.json": "n number ++" "n_number_-.json": "n number -" "n_number_2E.json": "n number 2E" "n_number_2e-.json": "n number 2e-" "n_number_+1.json": "n number +1" "n_number_+Inf.json": "n number +Inf" "n_number_-01.json": "n number -01" "n_number_-1.0..json": "n number -1.0." "n_number_-2..json": "n number -2." "n_number_-NaN.json": "n number -NaN" "n_number_.-1.json": "n number .-1" "n_number_.2e-3.json": "n number .2e-3" "n_number_0.1.2.json": "n number 0.1.2" "n_number_0.3e+.json": "n number 0.3e+" "n_number_0.3e.json": "n number 0.3e" "n_number_0.e1.json": "n number 0.e1" "n_number_0_capital_E+.json": "n number 0 capital E+" "n_number_0_capital_E.json": "n number 0 capital E" "n_number_0e+.json": "n number 0e+" "n_number_0e.json": "n number 0e" "n_number_1.0e+.json": "n number 1.0e+" "n_number_1.0e-.json": "n number 1.0e-" "n_number_1.0e.json": "n number 1.0e" "n_number_1_000.json": "n number 1 000" "n_number_1eE2.json": "n number 1eE2" "n_number_2.e+3.json": "n number 2.e+3" "n_number_2.e-3.json": "n number 2.e-3" "n_number_2.e3.json": "n number 2.e3" "n_number_9.e+.json": "n number 9.e+" "n_number_Inf.json": "n number Inf" "n_number_NaN.json": "n number NaN" "n_number_U+FF11_fullwidth_digit_one.json": "n number U+FF11 fullwidth digit one" "n_number_expression.json": "n number expression" "n_number_hex_1_digit.json": "n number hex 1 digit" "n_number_hex_2_digits.json": "n number hex 2 digits" "n_number_infinity.json": "n number infinity" "n_number_invalid+-.json": "n number invalid+-" "n_number_invalid-negative-real.json": "n number invalid-negative-real" "n_number_invalid-utf-8-in-bigger-int.json": "n number invalid-utf-8-in-bigger-int" "n_number_invalid-utf-8-in-exponent.json": "n number invalid-utf-8-in-exponent" "n_number_invalid-utf-8-in-int.json": "n number invalid-utf-8-in-int" "n_number_minus_infinity.json": "n number minus infinity" "n_number_minus_sign_with_trailing_garbage.json": "n number minus sign with trailing garbage" "n_number_minus_space_1.json": "n number minus space 1" "n_number_neg_int_starting_with_zero.json": "n number neg int starting with zero" "n_number_neg_real_without_int_part.json": "n number neg real without int part" "n_number_neg_with_garbage_at_end.json": "n number neg with garbage at end" "n_number_real_garbage_after_e.json": "n number real garbage after e" "n_number_real_with_invalid_utf8_after_e.json": "n number real with invalid utf8 after e" "n_number_real_without_fractional_part.json": "n number real without fractional part" "n_number_starting_with_dot.json": "n number starting with dot" "n_number_with_alpha.json": "n number with alpha" "n_number_with_alpha_char.json": "n number with alpha char" "n_number_with_leading_zero.json": "n number with leading zero" "n_object_bad_value.json": "n object bad value" "n_object_bracket_key.json": "n object bracket key" "n_object_comma_instead_of_colon.json": "n object comma instead of colon" "n_object_double_colon.json": "n object double colon" "n_object_emoji.json": "n object emoji" "n_object_garbage_at_end.json": "n object garbage at end" "n_object_key_with_single_quotes.json": "n object key with single quotes" "n_object_missing_colon.json": "n object missing colon" "n_object_missing_key.json": "n object missing key" "n_object_missing_semicolon.json": "n object missing semicolon" "n_object_missing_value.json": "n object missing value" "n_object_no-colon.json": "n object no-colon" "n_object_non_string_key.json": "n object non string key" "n_object_non_string_key_but_huge_number_instead.json": "n object non string key but huge number instead" "n_object_pi_in_key_and_trailing_comma.json": "n object pi in key and trailing comma" "n_object_repeated_null_null.json": "n object repeated null null" "n_object_several_trailing_commas.json": "n object several trailing commas" "n_object_single_quote.json": "n object single quote" "n_object_trailing_comma.json": "n object trailing comma" "n_object_trailing_comment.json": "n object trailing comment" "n_object_trailing_comment_open.json": "n object trailing comment open" "n_object_trailing_comment_slash_open.json": "n object trailing comment slash open" "n_object_trailing_comment_slash_open_incomplete.json": "n object trailing comment slash open incomplete" "n_object_two_commas_in_a_row.json": "n object two commas in a row" "n_object_unquoted_key.json": "n object unquoted key" "n_object_unterminated-value.json": "n object unterminated-value" "n_object_with_single_string.json": "n object with single string" "n_object_with_trailing_garbage.json": "n object with trailing garbage" "n_single_space.json": "n single space" "n_string_1_surrogate_then_escape.json": "n string 1 surrogate then escape" "n_string_1_surrogate_then_escape_u.json": "n string 1 surrogate then escape u" "n_string_1_surrogate_then_escape_u1.json": "n string 1 surrogate then escape u1" "n_string_1_surrogate_then_escape_u1x.json": "n string 1 surrogate then escape u1x" "n_string_accentuated_char_no_quotes.json": "n string accentuated char no quotes" "n_string_backslash_00.json": "n string backslash 00" "n_string_escape_x.json": "n string escape x" "n_string_escaped_backslash_bad.json": "n string escaped backslash bad" "n_string_escaped_ctrl_char_tab.json": "n string escaped ctrl char tab" "n_string_escaped_emoji.json": "n string escaped emoji" "n_string_incomplete_escape.json": "n string incomplete escape" "n_string_incomplete_escaped_character.json": "n string incomplete escaped character" "n_string_incomplete_surrogate.json": "n string incomplete surrogate" "n_string_incomplete_surrogate_escape_invalid.json": "n string incomplete surrogate escape invalid" "n_string_invalid-utf-8-in-escape.json": "n string invalid-utf-8-in-escape" "n_string_invalid_backslash_esc.json": "n string invalid backslash esc" "n_string_invalid_unicode_escape.json": "n string invalid unicode escape" "n_string_invalid_utf8_after_escape.json": "n string invalid utf8 after escape" "n_string_leading_uescaped_thinspace.json": "n string leading uescaped thinspace" "n_string_no_quotes_with_bad_escape.json": "n string no quotes with bad escape" "n_string_single_doublequote.json": "n string single doublequote" "n_string_single_quote.json": "n string single quote" "n_string_single_string_no_double_quotes.json": "n string single string no double quotes" "n_string_start_escape_unclosed.json": "n string start escape unclosed" "n_string_unescaped_crtl_char.json": "n string unescaped crtl char" "n_string_unescaped_newline.json": "n string unescaped newline" "n_string_unescaped_tab.json": "n string unescaped tab" "n_string_unicode_CapitalU.json": "n string unicode CapitalU" "n_string_with_trailing_garbage.json": "n string with trailing garbage" "n_structure_U+2060_word_joined.json": "n structure U+2060 word joined" "n_structure_UTF8_BOM_no_data.json": "n structure UTF8 BOM no data" "n_structure_angle_bracket_..json": "n structure angle bracket ." "n_structure_angle_bracket_null.json": "n structure angle bracket null" "n_structure_array_trailing_garbage.json": "n structure array trailing garbage" "n_structure_array_with_extra_array_close.json": "n structure array with extra array close" "n_structure_array_with_unclosed_string.json": "n structure array with unclosed string" "n_structure_ascii-unicode-identifier.json": "n structure ascii-unicode-identifier" "n_structure_capitalized_True.json": "n structure capitalized True" "n_structure_close_unopened_array.json": "n structure close unopened array" "n_structure_comma_instead_of_closing_brace.json": "n structure comma instead of closing brace" "n_structure_double_array.json": "n structure double array" "n_structure_end_array.json": "n structure end array" "n_structure_incomplete_UTF8_BOM.json": "n structure incomplete UTF8 BOM" "n_structure_lone-invalid-utf-8.json": "n structure lone-invalid-utf-8" "n_structure_lone-open-bracket.json": "n structure lone-open-bracket" "n_structure_no_data.json": "n structure no data" "n_structure_null-byte-outside-string.json": "n structure null-byte-outside-string" "n_structure_number_with_trailing_garbage.json": "n structure number with trailing garbage" "n_structure_object_followed_by_closing_object.json": "n structure object followed by closing object" "n_structure_object_unclosed_no_value.json": "n structure object unclosed no value" "n_structure_object_with_comment.json": "n structure object with comment" "n_structure_object_with_trailing_garbage.json": "n structure object with trailing garbage" "n_structure_open_array_apostrophe.json": "n structure open array apostrophe" "n_structure_open_array_comma.json": "n structure open array comma" "n_structure_open_array_open_object.json": "n structure open array open object" "n_structure_open_array_open_string.json": "n structure open array open string" "n_structure_open_array_string.json": "n structure open array string" "n_structure_open_object.json": "n structure open object" "n_structure_open_object_close_array.json": "n structure open object close array" "n_structure_open_object_comma.json": "n structure open object comma" "n_structure_open_object_open_array.json": "n structure open object open array" "n_structure_open_object_open_string.json": "n structure open object open string" "n_structure_open_object_string_with_apostrophes.json": "n structure open object string with apostrophes" "n_structure_open_open.json": "n structure open open" "n_structure_single_eacute.json": "n structure single eacute" "n_structure_single_star.json": "n structure single star" "n_structure_trailing_#.json": "n structure trailing #" "n_structure_uescaped_LF_before_string.json": "n structure uescaped LF before string" "n_structure_unclosed_array.json": "n structure unclosed array" "n_structure_unclosed_array_partial_null.json": "n structure unclosed array partial null" "n_structure_unclosed_array_unfinished_false.json": "n structure unclosed array unfinished false" "n_structure_unclosed_array_unfinished_true.json": "n structure unclosed array unfinished true" "n_structure_unclosed_object.json": "n structure unclosed object" "n_structure_unicode-identifier.json": "n structure unicode-identifier" "n_structure_whitespace_U+2060_word_joiner.json": "n structure whitespace U+2060 word joiner" "n_structure_whitespace_formfeed.json": "n structure whitespace formfeed" "n_multiple_tokens.json": "concatenated tokens" "n_incomplete_null_token.json": "incomplete null token" alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/000077500000000000000000000000001425465243200246145ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/basic_object.json000066400000000000000000000001121425465243200301100ustar00rootroot00000000000000{"a": 1, "b": "a tringg", "c": [1, 2, 3], "d": {"a": "a"}, "e": null} alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/false.json000066400000000000000000000000061425465243200265750ustar00rootroot00000000000000false alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/keyword_seq.json000066400000000000000000000000241425465243200300370ustar00rootroot00000000000000[true, false, null] alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/null.json000066400000000000000000000000051425465243200264540ustar00rootroot00000000000000null alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/numbers.json000066400000000000000000000001121425465243200271540ustar00rootroot00000000000000[0, 12345643, 1E+2, 1e-2, -41, -0, 1.000, 1E4, 1e21, 0.6E4, -6] alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/string.json000066400000000000000000000000161425465243200270120ustar00rootroot00000000000000"Hello\n\r\t" alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/test.adb000066400000000000000000000026521425465243200262500ustar00rootroot00000000000000with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Command_Line; with Ada.Text_IO; with GNATCOLL.JSON; with GNAT.OS_Lib; procedure Test is package JSON renames GNATCOLL.JSON; package IO renames Ada.Text_IO; function Read_File (Filename : String) return Unbounded_String is use GNAT.OS_Lib; F : constant File_Descriptor := Open_Read (Filename, Binary); Expected_Bytes_Read : Integer; Bytes_Read : Integer; begin Expected_Bytes_Read := Integer (File_Length (F)); declare Buffer_Str : aliased String (1 .. Expected_Bytes_Read); begin Bytes_Read := Read (F, Buffer_Str'Address, Expected_Bytes_Read); Close (F); return To_Unbounded_String (Buffer_Str); end; end Read_File; -- Read json filename passed as first argument Filename : constant String := Ada.Command_Line.Argument(1); JSON_Data : Unbounded_String := Read_File (Filename); begin -- Parse the json declare Value : JSON.JSON_Value := JSON.Read (Strm => JSON_Data, Filename => Filename); begin -- Dump JSON back to stdout for validation by the python json -- parser declare New_JSON_Data : constant Unbounded_String := JSON.Write (Item => Value, Compact => False); begin Ada.Text_IO.Put_Line(To_String(New_JSON_Data)); end; end; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/test.yaml000066400000000000000000000146701425465243200264670ustar00rootroot00000000000000driver: 'json_validation' data_files: test1.json: "Minimal test" test2.json: "Minimal test2" false.json: "null keyword" null.json: "false keyword" true.json: "true keyword" keyword_seq.json: "an array of null, false and true" basic_object.json: "a basic JSON object" string.json: "a string with some escape sequences" numbers.json: "an array of various kind of numbers" "y_array_arraysWithSpaces.json": "y array arraysWithSpaces" "y_array_empty-string.json": "y array empty-string" "y_array_empty.json": "y array empty" "y_array_ending_with_newline.json": "y array ending with newline" "y_array_false.json": "y array false" "y_array_heterogeneous.json": "y array heterogeneous" "y_array_null.json": "y array null" "y_array_with_1_and_newline.json": "y array with 1 and newline" "y_array_with_leading_space.json": "y array with leading space" "y_array_with_several_null.json": "y array with several null" "y_array_with_trailing_space.json": "y array with trailing space" "y_number.json": "y number" "y_number_0e+1.json": "y number 0e+1" "y_number_0e1.json": "y number 0e1" "y_number_after_space.json": "y number after space" "y_number_double_close_to_zero.json": "y number double close to zero" "y_number_int_with_exp.json": "y number int with exp" "y_number_minus_zero.json": "y number minus zero" "y_number_negative_int.json": "y number negative int" "y_number_negative_one.json": "y number negative one" "y_number_negative_zero.json": "y number negative zero" "y_number_real_capital_e.json": "y number real capital e" "y_number_real_capital_e_neg_exp.json": "y number real capital e neg exp" "y_number_real_capital_e_pos_exp.json": "y number real capital e pos exp" "y_number_real_exponent.json": "y number real exponent" "y_number_real_fraction_exponent.json": "y number real fraction exponent" "y_number_real_neg_exp.json": "y number real neg exp" "y_number_real_pos_exponent.json": "y number real pos exponent" "y_number_simple_int.json": "y number simple int" "y_number_simple_real.json": "y number simple real" "y_object.json": "y object" "y_object_basic.json": "y object basic" "y_object_duplicated_key.json": "y object duplicated key" "y_object_duplicated_key_and_value.json": "y object duplicated key and value" "y_object_empty.json": "y object empty" "y_object_empty_key.json": "y object empty key" "y_object_escaped_null_in_key.json": "y object escaped null in key" "y_object_extreme_numbers.json": "y object extreme numbers" "y_object_long_strings.json": "y object long strings" "y_object_simple.json": "y object simple" "y_object_string_unicode.json": "y object string unicode" "y_object_with_newlines.json": "y object with newlines" "y_string_1_2_3_bytes_UTF-8_sequences.json": "y string 1 2 3 bytes UTF-8 sequences" "y_string_accepted_surrogate_pair.json": "y string accepted surrogate pair" "y_string_accepted_surrogate_pairs.json": "y string accepted surrogate pairs" "y_string_allowed_escapes.json": "y string allowed escapes" "y_string_backslash_and_u_escaped_zero.json": "y string backslash and u escaped zero" "y_string_backslash_doublequotes.json": "y string backslash doublequotes" "y_string_comments.json": "y string comments" "y_string_double_escape_a.json": "y string double escape a" "y_string_double_escape_n.json": "y string double escape n" "y_string_escaped_control_character.json": "y string escaped control character" "y_string_escaped_noncharacter.json": "y string escaped noncharacter" "y_string_in_array.json": "y string in array" "y_string_in_array_with_leading_space.json": "y string in array with leading space" "y_string_last_surrogates_1_and_2.json": "y string last surrogates 1 and 2" "y_string_nbsp_uescaped.json": "y string nbsp uescaped" "y_string_nonCharacterInUTF-8_U+10FFFF.json": "y string nonCharacterInUTF-8 U+10FFFF" "y_string_nonCharacterInUTF-8_U+1FFFF.json": "y string nonCharacterInUTF-8 U+1FFFF" "y_string_nonCharacterInUTF-8_U+FFFF.json": "y string nonCharacterInUTF-8 U+FFFF" "y_string_null_escape.json": "y string null escape" "y_string_one-byte-utf-8.json": "y string one-byte-utf-8" "y_string_pi.json": "y string pi" "y_string_simple_ascii.json": "y string simple ascii" "y_string_space.json": "y string space" "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json": "y string surrogates U+1D11E MUSICAL SYMBOL G CLEF" "y_string_three-byte-utf-8.json": "y string three-byte-utf-8" "y_string_two-byte-utf-8.json": "y string two-byte-utf-8" "y_string_u+2028_line_sep.json": "y string u+2028 line sep" "y_string_u+2029_par_sep.json": "y string u+2029 par sep" "y_string_uEscape.json": "y string uEscape" "y_string_uescaped_newline.json": "y string uescaped newline" "y_string_unescaped_char_delete.json": "y string unescaped char delete" "y_string_unicode.json": "y string unicode" "y_string_unicodeEscapedBackslash.json": "y string unicodeEscapedBackslash" "y_string_unicode_2.json": "y string unicode 2" "y_string_unicode_U+10FFFE_nonchar.json": "y string unicode U+10FFFE nonchar" "y_string_unicode_U+1FFFE_nonchar.json": "y string unicode U+1FFFE nonchar" "y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json": "y string unicode U+200B ZERO WIDTH SPACE" "y_string_unicode_U+2064_invisible_plus.json": "y string unicode U+2064 invisible plus" "y_string_unicode_U+FDD0_nonchar.json": "y string unicode U+FDD0 nonchar" "y_string_unicode_U+FFFE_nonchar.json": "y string unicode U+FFFE nonchar" "y_string_unicode_escaped_double_quote.json": "y string unicode escaped double quote" "y_string_utf8.json": "y string utf8" "y_string_with_del_character.json": "y string with del character" "y_structure_lonely_false.json": "y structure lonely false" "y_structure_lonely_int.json": "y structure lonely int" "y_structure_lonely_negative_real.json": "y structure lonely negative real" "y_structure_lonely_null.json": "y structure lonely null" "y_structure_lonely_string.json": "y structure lonely string" "y_structure_lonely_true.json": "y structure lonely true" "y_structure_string_empty.json": "y structure string empty" "y_structure_trailing_newline.json": "y structure trailing newline" "y_structure_true_in_array.json": "y structure true in array" "y_structure_whitespace_array.json": "y structure whitespace array" alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/test1.json000066400000000000000000000000041425465243200265410ustar00rootroot00000000000000{ } alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/test2.json000066400000000000000000000000031425465243200265410ustar00rootroot00000000000000[] alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/true.json000066400000000000000000000000051425465243200264610ustar00rootroot00000000000000true alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_arraysWithSpaces.json000066400000000000000000000000071425465243200325260ustar00rootroot00000000000000[[] ]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_empty-string.json000066400000000000000000000000041425465243200316710ustar00rootroot00000000000000[""]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_empty.json000066400000000000000000000000021425465243200303630ustar00rootroot00000000000000[]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_ending_with_newline.json000066400000000000000000000000051425465243200332500ustar00rootroot00000000000000["a"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_false.json000066400000000000000000000000071425465243200303240ustar00rootroot00000000000000[false]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_heterogeneous.json000066400000000000000000000000221425465243200321030ustar00rootroot00000000000000[null, 1, "1", {}]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_null.json000066400000000000000000000000061425465243200302030ustar00rootroot00000000000000[null]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_with_1_and_newline.json000066400000000000000000000000041425465243200327650ustar00rootroot00000000000000[1 ]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_with_leading_space.json000066400000000000000000000000041425465243200330400ustar00rootroot00000000000000 [1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_with_several_null.json000066400000000000000000000000241425465243200327570ustar00rootroot00000000000000[1,null,null,null,2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_array_with_trailing_space.json000066400000000000000000000000041425465243200332460ustar00rootroot00000000000000[2] alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number.json000066400000000000000000000000101425465243200273160ustar00rootroot00000000000000[123e65]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_0e+1.json000066400000000000000000000000061425465243200300430ustar00rootroot00000000000000[0e+1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_0e1.json000066400000000000000000000000051425465243200277670ustar00rootroot00000000000000[0e1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_after_space.json000066400000000000000000000000041425465243200316550ustar00rootroot00000000000000[ 4]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_double_close_to_zero.json000066400000000000000000000001241425465243200336040ustar00rootroot00000000000000[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_int_with_exp.json000066400000000000000000000000061425465243200321040ustar00rootroot00000000000000[20e1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_minus_zero.json000066400000000000000000000000041425465243200315730ustar00rootroot00000000000000[-0]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_negative_int.json000066400000000000000000000000061425465243200320570ustar00rootroot00000000000000[-123]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_negative_one.json000066400000000000000000000000041425465243200320440ustar00rootroot00000000000000[-1]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_negative_zero.json000066400000000000000000000000041425465243200322420ustar00rootroot00000000000000[-0]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_real_capital_e.json000066400000000000000000000000061425465243200323270ustar00rootroot00000000000000[1E22]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_real_capital_e_neg_exp.json000066400000000000000000000000061425465243200340340ustar00rootroot00000000000000[1E-2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_real_capital_e_pos_exp.json000066400000000000000000000000061425465243200340640ustar00rootroot00000000000000[1E+2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_real_exponent.json000066400000000000000000000000101425465243200322410ustar00rootroot00000000000000[123e45]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_real_fraction_exponent.json000066400000000000000000000000141425465243200341320ustar00rootroot00000000000000[123.456e78]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_real_neg_exp.json000066400000000000000000000000061425465243200320330ustar00rootroot00000000000000[1e-2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_real_pos_exponent.json000066400000000000000000000000061425465243200331270ustar00rootroot00000000000000[1e+2]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_simple_int.json000066400000000000000000000000051425465243200315450ustar00rootroot00000000000000[123]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_number_simple_real.json000066400000000000000000000000141425465243200316760ustar00rootroot00000000000000[123.456789]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object.json000066400000000000000000000000321425465243200273000ustar00rootroot00000000000000{"asd":"sdf", "dfg":"fgh"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_basic.json000066400000000000000000000000151425465243200304420ustar00rootroot00000000000000{"asd":"sdf"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_duplicated_key.json000066400000000000000000000000211425465243200323440ustar00rootroot00000000000000{"a":"b","a":"c"}y_object_duplicated_key_and_value.json000066400000000000000000000000211425465243200343030ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation{"a":"b","a":"b"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_empty.json000066400000000000000000000000021425465243200305130ustar00rootroot00000000000000{}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_empty_key.json000066400000000000000000000000061425465243200313670ustar00rootroot00000000000000{"":0}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_escaped_null_in_key.json000066400000000000000000000000241425465243200333550ustar00rootroot00000000000000{"foo\u0000bar": 42}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_extreme_numbers.json000066400000000000000000000000431425465243200325660ustar00rootroot00000000000000{ "min": -1.0e+28, "max": 1.0e+28 }alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_long_strings.json000066400000000000000000000001541425465243200320750ustar00rootroot00000000000000{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_simple.json000066400000000000000000000000101425465243200306450ustar00rootroot00000000000000{"a":[]}alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_string_unicode.json000066400000000000000000000001561425465243200324030ustar00rootroot00000000000000{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_object_with_newlines.json000066400000000000000000000000141425465243200322370ustar00rootroot00000000000000{ "a": "b" }y_string_1_2_3_bytes_UTF-8_sequences.json000066400000000000000000000000261425465243200343130ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\u0060\u012a\u12AB"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_accepted_surrogate_pair.json000066400000000000000000000000201425465243200342730ustar00rootroot00000000000000["\uD801\udc37"]y_string_accepted_surrogate_pairs.json000066400000000000000000000000341425465243200344040ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\ud83d\ude39\ud83d\udc8d"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_allowed_escapes.json000066400000000000000000000000241425465243200325530ustar00rootroot00000000000000["\"\\\/\b\f\n\r\t"]y_string_backslash_and_u_escaped_zero.json000066400000000000000000000000131425465243200351640ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\\u0000"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_backslash_doublequotes.json000066400000000000000000000000061425465243200341470ustar00rootroot00000000000000["\""]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_comments.json000066400000000000000000000000211425465243200312430ustar00rootroot00000000000000["a/*b*/c/*d//e"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_double_escape_a.json000066400000000000000000000000071425465243200325140ustar00rootroot00000000000000["\\a"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_double_escape_n.json000066400000000000000000000000071425465243200325310ustar00rootroot00000000000000["\\n"]y_string_escaped_control_character.json000066400000000000000000000000121425465243200345170ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\u0012"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_escaped_noncharacter.json000066400000000000000000000000121425465243200335510ustar00rootroot00000000000000["\uFFFF"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_in_array.json000066400000000000000000000000071425465243200312260ustar00rootroot00000000000000["asd"]y_string_in_array_with_leading_space.json000066400000000000000000000000101425465243200350320ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation[ "asd"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_last_surrogates_1_and_2.json000066400000000000000000000000201425465243200341210ustar00rootroot00000000000000["\uDBFF\uDFFF"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_nbsp_uescaped.json000066400000000000000000000000211425465243200322310ustar00rootroot00000000000000["new\u00A0line"]y_string_nonCharacterInUTF-8_U+10FFFF.json000066400000000000000000000000101425465243200341070ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["ô¿¿"]y_string_nonCharacterInUTF-8_U+1FFFF.json000066400000000000000000000000101425465243200340270ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["𛿿"]y_string_nonCharacterInUTF-8_U+FFFF.json000066400000000000000000000000071425465243200337540ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["ï¿¿"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_null_escape.json000066400000000000000000000000121425465243200317100ustar00rootroot00000000000000["\u0000"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_one-byte-utf-8.json000066400000000000000000000000121425465243200321010ustar00rootroot00000000000000["\u002c"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_pi.json000066400000000000000000000000061425465243200300310ustar00rootroot00000000000000["Ï€"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_simple_ascii.json000066400000000000000000000000101425465243200320550ustar00rootroot00000000000000["asd "]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_space.json000066400000000000000000000000031425465243200305110ustar00rootroot00000000000000" "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json000066400000000000000000000000201425465243200360300ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\uD834\uDd1e"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_three-byte-utf-8.json000066400000000000000000000000121425465243200324270ustar00rootroot00000000000000["\u0821"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_two-byte-utf-8.json000066400000000000000000000000121425465243200321310ustar00rootroot00000000000000["\u0123"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_u+2028_line_sep.json000066400000000000000000000000071425465243200321330ustar00rootroot00000000000000["
"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_u+2029_par_sep.json000066400000000000000000000000071425465243200317670ustar00rootroot00000000000000["
"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_uEscape.json000066400000000000000000000000341425465243200310070ustar00rootroot00000000000000["\u0061\u30af\u30EA\u30b9"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_uescaped_newline.json000066400000000000000000000000211425465243200327300ustar00rootroot00000000000000["new\u000Aline"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_unescaped_char_delete.json000066400000000000000000000000051425465243200337060ustar00rootroot00000000000000[""]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_unicode.json000066400000000000000000000000121425465243200310440ustar00rootroot00000000000000["\uA66D"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_unicodeEscapedBackslash.json000066400000000000000000000000121425465243200341450ustar00rootroot00000000000000["\u005C"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_unicode_2.json000066400000000000000000000000151425465243200312700ustar00rootroot00000000000000["â‚㈴â‚"]y_string_unicode_U+10FFFE_nonchar.json000066400000000000000000000000201425465243200336230ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\uDBFF\uDFFE"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_unicode_U+1FFFE_nonchar.json000066400000000000000000000000201425465243200336220ustar00rootroot00000000000000["\uD83F\uDFFE"]y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json000066400000000000000000000000121425465243200343610ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\u200B"]y_string_unicode_U+2064_invisible_plus.json000066400000000000000000000000121425465243200347470ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\u2064"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_unicode_U+FDD0_nonchar.json000066400000000000000000000000121425465243200335110ustar00rootroot00000000000000["\uFDD0"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_unicode_U+FFFE_nonchar.json000066400000000000000000000000121425465243200335420ustar00rootroot00000000000000["\uFFFE"]y_string_unicode_escaped_double_quote.json000066400000000000000000000000121425465243200352200ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation["\u0022"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_utf8.json000066400000000000000000000000131425465243200303050ustar00rootroot00000000000000["€ð„ž"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_string_with_del_character.json000066400000000000000000000000071425465243200332350ustar00rootroot00000000000000["aa"]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_lonely_false.json000066400000000000000000000000051425465243200326260ustar00rootroot00000000000000falsealire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_lonely_int.json000066400000000000000000000000021425465243200323230ustar00rootroot0000000000000042alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_lonely_negative_real.json000066400000000000000000000000041425465243200343400ustar00rootroot00000000000000-0.1alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_lonely_null.json000066400000000000000000000000041425465243200325050ustar00rootroot00000000000000nullalire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_lonely_string.json000066400000000000000000000000051425465243200330420ustar00rootroot00000000000000"asd"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_lonely_true.json000066400000000000000000000000041425465243200325120ustar00rootroot00000000000000truealire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_string_empty.json000066400000000000000000000000021425465243200326730ustar00rootroot00000000000000""alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_trailing_newline.json000066400000000000000000000000061425465243200335050ustar00rootroot00000000000000["a"] alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_true_in_array.json000066400000000000000000000000061425465243200330160ustar00rootroot00000000000000[true]alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/json/validation/y_structure_whitespace_array.json000066400000000000000000000000041425465243200335030ustar00rootroot00000000000000 [] alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/000077500000000000000000000000001425465243200233425ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/external_default_value/000077500000000000000000000000001425465243200300645ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/external_default_value/p.gpr000077500000000000000000000000431425465243200310350ustar00rootroot00000000000000with "q.gpr"; project P is end P; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/external_default_value/q.gpr000077500000000000000000000003501425465243200310370ustar00rootroot00000000000000project Q is for Source_Files use (); Path := project'Project_Dir & "some_dir"; Var1 := external ("NONEXISTINGVAR1", Path); Var2 := external ("NONEXISTINGVAR2", project'Project_Dir & "some_dir"); end Q; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/external_default_value/test.adb000077500000000000000000000022671425465243200315250ustar00rootroot00000000000000with GNATCOLL.Projects; use GNATCOLL.Projects; with GNATCOLL.VFS; use GNATCOLL.VFS; with Test_Assert; function Test return Integer is PT : Project_Tree; My_Root_Project : Project_Type; Env : Project_Environment_Access; begin Initialize (Env); GNATCOLL.Projects.Load (PT, Root_Project_Path => Create ("p.gpr"), Env => Env); declare UV_Array : constant Untyped_Variable_Array := PT.Untyped_Variables; UV : Untyped_Variable; Expected_Value : constant String := PT.Project_From_Name ("Q").Project_Path.Display_Dir_Name & "some_dir"; begin Test_Assert.Assert (UV_Array'Length = 2, "Wrong number of Untyped Variables"); if UV_Array'Length = 2 then UV := UV_Array (UV_Array'First); Test_Assert.Assert (External_Default (UV), Expected_Value, "Default external value is wrong for " & External_Name (UV)); UV := UV_Array (UV_Array'Last); Test_Assert.Assert (External_Default (UV), Expected_Value, "Default external value is wrong for " & External_Name (UV)); end if; end; return Test_Assert.Report; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/external_default_value/test.yaml000077500000000000000000000001441425465243200317310ustar00rootroot00000000000000description: Complex default value of external in imported project data: - "p.gpr" - "q.gpr"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/file_from_unit/000077500000000000000000000000001425465243200263435ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/file_from_unit/my__proc.txt000077500000000000000000000004011425465243200307110ustar00rootroot00000000000000procedure Proc is function F (I : Integer) return Integer is begin return I + 1; end; function G (I : Integer) return Integer is (I + 1); procedure P is begin null; end; procedure Q is null; begin null; end; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/file_from_unit/test.adb000077500000000000000000000013701425465243200277760ustar00rootroot00000000000000with Gnat.Strings; use Gnat.Strings; with Gnatcoll.Projects; use Gnatcoll.Projects; with Gnatcoll.VFS; use Gnatcoll.VFS; with Test_Assert; function Test return Integer is Tree : Gnatcoll.Projects.Project_Tree; begin Load (Tree, Root_Project_Path => Create (+"test1.gpr")); declare File_Name : constant String := +File_From_Unit (Project => Root_Project (Tree), Unit_Name => "PrOc", Part => Unit_Body, Language => "ada", File_Must_Exist => False); begin Test_Assert.Assert (File_Name, "my__proc.txt", "Wrong file name for unit Proc"); end; return Test_Assert.Report; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/file_from_unit/test.yaml000077500000000000000000000001571425465243200302140ustar00rootroot00000000000000description: File_From_Unit argument Unit name is case insensitive data: - "test1.gpr" - "my__proc.txt"alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/projects/file_from_unit/test1.gpr000077500000000000000000000002421425465243200301160ustar00rootroot00000000000000project Test1 is package Naming is for Body ("proc") use "my__proc.txt"; for Body_Suffix ("ada") use ".ada"; end Naming; end Test1; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/strings/000077500000000000000000000000001425465243200232025ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/strings/basics/000077500000000000000000000000001425465243200244465ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/strings/basics/memory.ads000066400000000000000000000033371425465243200264550ustar00rootroot00000000000000------------------------------------------------------------------------------ -- Copyright (C) 2015-2016, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- ------------------------------------------------------------------------------ package Memory is Allocs : Integer := 0; -- Incremented every time we do a malloc Reallocs : Integer := 0; -- Incremented every time we do a realloc end Memory; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/strings/basics/s-memory.adb000066400000000000000000000122101425465243200266620ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- GNAT RUN-TIME COMPONENTS -- -- -- -- S Y S T E M . M E M O R Y -- -- -- -- B o d y -- -- -- -- Copyright (C) 2001-2016, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 3, or (at your option) any later ver- -- -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- As a special exception under Section 7 of GPL version 3, you are granted -- -- additional permissions described in the GCC Runtime Library Exception, -- -- version 3.1, as published by the Free Software Foundation. -- -- -- -- You should have received a copy of the GNU General Public License and -- -- a copy of the GCC Runtime Library Exception along with this program; -- -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- -- . -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- Copied from System.Memory, but counts the number of times we do -- malloc and realloc. pragma Compiler_Unit_Warning; with Ada.Exceptions; with System.Soft_Links; with System.Parameters; with System.CRTL; with Memory; package body System.Memory is use Ada.Exceptions; use System.Soft_Links; function c_malloc (Size : System.CRTL.size_t) return System.Address renames System.CRTL.malloc; procedure c_free (Ptr : System.Address) renames System.CRTL.free; function c_realloc (Ptr : System.Address; Size : System.CRTL.size_t) return System.Address renames System.CRTL.realloc; ----------- -- Alloc -- ----------- function Alloc (Size : size_t) return System.Address is Result : System.Address; Actual_Size : size_t := Size; begin if Size = size_t'Last then Raise_Exception (Storage_Error'Identity, "object too large"); end if; -- Change size from zero to non-zero. We still want a proper pointer -- for the zero case because pointers to zero length objects have to -- be distinct, but we can't just go ahead and allocate zero bytes, -- since some malloc's return zero for a zero argument. if Size = 0 then Actual_Size := 1; end if; if Parameters.No_Abort then Result := c_malloc (System.CRTL.size_t (Actual_Size)); else Abort_Defer.all; Result := c_malloc (System.CRTL.size_t (Actual_Size)); Abort_Undefer.all; end if; Standard.Memory.Allocs := Standard.Memory.Allocs + 1; if Result = System.Null_Address then Raise_Exception (Storage_Error'Identity, "heap exhausted"); end if; return Result; end Alloc; ---------- -- Free -- ---------- procedure Free (Ptr : System.Address) is begin if Parameters.No_Abort then c_free (Ptr); else Abort_Defer.all; c_free (Ptr); Abort_Undefer.all; end if; end Free; ------------- -- Realloc -- ------------- function Realloc (Ptr : System.Address; Size : size_t) return System.Address is Result : System.Address; Actual_Size : constant size_t := Size; begin if Size = size_t'Last then Raise_Exception (Storage_Error'Identity, "object too large"); end if; if Parameters.No_Abort then Result := c_realloc (Ptr, System.CRTL.size_t (Actual_Size)); else Abort_Defer.all; Result := c_realloc (Ptr, System.CRTL.size_t (Actual_Size)); Abort_Undefer.all; end if; if Result = System.Null_Address then Raise_Exception (Storage_Error'Identity, "heap exhausted"); end if; Standard.Memory.Reallocs := Standard.Memory.Reallocs + 1; return Result; end Realloc; end System.Memory; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/strings/basics/test.adb000066400000000000000000001411631425465243200261030ustar00rootroot00000000000000with Ada.Command_Line; use Ada.Command_Line; with GNATCOLL.Asserts; with GNATCOLL.Strings; with GNATCOLL.Strings_Impl; with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Wide_Characters.Handling; use Ada.Wide_Characters.Handling; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Text_IO; use Ada.Text_IO; with GNAT.Source_Info; with GNAT.Strings; use GNAT.Strings; with Memory; pragma Warnings (Off); with System.Memory; pragma Warnings (On); with Test_Assert; function Test return Integer is package A renames Test_Assert; generic with package Strings is new GNATCOLL.Strings_Impl.Strings (<>); with function Image (S : Strings.Char_String) return String is <>; First_Displayable : Strings.Char_Type := Strings.Char_Type'Val (Character'Pos ('A')); procedure Do_Test (Title : String); -- Tests for various instances of xstring type On_Error is new GNATCOLL.Asserts.Error_Reporter with null record; overriding procedure On_Assertion_Failed (Self : On_Error; Msg : String; Details : String; Location : String; Entity : String); Report : On_Error; package Asserts is new GNATCOLL.Asserts.Asserts (Report); package Equals_Boolean is new Asserts.Equals (Boolean, Boolean'Image); package Equals_Integer is new Asserts.Equals (Integer, Integer'Image); use Equals_Boolean, Equals_Integer; function Image (S : String) return String is ("--" & S & "--"); function Image (S : Wide_String) return String; -- For convenience of instantiation of Asserts, below. procedure Reset_Mem; -- Reset memory allocation counters --------------- -- Reset_Mem -- --------------- procedure Reset_Mem is begin Memory.Allocs := 0; Memory.Reallocs := 0; end Reset_Mem; ----------- -- Image -- ----------- function Image (S : Wide_String) return String is Result : Unbounded_String; begin Append (Result, "--"); for C of S loop if Wide_Character'Pos (C) <= 127 then Append (Result, Character'Val (Wide_Character'Pos (C))); else Append (Result, '[' & Integer'Image (Wide_Character'Pos (C)) & ']'); end if; end loop; Append (Result, "--"); return To_String (Result); end Image; ------------------------- -- On_Assertion_Failed -- ------------------------- overriding procedure On_Assertion_Failed (Self : On_Error; Msg : String; Details : String; Location : String; Entity : String) is pragma Unreferenced (Self); begin Put_Line ((if Msg = "" then "" else Msg & " ") & "(at " & Location & ", in " & Entity & ")" & ASCII.LF & " " & Details); end On_Assertion_Failed; ------------- -- Do_Test -- ------------- procedure Do_Test (Title : String) is use Strings; function Image (S : XString) return String is (Image (S.To_String)); package Equals1 is new Asserts.Equals (T => Strings.Char_Type, Image => Strings.Char_Type'Image); package Equals2 is new Asserts.Equals (T => Strings.Char_String, Image => Image); use Equals1, Equals2; generic type Left_Type (<>) is private; type Right_Type (<>) is private; Op : String; with function Compare (Left : Left_Type; Right : Right_Type) return Boolean; with function Image (L : Left_Type) return String is <>; with function Image (L : Right_Type) return String is <>; procedure Assert_Generic (Left : Left_Type; Right : Right_Type; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity); procedure Assert_Generic (Left : Left_Type; Right : Right_Type; Location : String := GNAT.Source_Info.Source_Location; Entity : String := GNAT.Source_Info.Enclosing_Entity) is begin if not Compare (Left, Right) then Asserts.Assert_Failed (Image (Left) & ' ' & Op & ' ' & Image (Right), Location => Location, Entity => Entity); end if; end Assert_Generic; procedure Assert is new Assert_Generic (XString, Char_String, "=", "="); procedure Assert is new Assert_Generic (Char_String, XString, "=", "="); procedure Assert is new Assert_Generic (XString, XString, "=", "="); procedure Assert_Less is new Assert_Generic (XString, Char_String, "<", "<"); procedure Assert_Less is new Assert_Generic (Char_String, XString, "<", "<"); procedure Assert_Less is new Assert_Generic (XString, XString, "<", "<"); procedure Assert_Less_Equal is new Assert_Generic (XString, Char_String, "<=", "<="); procedure Assert_Less_Equal is new Assert_Generic (Char_String, XString, "<=", "<="); procedure Assert_Less_Equal is new Assert_Generic (XString, XString, "<=", "<="); procedure Assert_Greater is new Assert_Generic (XString, Char_String, ">", ">"); procedure Assert_Greater is new Assert_Generic (Char_String, XString, ">", ">"); procedure Assert_Greater is new Assert_Generic (XString, XString, ">", ">"); procedure Assert_Greater_Equal is new Assert_Generic (XString, Char_String, ">=", ">="); procedure Assert_Greater_Equal is new Assert_Generic (Char_String, XString, ">=", ">="); procedure Assert_Greater_Equal is new Assert_Generic (XString, XString, ">=", ">="); Space : constant Char_Type := Char_Type'Val (Character'Pos (' ')); Spaces : constant Char_String := Space & Space; Newline : constant Char_Type := Char_Type'Val (Character'Pos (ASCII.LF)); Equal : constant Char_Type := Char_Type'Val (Character'Pos ('=')); Empty : Char_String (1 .. 0); Short : Char_String (3 .. 7); Long : Char_String (3 .. Integer (Strings.SSize'Last) + 10); Null_String : Char_String (1 .. 0); procedure Test_Append; procedure Test_Compare; procedure Test_Indexing (Base : Char_String); procedure Test_Trim; procedure Test_Substrings; procedure Test_Starts; procedure Test_Head_Tail; procedure Test_Iterate; procedure Test_Modify (Base : Char_String); procedure Test_Shrink; procedure Test_Swap; procedure Test_Justify (Base : Char_String); procedure Test_Split (Base : Char_String); procedure Test_Search (Base : Char_String); procedure Test_Casing; procedure Test_Access; ----------------- -- Test_Append -- ----------------- procedure Test_Append is S, S2 : XString; begin S.Set (Short); A.Assert (S = Short, Title); S.Set (Long); A.Assert (S = Long, Title); S2 := S; Append (S, Short); A.Assert (S2 = Long, Title); A.Assert (S = Long & Short, Title); S.Set (Short); A.Assert (S = Short, Title); A.Assert (S2 = Long, Title); -- Appending to a slice S.Set (Long); S2 := S; S.Slice (2, 3); S.Append (Short); A.Assert (S2 = Long, Title); A.Assert (S = Long (Long'First + 1 .. Long'First + 2) & Short, Title); end Test_Append; ------------------ -- Test_Compare -- ------------------ procedure Test_Compare is S, S2 : XString; begin -- Test equality between null strings S := Null_XString; if S /= Null_XString then raise Program_Error; end if; A.Assert (S.Is_Empty = True, Title); -- Test equality for short string and null string S := Null_XString; S.Set (Empty); A.Assert (S = Empty, Title); if S /= Null_XString then raise Program_Error; end if; Assert (Compare (S, Empty), 0); -- Test equality for big string and null string S := Null_XString; S.Set (Long); -- force malloc S.Set (Empty); -- reset to empty string A.Assert (S = Empty, Title); if S /= Null_XString then raise Program_Error; end if; A.Assert (S.Is_Empty = True, Title); A.Assert (Compare (S, Empty) = 0, Title); -- Test equality for short strings S := Null_XString; S2 := Null_XString; S.Set (Short); S2.Set (Short); if S /= S2 then raise Program_Error; end if; -- Test equality for long strings S := Null_XString; S2 := Null_XString; S.Set (Long); S2.Set (Long); if S /= S2 then raise Program_Error; end if; -- Test equality for short and long strings S := Null_XString; S2 := Null_XString; S.Set (Long); -- force malloc S.Set (Short); S2.Set (Short); if S /= S2 then raise Program_Error; end if; -- Test equality with Char_String declare XS : XString; S : Char_String := Short; begin XS.Set (Short); A.Assert (To_String(XS) = S, Title); A.Assert (To_XString(S) = XS, Title); A.Assert (Compare (XS, S) = 0, Title); end; -- Test equality with substrings declare S, S2, S3 : XString; begin S.Set (Short); S2.Set (Long); A.Assert (S = Short, Title); A.Assert (Short = S, Title); A.Assert (S2 = Long, Title); A.Assert (Long = S2, Title); A.Assert (S.Slice (2, 3) = S.Slice (2, 3), Title); A.Assert (Compare (S.Slice (2, 3), S.Slice (2, 3)) = 0, Title); A.Assert (S.Slice (2, 3) = S2.Slice (2, 3), Title); A.Assert (Compare (S.Slice (2, 3), S2.Slice (2, 3)) = 0, Title); A.Assert (S2.Slice (2, 3) = S.Slice (2, 3), Title); A.Assert (Compare (S2.Slice (2, 3), S.Slice (2, 3)) = 0, Title); A.Assert (S2.Slice (2, 3) = S2.Slice (2, 3), Title); A.Assert (Compare (S2.Slice (2, 3), S2.Slice (2, 3)) = 0, Title); -- Check that we have the same behavior as we standard strings A.Assert (S.Slice (3, 2) = Null_XString, Title); A.Assert (S.Slice (Natural'Last, 1) = Null_XString, Title); A.Assert (S.Slice (1, 0) = Null_XString, Title); S3 := S2; S3.Slice (3, 2); A.Assert (S3 = Null_XString, Title); S3 := S2; S3.Slice (Natural'Last, 1); A.Assert (S3 = Null_XString, Title); S3 := S2; S3.Slice (3, 0); A.Assert (S3 = Null_XString, Title); end; declare S, S2 : XString; begin S.Set (Short); S2.Set (Long); Assert_Less (S, S2); Assert_Greater (S2, S); Assert_Less (S, Short (Short'First + 1 .. Short'Last)); Assert_Less_Equal (S, Short (Short'First + 1 .. Short'Last)); Assert_Greater_Equal (Short (Short'First + 1 .. Short'Last), S); Assert_Greater (Short (Short'First + 1 .. Short'Last), S); Assert_Less (Short, S.Slice (2, 3)); Assert_Less_Equal (Short, S.Slice (2, 3)); Assert_Greater_Equal (S.Slice (2, 3), Short); Assert_Greater (S.Slice (2, 3), Short); A.Assert (Compare (S, Short (Short'First + 1 .. Short'Last)) = -1, Title); A.Assert (Compare (Short (Short'First + 1 .. Short'Last), S) = 1, Title); Assert_Less (S2, Long (Long'First + 1 .. Long'Last)); Assert_Less (Long, S2.Slice (2, 3)); A.Assert (Compare (S2, Long (Long'First + 1 .. Long'Last)) = -1, Title); A.Assert (Compare (Long (Long'First + 1 .. Long'Last), S2) = 1, Title); A.Assert (Compare (S, S) = 0, Title); A.Assert (Compare (S2, S2) = 0, Title); end; end Test_Compare; ------------------- -- Test_Indexing -- ------------------- procedure Test_Indexing (Base : Char_String) is Is_Long : constant Boolean := Base'Length > Natural (Strings.SSize'Last); S, S2 : XString; Idx : Positive; begin S.Set (Base); Reset_Mem; -- Test the constant indexing aspect -- We check memory allocations to make sure we are using -- a constant indexing aspect if S (1) /= First_Displayable then raise Program_Error; end if; if S (2) /= Char_Type'Succ (First_Displayable) then raise Program_Error; end if; A.Assert (Memory.Allocs = 0, Title); A.Assert (Memory.Reallocs = 0, Title); begin if S (10000) /= First_Displayable then null; end if; if S (Base'Length + 1) /= First_Displayable then null; end if; raise Program_Error; -- should have receive exeption exception when Ada.Strings.Index_Error => null; end; -- Testing loops -- We check memory allocations to make sure we are using -- a constant indexing aspect Reset_Mem; Idx := Base'First; for C of S loop Assert (C, Base (Idx)); Idx := Idx + 1; end loop; Assert (Idx, Base'Last + 1); S2 := S; -- Test that the string is still shareable A.Assert (S = Base, Title); A.Assert (S2 = Base, Title); A.Assert (Memory.Allocs = (if not Strings.Copy_On_Write and then Is_Long then 1 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); -- Same test for loops on indexes Reset_Mem; Idx := Base'First; for Idx2 in S.Iterate loop A.Assert (Idx2 = Idx - Base'First + 1, Title); A.Assert (S (Idx2) = Base (Idx), Title); Idx := Idx + 1; end loop; Assert (Idx, Base'Last + 1); S2 := S; A.Assert (S = Base, Title); A.Assert (S2 = Base, Title); A.Assert (Memory.Allocs = (if not Strings.Copy_On_Write and then Is_Long then 1 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); -- Test the Variable indexing aspect S.Set (Base); S (2) := First_Displayable; A.Assert (S = Base (Base'First) & First_Displayable & Base (Base'First + 2 .. Base'Last), Title); Reset_Mem; S.Set (Base); S2 := S; S (2) := First_Displayable; -- makes a copy A.Assert (S2 = Base, Title); A.Assert (S = Base (Base'First) & First_Displayable & Base (Base'First + 2 .. Base'Last), Title); A.Assert (Memory.Allocs = (if Is_Long then 1 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); Reset_Mem; S.Set (Base); declare R : Character_Reference := S.Reference (2); begin S2 := S; R := First_Displayable; A.Assert (S2 = Base, Title); A.Assert (S = Base (Base'First) & First_Displayable & Base (Base'First + 2 .. Base'Last), Title); end; A.Assert (Memory.Allocs = (if Is_Long then 1 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); end Test_Indexing; --------------- -- Test_Trim -- --------------- procedure Test_Trim is pragma Compile_Time_Error (Short'Length + 2 * Spaces'Length > Integer (SSize'Last), "Cannot test short string with spaces"); -- So that we can test Trim with small strings. S, S2 : XString; begin -- Short strings S.Set (Spaces & Short & Spaces); A.Assert (S.Trim (Chars => Space) = Short, Title); A.Assert (S.Trim (Ada.Strings.Right) = Spaces & Short, Title); A.Assert (S.Trim (Ada.Strings.Left) = Short & Spaces, Title); S.Trim (Chars => Space); A.Assert (S = Short, Title); S.Set (Spaces & Short & Spaces); S.Trim (Side => Ada.Strings.Right, Chars => Space); A.Assert (S = Spaces & Short, Title); S.Set (Spaces & Short & Spaces); S.Trim (Side => Ada.Strings.Left, Chars => Space); A.Assert (S = Short & Spaces, Title); -- Long strings S.Set (Spaces & Long & Spaces); A.Assert (S.Trim = Long, Title); A.Assert (S.Trim (Ada.Strings.Right) = Spaces & Long, Title); A.Assert (S.Trim (Ada.Strings.Left) = Long & Spaces, Title); S2 := S; S.Trim (Chars => Space); A.Assert (S = Long, Title); S := S2; S.Trim (Side => Ada.Strings.Right, Chars => Space); A.Assert (S = Spaces & Long, Title); S := S2; S.Trim (Side => Ada.Strings.Left, Chars => Space); A.Assert (S = Long & Spaces, Title); -- Long strings with First /= 1 S.Set (Spaces & Spaces & Long & Spaces & Spaces); S.Slice (3, Spaces'Length * 4 + Long'Length - 2); A.Assert (S.Trim = Long, Title); A.Assert (S.Trim (Ada.Strings.Right) = Spaces & Long, Title); A.Assert (S.Trim (Ada.Strings.Left) = Long & Spaces, Title); S2 := S; S.Trim; A.Assert (S = Long, Title); S := S2; S.Trim (Ada.Strings.Right); A.Assert (S = Spaces & Long, Title); S := S2; S.Trim (Ada.Strings.Left); A.Assert (S = Long & Spaces, Title); end Test_Trim; --------------------- -- Test_Substrings -- --------------------- procedure Test_Substrings is S, S2, S3 : XString; begin -- Short strings S.Set (Spaces & Short & Spaces); S2 := S; -- shared buffer S.Trim; -- get a substring S2.Append (Short); -- no longer shared S3 := S; -- shared buffer S3.Append (Short); -- no longer shared A.Assert (S = Short, Title); A.Assert (S2 = Spaces & Short & Spaces & Short, Title); A.Assert (S3 = Short & Short, Title); -- Check that first character is still index 1 even with -- small strings. A.Assert (S (1) = First_Displayable, Title); end Test_Substrings; ----------------- -- Test_Starts -- ----------------- procedure Test_Starts is S : XString; begin S.Set (Short); A.Assert (S.Starts_With (Short) = True, Title); A.Assert (S.Starts_With (Short (3 .. 4)) = True, Title); A.Assert (S.Starts_With (Null_XString) = True, Title); A.Assert (S.Starts_With (Null_String) = True, Title); A.Assert (S.Starts_With (Short & First_Displayable) = False, Title); A.Assert (S.Ends_With (Short) = True, Title); A.Assert (S.Ends_With (Short (Short'Last - 1 .. Short'Last)) = True, Title); A.Assert (S.Ends_With (Null_XString) = True, Title); A.Assert (S.Ends_With (Null_String) = True, Title); A.Assert (S.Ends_With (Short & First_Displayable) = False, Title); S.Set (Long); A.Assert (S.Starts_With (Long) = True, Title); A.Assert (S.Starts_With (Long (3 .. 4)) = True, Title); A.Assert (S.Starts_With (Null_XString) = True, Title); A.Assert (S.Starts_With (Null_String) = True, Title); A.Assert (S.Starts_With (Long & First_Displayable) = False, Title); A.Assert (S.Ends_With (Long) = True, Title); A.Assert (S.Ends_With (Long (Long'Last - 1 .. Long'Last)) = True, Title); A.Assert (S.Ends_With (Null_XString) = True, Title); A.Assert (S.Ends_With (Null_String) = True, Title); A.Assert (S.Ends_With (Long & First_Displayable) = False, Title); end Test_Starts; -------------------- -- Test_Head_Tail -- -------------------- procedure Test_Head_Tail is S, S2 : XString; begin S.Set (Short); A.Assert (S.Head (1) = Short (Short'First .. Short'First), Title); A.Assert (S.Head (2) = Short (Short'First .. Short'First + 1), Title); A.Assert (S.Head (1000) = Short, Title); A.Assert (S.Tail (1) = Short (Short'Last .. Short'Last), Title); A.Assert (S.Tail (2) = Short (Short'Last - 1 .. Short'Last), Title); A.Assert (S.Tail (1000) = Short, Title); S.Set (Long); A.Assert (S.Head (1) = Long (Long'First .. Long'First), Title); A.Assert (S.Head (2) = Long (Long'First .. Long'First + 1), Title); A.Assert (S.Head (1000) = Long, Title); A.Assert (S.Tail (1) = Long (Long'Last .. Long'Last), Title); A.Assert (S.Tail (2) = Long (Long'Last - 1 .. Long'Last), Title); A.Assert (S.Tail (1000) = Long, Title); S.Set (Long); S.Slice (3, 10); A.Assert (S.Head (1) = Long (Long'First + 2 .. Long'First + 2), Title); A.Assert (S.Head (2) = Long (Long'First + 2 .. Long'First + 3), Title); A.Assert (S.Head (1000) = Long (Long'First + 2 .. Long'First + 9), Title); A.Assert (S.Tail (1) = Long (Long'First + 9 .. Long'First + 9), Title); A.Assert (S.Tail (2) = Long (Long'First + 8 .. Long'First + 9), Title); A.Assert (S.Tail (1000) =Long (Long'First + 2 .. Long'First + 9), Title); -- A slice into itself S.Set (Long); S.Slice (3, 10, Into => S); A.Assert (S = Long (Long'First + 2 .. Long'First + 9), Title); -- A slice into an already allocated string should not leak -- memory. S.Set (Long); S2.Set (Long); S.Slice (3, 10, Into => S2); A.Assert (S = Long, Title); A.Assert (S2 = Long (Long'First + 2 .. Long'First + 9), Title); end Test_Head_Tail; ------------------ -- Test_Iterate -- ------------------ procedure Test_Iterate is S : XString; Expected : Natural; E : Char_Type; begin -- Iterate on indexes, short string S.Set (Short); Expected := 1; for Index of S.Iterate loop A.Assert (Index = Expected, Title); Expected := Expected + 1; end loop; A.Assert (Expected = Short'Length + 1, Title); Expected := 1; for Index of S.Slice (2, 3).Iterate loop A.Assert (Index = Expected, Title); Expected := Expected + 1; end loop; A.Assert (Expected = 3, Title); -- Iterate on characters, short string E := First_Displayable; for C of S loop A.Assert (C = E, Title); E := Char_Type'Succ (E); end loop; A.Assert (Char_Type'Pos (E) = Char_Type'Pos (First_Displayable) + Short'Length, Title); E := Char_Type'Succ (First_Displayable); for C of S.Slice (2, 3) loop A.Assert (C = E, Title); E := Char_Type'Succ (E); end loop; A.Assert (Char_Type'Pos (E) = Char_Type'Pos (First_Displayable) + 3, Title); -- Iterate on indexes, long string S.Set (Long); Expected := 1; for Index of S.Iterate loop A.Assert (Index = Expected, Title); Expected := Expected + 1; end loop; A.Assert (Expected = Long'Length + 1, Title); Expected := 1; for Index of S.Slice (2, 10).Iterate loop A.Assert (Index = Expected, Title); Expected := Expected + 1; end loop; A.Assert (Expected = 10, Title); -- Iterate on characters, long string E := First_Displayable; for C of S loop A.Assert (C = E, Title); E := Char_Type'Succ (E); end loop; A.Assert (Char_Type'Pos (E) = Char_Type'Pos (First_Displayable) + Long'Length, Title); E := Char_Type'Succ (First_Displayable); for C of S.Slice (2, 10) loop A.Assert (C = E, Title); E := Char_Type'Succ (E); end loop; A.Assert (Char_Type'Pos (E) = Char_Type'Pos (First_Displayable) + 10, Title); end Test_Iterate; ----------------- -- Test_Modify -- ----------------- procedure Test_Modify(Base : Char_String) is S, S2 : XString; begin S.Set (Base); S2 := S; S.Replace (2, First_Displayable); A.Assert (S = Base (Base'First) & First_Displayable & Base (Base'First + 2 .. Base'Last), Title); A.Assert (S2 = Base, Title); -- Replace with small string S.Set (Base); S2 := S; S.Replace (2, 3, (3 => First_Displayable)); A.Assert (S = Base (Base'First) & First_Displayable & Base (Base'First + 3 .. Base'Last), Title); A.Assert (S2 = Base, Title); -- Replace with longer string S.Set (Base); S2 := S; S.Replace (2, 3, (3 .. 20 => First_Displayable)); A.Assert (S = Base (Base'First) & (3 .. 20 => First_Displayable) & Base (Base'First + 3 .. Base'Last), Title); A.Assert (S2 = Base, Title); -- Replace an empty string (same as insert) S.Set (Base); S2 := S; S.Replace (2, 1, (3 .. 20 => First_Displayable)); A.Assert (S = Base (Base'First) & (3 .. 20 => First_Displayable) & Base (Base'First + 1 .. Base'Last), Title); A.Assert (S2 = Base, Title); -- Replace with self S.Set (Base); S.Replace_Slice (1, 1, S); A.Assert (S = Base & Base (Base'First + 1 .. Base'Last), Title); S.Set (Base); S2 := S; S.Insert (3, First_Displayable & First_Displayable); A.Assert (S = Base (Base'First .. Base'First + 1) & First_Displayable & First_Displayable & Base (Base'First + 2 .. Base'Last), Title); A.Assert (S2 = Base, Title); -- Overwrite with shorter string S.Set (Base); S2 := S; S.Overwrite (3, Base (Base'First .. Base'First + 1)); A.Assert (S = Base (Base'First .. Base'First + 1) & Base (Base'First .. Base'First + 1) & Base (Base'First + 4 .. Base'Last), Title); A.Assert (S2 = Base, Title); -- Overwrite with longer string S.Set (Base); S2 := S; S.Overwrite (3, Base); A.Assert (S = Base (Base'First .. Base'First + 1) & Base, Title); A.Assert (S2 = Base, Title); -- Deleting S.Set (Base); S2 := S; S.Delete (3, 4); A.Assert (S = Base (Base'First .. Base'First + 1) & Base (Base'First + 4 .. Base'Last), Title); A.Assert (S2 = Base, Title); -- Deleting past the end S.Set (Base); S2 := S; S.Delete (3, 10_000); A.Assert (S = Base (Base'First .. Base'First + 1), Title); A.Assert (S2 = Base, Title); -- Clearing the string S.Set (Base); S2 := S; S.Clear; A.Assert (S2 = Base, Title); A.Assert (S = Null_String, Title); end Test_Modify; ----------------- -- Test_Shrink -- ----------------- procedure Test_Shrink is S : XString; begin S.Set (Short); S.Shrink; A.Assert (S = Short, Title); S := 50 * Long; S.Set (Long); S.Shrink; A.Assert (S = Long, Title); S.Set (Short); S.Shrink; A.Assert (S = Short, Title); end Test_Shrink; --------------- -- Test_Swap -- --------------- procedure Test_Swap is S, S2 : XString; begin -- Swapping two short strings S.Set (Short); S2.Set (Spaces); S.Swap (S2); A.Assert (S = Spaces, Title); A.Assert (S2 = Short, Title); S.Swap (S2); A.Assert (S = Short, Title); A.Assert (S2 = Spaces, Title); -- Swapping a short and a long string S.Set (Short); S2.Set (Long); S.Swap (S2); A.Assert (S = Long, Title); A.Assert (S2 = Short, Title); S.Swap (S2); A.Assert (S = Short, Title); A.Assert (S2 = Long, Title); -- Swapping self S.Set (Short); S.Swap (S); A.Assert (S = Short, Title); S.Set (Long); S.Swap (S); A.Assert (S = Long, Title); end Test_Swap; ------------------ -- Test_Justify -- ------------------ procedure Test_Justify (Base : Char_String) is S, S2 : XString; begin -- procedure Center S.Set (Base); S.Center (Width => Base'Length + 4); A.Assert (S = Space & Space & Base & Space & Space, Title); S.Clear; S.Set (Base); S.Center (Width => Base'Length + 3); A.Assert (S = Space & Space & Base & Space, Title); S.Clear; S.Set (Base); S.Center (Width => Base'Length - 1); A.Assert (S = Base, Title); S.Clear; S.Set (Base); S.Center (Base'Length + 2, First_Displayable); A.Assert (S = First_Displayable & Base & First_Displayable, Title); -- function Center S.Clear; S.Set (Base); A.Assert (S.Center (Base'Length + 4) = Space & Space & Base & Space & Space, Title); A.Assert (S.Center (Base'Length + 3) = Space & Space & Base & Space, Title); A.Assert (S.Center (Base'Length - 1) = Base, Title); -- procedure Left justify S.Clear; S.Set (Base); S.Left_Justify (Width => Base'Length + 2); A.Assert (S = Base & Space & Space, Title); S.Clear; S.Set (Base); S.Left_Justify (Width => Base'Length - 1); A.Assert (S = Base, Title); S.Clear; S.Set (Base); S.Left_Justify (Base'Length + 2, First_Displayable); A.Assert (S = Base & First_Displayable & First_Displayable, Title); -- function Left justify S.Clear; S.Set (Base); A.Assert (S.Left_Justify (Base'Length + 2) = Base & Space & Space, Title); A.Assert (S.Left_Justify (Base'Length - 1) = Base, Title); A.Assert (S.Left_Justify (Base'Length + 2, First_Displayable) = Base & First_Displayable & First_Displayable, Title); -- procedure Right justify S.Clear; S.Set (Base); S.Right_Justify (Width => Base'Length + 2); A.Assert (S = Space & Space & Base, Title); S.Clear; S.Set (Base); S.Right_Justify (Width => Base'Length - 1); A.Assert (S = Base, Title); S.Clear; S.Set (Base); S.Right_Justify (Base'Length + 2, First_Displayable); A.Assert (S = First_Displayable & First_Displayable & Base, Title); -- function Right justify S.Set (Base); A.Assert (S.Right_Justify (Base'Length + 2) = Space & Space & Base, Title); A.Assert (S.Right_Justify (Base'Length - 1) = Base, Title); A.Assert (S.Right_Justify (Base'Length + 2, First_Displayable) = First_Displayable & First_Displayable & Base, Title); end Test_Justify; ---------------- -- Test_Split -- ---------------- procedure Test_Split (Base : Char_String) is Is_Long : constant Boolean := Base'Length > Natural (Strings.SSize'Last); S, S2 : XString; begin S.Set (Space & Space & Base & Space & Base & Space & Base & Space & Space); Reset_Mem; declare R : constant XString_Array := S.Split (Space); begin -- 3 copies per non-null substring when not copy-on-write -- 1 copy when creating the slide -- 2 copies when returning the array, since have a temporary -- created by the compiler A.Assert (Memory.Allocs = (if Is_Long and not Copy_On_Write then 9 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); A.Assert (R'Length = 7, Title); A.Assert (R (R'First + 0) = Null_XString, Title); A.Assert (R (R'First + 1) = Null_String, Title); A.Assert (R (R'First + 2) = Base, Title); A.Assert (R (R'First + 3) = Base, Title); A.Assert (R (R'First + 4) = Base, Title); A.Assert (R (R'First + 5) = Null_String, Title); A.Assert (R (R'First + 6) = Null_String, Title); S2.Set_As_Join (Space, R); A.Assert (S2 = S, Title); A.Assert (Join (Space, R) = S, Title); A.Assert (Join ((1 => Space), R) = S, Title); end; Reset_Mem; declare R : XString_Array (1 .. 20); Last : Natural; begin S.Split (Space, Into => R, Last => Last); -- One copy per non-null substring when not copy-on-write A.Assert (Memory.Allocs = (if Is_Long and not Copy_On_Write then 3 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); A.Assert (Last = 7, Title); end; Reset_Mem; declare R : constant XString_Array := S.Right_Split (Space); begin -- Three copies per non-null substring when not copy-on-write A.Assert (Memory.Allocs = (if Is_Long and not Copy_On_Write then 9 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); A.Assert (R'Length = 7, Title); A.Assert (R (R'First + 6) = Null_XString, Title); A.Assert (R (R'First + 5) = Null_String, Title); A.Assert (R (R'First + 4) = Base, Title); A.Assert (R (R'First + 3) = Base, Title); A.Assert (R (R'First + 2) = Base, Title); A.Assert (R (R'First + 1) = Null_String, Title); A.Assert (R (R'First + 0) = Null_String, Title); end; Reset_Mem; declare R : XString_Array (1 .. 20); Last : Natural; begin S.Right_Split (Space, Into => R, Last => Last); A.Assert (Memory.Allocs = (if Is_Long and not Copy_On_Write then 3 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); A.Assert (Last = 7, Title); end; declare R : constant XString_Array := S.Split (Space, Max_Split => 1); R2 : constant XString_Array := S.Right_Split (Space, Max_Split => 1); begin A.Assert (R'Length = 1, Title); A.Assert (R (R'First + 0) = S, Title); A.Assert (R2'Length = 1, Title); A.Assert (R2 (R2'First + 0) = S, Title); S2.Set_As_Join (Space, R); A.Assert (S2 = S, Title); A.Assert (Join (Space, R) = S, Title); A.Assert (Join ((1 => Space), R) = S, Title); end; declare R : constant XString_Array := S.Split (Space, Max_Split => 2); R2 : constant XString_Array := S.Right_Split (Space, Max_Split => 2); begin A.Assert (R'Length = 2, Title); A.Assert (R (R'First + 0) = Null_XString, Title); A.Assert (R (R'First + 1) = Space & Base & Space & Base & Space & Base & Space & Space, Title); A.Assert (R2'Length = 2, Title); A.Assert (R2 (R2'First + 0) = Null_XString, Title); A.Assert (R2 (R2'First + 1) = Space & Space & Base & Space & Base & Space & Base & Space, Title); S2.Set_As_Join (Space, R); A.Assert (S2 = S, Title); A.Assert (Join (Space, R) = S, Title); A.Assert (Join ((1 => Space), R) = S, Title); end; declare R : constant XString_Array := S.Split (Space, Omit_Empty => True); R2 : constant XString_Array := S.Right_Split (Space, Omit_Empty => True); begin A.Assert (R'Length = 3, Title); A.Assert (R (R'First + 0) = Base, Title); A.Assert (R (R'First + 1) = Base, Title); A.Assert (R (R'First + 2) = Base, Title); A.Assert (R2'Length = 3, Title); A.Assert (R2 (R2'First + 2) = Base, Title); A.Assert (R2 (R2'First + 1) = Base, Title); A.Assert (R2 (R2'First + 0) = Base, Title); end; declare R : constant XString_Array := Null_XString.Split (Space, Omit_Empty => True); R2 : constant XString_Array := Null_XString.Right_Split (Space, Omit_Empty => True); begin A.Assert (R'Length = 0, Title); A.Assert (R2'Length = 0, Title); end; -- Splitting on strings declare R : constant XString_Array := S.Split (Space & Space); begin A.Assert (R'Length = 3, Title); A.Assert (R (R'First + 0) = Null_XString, Title); A.Assert (R (R'First + 1) = Base & Space & Base & Space & Base, Title); A.Assert (R (R'First + 2) = Null_XString, Title); end; declare R : constant XString_Array := S.Split (Space & Space, Omit_Empty => True); begin A.Assert (R'Length = 1, Title); A.Assert (R (R'First + 0) = Base & Space & Base & Space & Base, Title); end; A.Assert (Null_XString.Split (Space & Space)'Length = 0, Title); A.Assert (Null_XString.Split (Null_String)'Length = 0, Title); A.Assert (S.Split (Null_String)'Length = 0, Title); declare R : constant XString_Array := S.Right_Split (Space & Space); begin A.Assert (R'Length = 3, Title); A.Assert (R (R'First + 0) = Null_XString, Title); A.Assert (R (R'First + 1) = Base & Space & Base & Space & Base, Title); A.Assert (R (R'First + 2) = Null_XString, Title); end; declare R : constant XString_Array := S.Right_Split (Space & Space, Omit_Empty => True); begin A.Assert (R'Length = 1, Title); A.Assert (R (R'First + 0) = Base & Space & Base & Space & Base, Title); end; A.Assert (Null_XString.Right_Split (Space & Space)'Length = 0, Title); A.Assert (Null_XString.Right_Split (Null_String)'Length = 0, Title); A.Assert (S.Right_Split (Null_String)'Length = 0, Title); -- Joining A.Assert (Join (Null_XString, XString_Array'(1 .. 0 => Null_XString)) = Null_XString, Title); A.Assert (Join (Space, XString_Array'(1 .. 0 => Null_XString)) = Null_XString, Title); A.Assert (Join (Space & Space, XString_Array'(1 .. 0 => Null_XString)) = Null_XString, Title); -- Parsing a file containing "key = value" lines declare L : XString_Array (1 .. 2); Key, Value : XString; Last : Natural; begin S.Set (Spaces & Newline & Base & Equal & Base & Newline & Base & Equal & Base & Newline & Base & Equal & Base & Newline); Reset_Mem; for Line of S.Split (Newline) loop Line.Split (Equal, Into => L, Last => Last); if Last = 2 then Key := L (1); Key.Trim; Value := L (2); Value.Trim; end if; end loop; A.Assert (Memory.Allocs = (if Is_Long and not Copy_On_Write then 14 else 0), Title); A.Assert (Memory.Reallocs = 0, Title); end; end Test_Split; ----------------- -- Test_Search -- ----------------- procedure Test_Search (Base : Char_String) is S, S2 : XString; begin S.Set (Space & Space & Base & Space & Base & Space & Base & Space & Space); A.Assert (S.Count (Space) = 6, Title); A.Assert (S.Count (Char_Type'Val (0)) = 0, Title); A.Assert (S.Count (Space & Space) = 2, Title); A.Assert (S.Count (First_Displayable & Char_Type'Succ (First_Displayable)) = 3, Title); A.Assert (S.Count (Null_String) = Natural'Last, Title); A.Assert (Null_XString.Count (Space) = 0, Title); A.Assert (Null_XString.Count (Space & Space) = 0, Title); A.Assert (Null_XString.Count (Null_String) = 0, Title); A.Assert (S.Find (Space) = 1, Title); A.Assert (S.Find (Space & Space) = 1, Title); A.Assert (S.Slice (2, 3).Find (Space) = 1, Title); A.Assert (S.Slice (3, Base'Length * 2).Find (Space) = Base'Length + 1, Title); A.Assert (S.Find (Space, Low => 2, High => 3) = 2, Title); A.Assert (S.Find (Space, Low => 3) = Base'Length + 3, Title); A.Assert (S.Find (Base, Low => 3, High => 4) = 0, Title); A.Assert (S.Find (First_Displayable) = 3, Title); A.Assert (S.Find (Base) = 3, Title); A.Assert (S.Right_Find (Space) = S.Length, Title); A.Assert (S.Right_Find (Space & Space) = S.Length - 1, Title); A.Assert (S.Right_Find (Base) = S.Length - 1 - Base'Length, Title); A.Assert (S.Find (First_Displayable & First_Displayable) = 0, Title); A.Assert (S.Right_Find (First_Displayable & First_Displayable) = 0, Title); end Test_Search; ----------------- -- Test_Casing -- ----------------- procedure Test_Casing is S : XString; S2 : XString; begin S.Set (Short); A.Assert (S.Is_Upper = True, Title); A.Assert (S.Is_Lower = False, Title); S2 := To_Lower(S); A.Assert (S2.Is_Upper = False, Title); A.Assert (S2.Is_Lower = True, Title); S.To_Lower; A.Assert (S.Is_Upper = False, Title); A.Assert (S.Is_Lower = True, Title); S.Capitalize; A.Assert ((Slice (S, 1, 1).Is_Upper and Slice (S, 2, S.Length).Is_Lower) = True, Title); A.Assert ((Slice (S, 1, 1).Is_Lower and Slice (S, 2, S.Length).Is_Upper) = False, Title); S2 := To_Upper(S); A.Assert (S2.Is_Upper = True, Title); A.Assert (S2.Is_Lower = False, Title); S.To_Upper; A.Assert (S.Is_Upper = True, Title); A.Assert (S.Is_Lower = False, Title); S.Set (Long); A.Assert (S.Is_Upper = (Long'Length < 100), Title); A.Assert (S.Is_Lower = False, Title); S2 := To_Lower(S); A.Assert (S2.Is_Upper = False, Title); A.Assert (S2.Is_Lower = True, Title); S.To_Lower; A.Assert (S.Is_Upper = False, Title); A.Assert (S.Is_Lower = True, Title); S.Capitalize; A.Assert ((Slice (S, 1, 1).Is_Upper and Slice (S, 2, S.Length).Is_Lower) = True, Title); A.Assert ((Slice (S, 1, 1).Is_Lower and Slice (S, 2, S.Length).Is_Upper) = False, Title); S2 := To_Upper(S); A.Assert (S2.Is_Upper = True, Title); A.Assert (S2.Is_Lower = False, Title); S.To_Upper; A.Assert (S.Is_Upper = True, Title); A.Assert (S.Is_Lower = False, Title); end Test_Casing; ----------------- -- Test_Access -- ----------------- procedure Test_Access is S : XString; Is_Long : Boolean; procedure Callback (Data : Char_String) is begin A.Assert (Data = (if Is_Long then Long else Short), Title); S.Append (Space); A.Assert (Data = (if Is_Long then Long else Short), Title); A.Assert (S = (if Is_Long then Long else Short) & Space, Title); S := Null_XString; A.Assert (Data = (if Is_Long then Long else Short), Title); end Callback; begin S.Set (Short); Is_Long := False; S.Access_String (Callback'Access); S.Set (Long); Is_Long := True; S.Access_String (Callback'Access); end Test_Access; begin declare C : Char_Type := First_Displayable; begin for S in Short'Range loop Short (S) := C; C := Char_Type'Succ (C); end loop; C := First_Displayable; for S in Long'Range loop Long (S) := C; C := Char_Type'Succ (C); end loop; end; declare -- coverage of function '*' (Count : Natural; -- Right : Char_Type) return XString -- and of function '*' (Count : Natural; -- Right : XString) return XString S1 : XString := 4 * First_Displayable; S2 : XString := 4 * S1; begin A.Assert (S1.Length = 4); A.Assert (S1 (1) = First_Displayable); A.Assert (S1 (S1.Length) = First_Displayable); A.Assert (S2.Length = 16); A.Assert (S2 (1) = First_Displayable); A.Assert (S2 (S2.Length) = First_Displayable); end; Test_Append; Test_Compare; Test_Indexing (Short); Test_Indexing (Long); Test_Trim; Test_Substrings; Test_Starts; Test_Head_Tail; Test_Iterate; Test_Modify (Short); Test_Modify (Long); Test_Shrink; Test_Swap; Test_Justify (Short); Test_Justify (Long); Test_Search (Short); Test_Search (Long); Test_Split (Short); Test_Split (Long); Test_Casing; Test_Access; end Do_Test; procedure Test_COW is new Do_Test (GNATCOLL.Strings); package Basic_No_COW is new GNATCOLL.Strings_Impl.Strings (GNATCOLL.Strings_Impl.Optimal_String_Size, Character, String, Copy_On_Write => False); procedure Test_No_COW is new Do_Test (Basic_No_COW); type SSize_3 is mod 128; package Strings3 is new GNATCOLL.Strings_Impl.Strings (SSize_3, Character, String); procedure Test3 is new Do_Test (Strings3); type SSize_2 is mod 10; package Wide is new GNATCOLL.Strings_Impl.Strings (SSize_2, Wide_Character, Wide_String, Copy_On_Write => True); procedure Test_Wide is new Do_Test (Wide); begin Test_No_COW("basic strings, no COW"); Test_COW("basic strings, with COW"); Test3("strings with size" & SSize_3'Last'Img); Test_Wide("wide strings"); return A.Report; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/strings/basics/test.gpr000066400000000000000000000006201425465243200261350ustar00rootroot00000000000000with "gnatcoll"; project Test is for Main use ("test.adb"); for Object_Dir use "obj"; for Source_Dirs use (".", "../../../support"); package Compiler is for Switches ("Ada") use ("-g", "-gnateE"); for Switches ("s-memory.adb") use ("-gnatg") & Compiler'Switches ("Ada"); end Compiler; package Binder is for Switches ("Ada") use ("-E"); end Binder; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/strings/basics/test.yaml000066400000000000000000000000471425465243200263120ustar00rootroot00000000000000description: Test for GNATCOLL.Strings alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/vfs/000077500000000000000000000000001425465243200223075ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/vfs/create_from_dir/000077500000000000000000000000001425465243200254335ustar00rootroot00000000000000alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/vfs/create_from_dir/test.adb000066400000000000000000000077271425465243200270770ustar00rootroot00000000000000with GNAT.OS_Lib; use GNAT.OS_Lib; with GNATCOLL.VFS; use GNATCOLL.VFS; with Ada.Text_IO; use Ada.Text_IO; with Test_Assert; function Test return Integer is package A renames Test_Assert; DS : constant Character := GNAT.OS_Lib.Directory_Separator; Folder : Virtual_File; F : Virtual_File; begin ------------ -- Case 1 -- ------------ -- Using a directory that is not a full name (and where the .. cannot -- be resolved) Folder := Create (+".." & DS & ".." & DS & "foo" & DS); F := Create_From_Dir (Dir => Folder, Base_name => +"file.ads"); A.Assert (".." & DS & ".." & DS & "foo" & DS & "file.ads", F.Display_Full_Name, "With base name and relative directory"); A.Assert (".." & DS & ".." & DS & "foo" & DS & "file.ads", F.Display_Full_Name (Normalize => True), "Normalized with base name and relative directory"); F := Create_From_Dir (Dir => Folder, Base_name => +"file.ads", Normalize => True); A.Assert (".." & DS & ".." & DS & "foo" & DS & "file.ads", F.Display_Full_Name, "With base name and relative directory"); A.Assert (".." & DS & ".." & DS & "foo" & DS & "file.ads", F.Display_Full_Name (Normalize => True), "Normalized with base name and relative directory"); ------------ -- Case 2 -- ------------ Folder := Create (+"foo1" & DS & "foo2" & DS & "foo3" & DS & ""); F := Create_From_Dir (Dir => Folder, Base_name => +".." & DS & ".." & DS & "file.ads"); A.Assert ("foo1" & DS & "foo2" & DS & "foo3" & DS & ".." & DS & ".." & DS & "file.ads", F.Display_Full_Name, "When file is relative to absolute directory"); A.Assert ("foo1" & DS & "file.ads", F.Display_Full_Name (Normalize => True), "Normalized name when file is relative to absolute directory"); F := Create_From_Dir ( Dir => Folder, Base_name => +".." & DS & ".." & DS & "file.ads", Normalize => True); A.Assert ("foo1" & DS & "foo2" & DS & "foo3" & DS & ".." & DS & ".." & DS & "file.ads", F.Display_Full_Name, "When file is relative to normalized absolute directory"); A.Assert ("foo1" & DS & "file.ads", F.Display_Full_Name (Normalize => True), "Normalized name when file is relative to normalized absolute" & " directory"); ------------ -- Case 3 -- ------------ -- Using an absolute directory, where the .. can be resolved Folder := Create (+"" & DS & "foo1" & DS & "foo2" & DS & "foo3" & DS & ".." & DS & ".." & DS & "foo" & DS & ""); F := Create_From_Dir (Dir => Folder, Base_name => +"file.ads"); A.Assert ("" & DS & "foo1" & DS & "foo2" & DS & "foo3" & DS & ".." & DS & ".." & DS & "foo" & DS & "file.ads", F.Display_Full_Name, "When file is relative to absolute directory with .."); A.Assert ("" & DS & "foo1" & DS & "foo" & DS & "file.ads", F.Display_Full_Name (Normalize => True), "Normalized name when file is relative to absolute directory" & " with .."); F := Create_From_Dir (Dir => Folder, Base_name => +"file.ads", Normalize => True); A.Assert ("" & DS & "foo1" & DS & "foo" & DS & "file.ads", F.Display_Full_Name, "When file is relative to normalized absolute directory with .."); A.Assert ("" & DS & "foo1" & DS & "foo" & DS & "file.ads", F.Display_Full_Name (Normalize => True), "Normalized name when file is relative to normalized absolute" & " directory with .."); -- Check Create_From_Dir with a No_File entry declare Test_Success : Boolean := False; begin begin F := Create_From_Dir (No_File, +"file.ads"); exception when VFS_Invalid_File_Error => Test_Success := True; end; A.Assert (Test_Success, "Should raise Invalid_File_Error"); end; return A.Report; end Test; alire-1.2.1/deps/gnatcoll-slim/testsuite/tests/vfs/create_from_dir/test.yaml000066400000000000000000000000421425465243200272720ustar00rootroot00000000000000description: Test Create_From_Dir alire-1.2.1/deps/gnatcoll-slim/version_information000066400000000000000000000000041425465243200223250ustar00rootroot000000000000000.0 pax_global_header00006660000000000000000000000064140273477060014524gustar00rootroot0000000000000052 comment=4550aa356d55b9cd55f26acd34701f646021c5ff alire-1.2.1/deps/minirest/000077500000000000000000000000001402734770600154065ustar00rootroot00000000000000alire-1.2.1/deps/minirest/.github/000077500000000000000000000000001402734770600167465ustar00rootroot00000000000000alire-1.2.1/deps/minirest/.github/workflows/000077500000000000000000000000001402734770600210035ustar00rootroot00000000000000alire-1.2.1/deps/minirest/.github/workflows/build.yml000066400000000000000000000010261402734770600226240ustar00rootroot00000000000000name: Build on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Set up GNAT toolchain run: > sudo apt-get update && sudo apt-get install gnat gprbuild - name: Set up Alire uses: alire-project/setup-alire@latest-stable - name: Build run: | alr update -f -n # force to accept curl missing alr with --versions alr build alire-1.2.1/deps/minirest/.gitignore000066400000000000000000000000351402734770600173740ustar00rootroot00000000000000obj/ lib/ alire/ alire.lock alire-1.2.1/deps/minirest/LICENSE000066400000000000000000000020631402734770600164140ustar00rootroot00000000000000MIT License Copyright (c) 2020 Alejandro R Mosteo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. alire-1.2.1/deps/minirest/README.md000066400000000000000000000005311402734770600166640ustar00rootroot00000000000000# minirest [![Build](https://github.com/mosteo/minirest/workflows/Build/badge.svg)](https://github.com/mosteo/minirest/actions) [![Alire](https://img.shields.io/endpoint?url=https://alire.ada.dev/badges/minirest.json)](https://alire.ada.dev/crates/minirest.html) Minimalist REST Ada client library. Depends on `curl` being available in PATH. alire-1.2.1/deps/minirest/alire.toml000066400000000000000000000004761402734770600174060ustar00rootroot00000000000000name = "minirest" description = "Minimalist Ada REST client library" version = "0.2-dev" authors = ["Alejandro R. Mosteo"] maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mosteo"] licenses = "MIT" tags = ["rest"] website = "https://github.com/mosteo/minirest" [[depends-on]] aaa = "~0.2.1" curl = "*" alire-1.2.1/deps/minirest/minirest.gpr000066400000000000000000000055611402734770600177610ustar00rootroot00000000000000-- begin auto-gpr-with -- -- This section was automatically added by Alire with "aaa.gpr"; -- end auto-gpr-with -- project Minirest is for Library_Name use "Minirest"; for Library_Version use "0.0.0"; for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Library_Dir use "lib"; type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := external ("MINIREST_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); for Library_Kind use Library_Type; type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("MINIREST_COMPILE_CHECKS", "enabled"); Runtime_Checks : Enabled_Kind := External ("MINIREST_RUNTIME_CHECKS", "enabled"); Style_Checks : Enabled_Kind := External ("MINIREST_STYLE_CHECKS", "enabled"); Contracts_Checks : Enabled_Kind := External ("MINIREST_CONTRACTS", "enabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("MINIREST_BUILD_MODE", "debug"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Supress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => null; Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-ds", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnatyO"); -- Overriding subprograms explicitly marked as such when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => null; Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Minirest; alire-1.2.1/deps/minirest/src/000077500000000000000000000000001402734770600161755ustar00rootroot00000000000000alire-1.2.1/deps/minirest/src/minirest.adb000066400000000000000000000127251402734770600205060ustar00rootroot00000000000000with AAA.Processes; with Ada.Strings.Unbounded; with Ada.Integer_Text_IO; with GNAT.OS_Lib; package body Minirest is package OS renames GNAT.OS_Lib; ------------------ -- Code_To_Kind -- ------------------ function Code_To_Kind (Code : Integer) return Status_Kinds is (case Code is when 100 .. 199 => Informative, when 200 .. 299 => Success, when 300 .. 399 => Redirect, when 400 .. 499 => Client_Error, when 500 .. 599 => Server_Error, when others => raise Constraint_Error); -------------- -- Encoding -- -------------- function To_Hex (Char : Character) return String is Hex : String (1 .. 6); begin Ada.Integer_Text_IO.Put (Hex, Character'Pos (Char), Base => 16); return Hex (4 .. 5); end To_Hex; function Encoding (Char : Character) return String is (case Char is when '!' | '#' | '$' | '%' | '&' | ''' | '(' | ')' | '*' | '+' | ',' | '/' | ':' | ';' | '=' | '?' | '@' | '[' | ']' | ' ' => "%" & To_Hex (Char), when others => (1 => Char)); ------------ -- Encode -- ------------ function Encode (S : String) return String is use Ada.Strings.Unbounded; Result : Unbounded_String; begin for Char of S loop Append (Result, Encoding (Char)); end loop; return To_String (Result); end Encode; ----------- -- "and" -- ----------- function "and" (L : Parameters; R : Parameters) return Parameters is begin return Result : Parameters := L do for I in R.Data.Iterate loop Result.Data.Insert (AAA.Strings.Maps.Key (I), R.Data (I)); end loop; end return; end "and"; --------- -- "=" -- --------- function "=" (Key, Value : String) return Parameters is begin return P : Parameters do P.Data.Insert (Key, Value); end return; end "="; --------- -- Get -- --------- Curl : constant OS.String_Access := OS.Locate_Exec_On_Path ("curl"); function Get (URL : String; Arguments : Parameters := No_Arguments; Headers : Parameters := No_Arguments) return Response is function To_URL_Args (Map : AAA.Strings.Map) return String is use AAA.Strings.Maps; Flat : AAA.Strings.Vector; begin for I in Map.Iterate loop Flat.Append (Encode (Key (I)) & "=" & Encode (Map (I))); end loop; return Flat.Flatten ('&'); end To_URL_Args; Curl_Args : AAA.Strings.Vector := AAA.Strings .To_Vector ("curl") .Append ("-s") .Append ("-i"); begin if Curl in null then raise Rest_Error with "Could not find 'curl' tool in path"; end if; -- Add request headers for I in Headers.Data.Iterate loop Curl_Args.Append ("-H"); Curl_Args.Append (AAA.Strings.Maps.Key (I) & ": " & Headers.Data (I)); end loop; declare Raw : constant AAA.Processes.Result := AAA.Processes.Run (Curl_Args .Append (URL & (if Arguments.Data.Is_Empty then "" elsif (for some C of URL => C = '?') then "&" else "?") & To_URL_Args (Arguments.Data)), Raise_On_Error => False); begin if Raw.Exit_Code /= 0 then raise Rest_Error with "curl exited with non-zero error code:" & Raw.Exit_Code'Image; end if; declare Status_Line : constant String := Raw.Output.First_Element; Code : Integer := -1; In_Headers : Boolean := True; Skip : Boolean := False; begin -- Identify code for I in Status_Line'Range loop if Status_Line (I) = ' ' then Code := Integer'Value (Status_Line (I + 1 .. I + 4)); exit; end if; end loop; if Code = -1 then raise Rest_Error with "Malformed status line: " & Status_Line; end if; -- Fill response return R : Response (Code_To_Kind (Code), Status_Line'Length) do R.Status_Line := Status_Line; R.Status_Code := Code; for I in Raw.Output.First_Index + 1 .. Raw.Output.Last_Index loop declare Line : constant String := Raw.Output (I); begin if In_Headers and then Line = "" then In_Headers := False; Skip := True; end if; if In_Headers then R.Raw_Headers.Append (Line); R.Headers.Insert (AAA.Strings.Head (Line, ':'), AAA.Strings.Trim (AAA.Strings.Tail (Line, ':'))); elsif Skip then Skip := False; else R.Content.Append (Line); end if; end; end loop; end return; end; end; end Get; end Minirest; alire-1.2.1/deps/minirest/src/minirest.ads000066400000000000000000000027511402734770600205250ustar00rootroot00000000000000with AAA.Strings; package Minirest is Rest_Error : exception; type Status_Kinds is (Informative, -- 1xx Success, -- 2xx Redirect, -- 3xx Client_Error, -- 4xx Server_Error); -- 5xx type Parameters is private; -- A collection of arguments of type key + value No_Arguments : constant Parameters; function "and" (L : Parameters; R : Parameters) return Parameters; function "=" (Key, Value : String) return Parameters; type Response (Status : Status_Kinds; Status_Length : Natural) is tagged record Status_Line : String (1 .. Status_Length); Status_Code : Positive range 100 .. 599; Raw_Headers : AAA.Strings.Vector; Headers : AAA.Strings.Map; Content : AAA.Strings.Vector; end record; function Succeeded (This : Response) return Boolean is (This.Status = Success); function Get (URL : String; Arguments : Parameters := No_Arguments; -- these are ?key=val Headers : Parameters := No_Arguments) -- these are Key: Val return Response; -- Use GET to retrieve URL; may raise Rest_Error for unexpected situations. -- Headers are passed via -H switch to curl. private type Parameters is record Data : AAA.Strings.Map; end record; No_Arguments : constant Parameters := (Data => AAA.Strings.Empty_Map); end Minirest; pax_global_header00006660000000000000000000000064140653703160014517gustar00rootroot0000000000000052 comment=0c7d20c0c8b48ccb6b25fb648d48382e598c25c3 alire-1.2.1/deps/optional/000077500000000000000000000000001406537031600153745ustar00rootroot00000000000000alire-1.2.1/deps/optional/.gitignore000066400000000000000000000000211406537031600173550ustar00rootroot00000000000000obj/ lib/ alire/ alire-1.2.1/deps/optional/LICENSE000066400000000000000000001045151406537031600164070ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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. This program 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. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . alire-1.2.1/deps/optional/README000066400000000000000000000003461406537031600162570ustar00rootroot00000000000000[![Alire](https://img.shields.io/endpoint?url=https://alire.ada.dev/badges/optional.json)](https://alire.ada.dev/crates/optional.html) ## Optional values See `Optional.Values` package for specs and `examples/optional-demo.adb`. alire-1.2.1/deps/optional/alire.lock000066400000000000000000000001501406537031600173360ustar00rootroot00000000000000# THIS IS A MACHINE-GENERATED FILE. DO NOT EDIT MANUALLY. [solution] [solution.context] solved = true alire-1.2.1/deps/optional/alire.toml000066400000000000000000000004001406537031600173570ustar00rootroot00000000000000name = "optional" description = "Optional values a la java.lang.Optional" version = "0.1-rc1" tags = ["optional", "functional"] authors = ["Alejandro R. Mosteo"] maintainers = ["Alejandro R. Mosteo "] maintainers-logins = ["mosteo"] alire-1.2.1/deps/optional/examples/000077500000000000000000000000001406537031600172125ustar00rootroot00000000000000alire-1.2.1/deps/optional/examples/optional-demo.adb000066400000000000000000000005631406537031600224350ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; with Optional.Values; procedure Optional.Demo is package Opt_Strings is new Optional.Values (String); begin Put_Line (Opt_Strings.Empty.Image); Put_Line (Opt_Strings.Empty.Or_Else ("default")'Image); Put_Line (Opt_Strings.Unit ("hello").Image); Put_Line (Opt_Strings.Unit ("hello").Element.Image); end Optional.Demo; alire-1.2.1/deps/optional/optional.gpr000066400000000000000000000054501406537031600177370ustar00rootroot00000000000000project Optional is for Library_Name use "optional"; for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Library_Dir use "lib"; type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := external ("OPTIONAL_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); for Library_Kind use Library_Type; type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("OPTIONAL_COMPILE_CHECKS", "enabled"); Runtime_Checks : Enabled_Kind := External ("OPTIONAL_RUNTIME_CHECKS", "enabled"); Style_Checks : Enabled_Kind := External ("OPTIONAL_STYLE_CHECKS", "enabled"); Contracts_Checks : Enabled_Kind := External ("OPTIONAL_CONTRACTS", "enabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("OPTIONAL_BUILD_MODE", "debug"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Supress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-d", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnatyO"); -- Overriding subprograms explicitly marked as such when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => null; end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnat2020", "-gnatw.X", -- Disable warnings for No_Exception_Propagation "-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Optional; alire-1.2.1/deps/optional/optional_demo.gpr000066400000000000000000000051251406537031600207420ustar00rootroot00000000000000with "optional"; project Optional_Demo is for Source_Dirs use ("examples"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Main use ("examples/optional-demo.adb"); type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("OPTIONAL_COMPILE_CHECKS", "enabled"); Runtime_Checks : Enabled_Kind := External ("OPTIONAL_RUNTIME_CHECKS", "enabled"); Style_Checks : Enabled_Kind := External ("OPTIONAL_STYLE_CHECKS", "enabled"); Contracts_Checks : Enabled_Kind := External ("OPTIONAL_CONTRACTS", "enabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("OPTIONAL_BUILD_MODE", "debug"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Supress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-d", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnatyO"); -- Overriding subprograms explicitly marked as such when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => null; end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnat2020", "-gnatw.X", -- Disable warnings for No_Exception_Propagation "-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Optional_Demo; alire-1.2.1/deps/optional/src/000077500000000000000000000000001406537031600161635ustar00rootroot00000000000000alire-1.2.1/deps/optional/src/optional-values.adb000066400000000000000000000017751406537031600217670ustar00rootroot00000000000000with Ada.Unchecked_Deallocation; package body Optional.Values is ------------ -- Adjust -- ------------ overriding procedure Adjust (This : in out Optional) is begin if This.Element /= null then This.Element := new Element_Type'(This.Element.all); end if; end Adjust; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Optional) is procedure Free is new Ada.Unchecked_Deallocation (Element_Type, Element_Access); begin Free (This.Element); end Finalize; -------------- -- Or_Raise -- -------------- function Or_Raise (This : Optional; Ex_Id : Ada.Exceptions.Exception_Id; Ex_Msg : String := "") return Element_Type is begin if This.Has_Element then return This.Element.all; else Ada.Exceptions.Raise_Exception (Ex_Id, Ex_Msg); end if; end Or_Raise; end Optional.Values; alire-1.2.1/deps/optional/src/optional-values.ads000066400000000000000000000142541406537031600220040ustar00rootroot00000000000000with Ada.Exceptions; private with Ada.Finalization; generic type Element_Type (<>) is private; with function Image (This : Element_Type) return String; package Optional.Values with Preelaborate is -- Reference types type Const_Ref (Ptr : access constant Element_Type) is limited null record with Implicit_Dereference => Ptr; type Var_Ref (Ptr : access Element_Type) is limited null record with Implicit_Dereference => Ptr; -------------- -- Optional -- -------------- type Optional is tagged private; function "=" (L : Optional; R : Element_Type) return Boolean; function "=" (L : Element_Type; R : Optional) return Boolean; Empty : constant Optional; function Has_Element (This : Optional) return Boolean; function Image (This : Optional) return String; function Unit (Element : Element_Type) return Optional; function Element (This : Optional) return Const_Ref with Pre => This.Has_Element; function Value (This : Optional) return Element_Type with Pre => This.Has_Element; function Reference (This : in out Optional) return Var_Ref with Pre => This.Has_Element; function Is_Empty (This : Optional) return Boolean; ---------------- -- Operations -- ---------------- function Flat_Map (This : Optional; Mapper : access function (Element : Optional) return Optional) return Optional with Post => (if This.Has_Element and then Mapper /= null then Flat_Map'Result = Mapper (This) elsif This.Has_Element and then Mapper = null then Flat_Map'Result = This else Flat_Map'Result = Empty); function Map (This : Optional; Mapper : access function (Element : Element_Type) return Element_Type) return Optional with Post => (if This.Has_Element and then Mapper /= null then Map'Result.Element.Ptr.all = Mapper (This.Element.Ptr.all) elsif This.Has_Element and then Mapper = null then Map'Result = This else Map'Result = Empty); function Or_Else (This : Optional; Default : Element_Type) return Element_Type with Post => (if This.Has_Element then Or_Else'Result = This.Element.Ptr.all else Or_Else'Result = Default); function Or_Raise (This : Optional; Ex_Id : Ada.Exceptions.Exception_Id; Ex_Msg : String := "") return Element_Type with Post => (if This.Has_Element then Or_Raise'Result = This.Element.Ptr.all else raise Constraint_Error); -- Actually, Ex_Id will be raised, not CE function Filter (This : Optional; Condition : Boolean) return Optional with Post => (if Condition then Filter'Result = This else Filter'Result = Empty); ---------------- -- References -- ---------------- function Image (This : Const_Ref) return String; function Image (This : Var_Ref) return String; private package AF renames Ada.Finalization; type Element_Access is access Element_Type; type Optional is new Ada.Finalization.Controlled with record Element : Element_Access; -- Holders still causing bugs end record; overriding procedure Adjust (This : in out Optional); overriding procedure Finalize (This : in out Optional); --------- -- "=" -- --------- function "=" (L : Optional; R : Element_Type) return Boolean is (L.Has_Element and then L.Element.all = R); function "=" (L : Element_Type; R : Optional) return Boolean is (R = L); ------------- -- Element -- ------------- function Element (This : Optional) return Const_Ref is (Const_Ref'(Ptr => This.Element)); Empty : constant Optional := (AF.Controlled with Element => null); ------------ -- Filter -- ------------ function Filter (This : Optional; Condition : Boolean) return Optional is (if Condition then This else Empty); -------------- -- Flat_Map -- -------------- function Flat_Map (This : Optional; Mapper : access function (Element : Optional) return Optional) return Optional is (if This.Has_Element and then Mapper /= null then Mapper (This) else This); ----------------- -- Has_Element -- ----------------- function Has_Element (This : Optional) return Boolean is (This.Element /= null); ----------- -- Image -- ----------- function Image (This : Optional) return String is (if not This.Has_Element then "[empty]" else "[value:" & Image (This.Element.all) & "]"); function Image (This : Const_Ref) return String is (Image (This.Ptr.all)); function Image (This : Var_Ref) return String is (Image (This.Ptr.all)); -------------- -- Is_Empty -- -------------- function Is_Empty (This : Optional) return Boolean is (not This.Has_Element); --------- -- Map -- --------- function Map (This : Optional; Mapper : access function (Element : Element_Type) return Element_Type) return Optional is (if This.Has_Element and then Mapper /= null then Unit (Mapper (This.Element.all)) else This); ------------- -- Or_Else -- ------------- function Or_Else (This : Optional; Default : Element_Type) return Element_Type is (if This.Has_Element then This.Element.all else Default); --------------- -- Reference -- --------------- function Reference (This : in out Optional) return Var_Ref is (Var_Ref'(Ptr => This.Element)); ---------- -- Unit -- ---------- function Unit (Element : Element_Type) return Optional is (Ada.Finalization.Controlled with Element => new Element_Type'(Element)); ----------- -- Value -- ----------- function Value (This : Optional) return Element_Type is (Element (This)); end Optional.Values; alire-1.2.1/deps/optional/src/optional.ads000066400000000000000000000001301406537031600204730ustar00rootroot00000000000000package Optional with Pure is -- Use Optional.Values to get started end Optional; pax_global_header00006660000000000000000000000064140650556330014521gustar00rootroot0000000000000052 comment=fe4e72e40786589a66d53662639f894fcdb3419c alire-1.2.1/deps/semantic_versioning/000077500000000000000000000000001406505563300176175ustar00rootroot00000000000000alire-1.2.1/deps/semantic_versioning/.github/000077500000000000000000000000001406505563300211575ustar00rootroot00000000000000alire-1.2.1/deps/semantic_versioning/.github/workflows/000077500000000000000000000000001406505563300232145ustar00rootroot00000000000000alire-1.2.1/deps/semantic_versioning/.github/workflows/build.yml000066400000000000000000000023571406505563300250450ustar00rootroot00000000000000name: build on: push: pull_request: paths-ignore: - 'doc/**' - '*.md' jobs: build: name: ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: - macos-latest - ubuntu-latest - windows-latest steps: - name: Check out repository uses: actions/checkout@v1 - name: Check out submodules run: git submodule update --init --recursive - name: Set up GNAT toolchain (FSF) if: matrix.os == 'ubuntu-latest' uses: ada-actions/toolchain@ce2021 with: distrib: fsf - name: Set up GNAT toolchain (Community 2021) if: matrix.os == 'windows-latest' uses: ada-actions/toolchain@ce2021 with: distrib: community - name: Set up GNAT toolchain (Community 2020) if: matrix.os == 'macos-latest' uses: ada-actions/toolchain@ce2020 with: distrib: community - name: Build on demand run: gprbuild -j0 -p -XSEMVER_BUILD_MODE=On_Demand - name: Build static lib run: gprbuild -j0 -p -XSEMVER_BUILD_MODE=Static_Lib - name: Build shared lib run: gprbuild -j0 -p -XSEMVER_BUILD_MODE=Shared_Lib - name: Run test programs run: bin/demo alire-1.2.1/deps/semantic_versioning/.gitignore000066400000000000000000000001011406505563300215770ustar00rootroot00000000000000*.ali *.o alire.lock # Generated folders bin/ config/ lib/ obj/ alire-1.2.1/deps/semantic_versioning/LICENSE000066400000000000000000001045051406505563300206310ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program 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. This program 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. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . alire-1.2.1/deps/semantic_versioning/README.md000066400000000000000000000032431406505563300211000ustar00rootroot00000000000000[![build](https://github.com/alire-project/semantic_versioning/workflows/build/badge.svg)](https://github.com/alire-project/semantic_versioning/actions) # Semantic_Versioning Semantic Versioning for the Ada language Implements the 2.0 specification found at http://semver.org/ ## Types Three types are provided: - `Semantic_Versioning.Version`, which stores a single semantic version (e.g., `"1.0.2-beta+build0bdf3"`). - `Semantic_Versioning.Basic.Version_Set`, which stores a single version restriction over the whole set of versions (e.g., `"~1.2"`), or a list of AND (`&`) restrictions (e.g., `"^1.0 & /=1.1"`). - `Semantic_Versioning.Extended.Version_Set`, which stores a general subset expressed with combinations of AND (`&`) and OR (`|`) logical operators. As in Ada, both cannot be mixed at the same level but can be combined with parentheses, e.g., `"(≥7 & ≤9) | ≥2018"`. ## Limitations 1. Wildcard version sets (`1.*`) are not yet supported, but for a single `*` which means "any version". 1. The special interpretation of caret and tilde for pre-1 versions that exists in some implementations is not applied, so they retain their usual meaning (compatibility within major/minor numbers). According to the Semver 2.0 spec, pre-1 releases do not offer any compatibility guarantees. ## Unicode By default, relational operators are accepted as plain ASCII sequences (`<=, >=, /=`) and as Unicode-encoded characters (`≤, ≥, ≠`). Unicode alternatives can be disabled in calls that accept textual input or produce corresponding output. ## Usage The public specifications are relatively small and intuitive. Check `semantic_versioning-demo.adb` for examples of use. alire-1.2.1/deps/semantic_versioning/alire.toml000066400000000000000000000004261406505563300216120ustar00rootroot00000000000000name = "semantic_versioning" version = "2.0-dev" description = "Semantic Versioning in Ada" licenses = "LGPL-3.0-only" authors = [ "Alejandro R. Mosteo" ] maintainers = [ "alejandro@mosteo.com", ] maintainers-logins = [ "mosteo", ] tags = ["semver", "semantic", "versioning"] alire-1.2.1/deps/semantic_versioning/grammar.txt000066400000000000000000000011321406505563300220030ustar00rootroot00000000000000Short names =========== V: version (without prefix subsetter) VS: version set (version with optional prefix subsetter) EVS: extended version set (with and/or ops) Grammar (after LR removal, with precedence mixing forbidden) ======= EVS ::= (EVS_Nested | VS) [list] EVS_Nested ::= '(' EVS ')' VS ::= V | OP V V ::= list ::= list_and | list_or list_and ::= '&' EVS_and list_or ::= '|' EVS_or EVS_and ::= (EVS_Nested | VS) [and_list] EVS_or ::= (EVS_Nested | VS) [or_list] OP ::= '<' | '>' etc alire-1.2.1/deps/semantic_versioning/semantic_versioning.gpr000066400000000000000000000032221406505563300243760ustar00rootroot00000000000000project Semantic_Versioning is for Create_Missing_Dirs use "True"; for Source_Dirs use ("src"); for Exec_Dir use "bin"; type Build_Modes is ("On_Demand", "Static_Lib", "Shared_Lib"); Build_Mode : Build_Modes := External ("SEMVER_BUILD_MODE", "On_Demand"); case Build_Mode is when "On_Demand" => for Main use ("semantic_versioning-demo.adb", "semantic_versioning-parser.adb", "semantic_versioning-extended-parser.adb"); for Object_Dir use "obj"; when "Static_Lib" => for Library_Kind use "static-pic"; for Library_Name use "semverada"; for Library_Dir use "lib"; for Object_Dir use "obj/static"; when "Shared_Lib" => for Library_Kind use "dynamic"; for Library_Name use "semverada"; for Library_Dir use "lib"; for Object_Dir use "obj/shared"; end case; package Pretty_Printer is for Switches ("ada") use ("--no-separate-is"); end Pretty_Printer; package Builder is for Switches ("ada") use ("-s", "-m", "-j0", "-g"); for Executable ("semantic_versioning-demo.adb") use "demo"; end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnat12", "-gnato", "-fstack-check", "-gnata"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; package Ide is for Vcs_Kind use "Git"; end Ide; package Linker is for Switches ("ada") use ("-g"); end Linker; end Semantic_Versioning; alire-1.2.1/deps/semantic_versioning/src/000077500000000000000000000000001406505563300204065ustar00rootroot00000000000000alire-1.2.1/deps/semantic_versioning/src/semantic_versioning-basic.adb000066400000000000000000000164731406505563300262160ustar00rootroot00000000000000with Ada.Characters.Handling; with Ada.Exceptions; with Ada.Strings.Fixed; with GNAT.Case_Util; package body Semantic_Versioning.Basic is Separator : constant Character := '&'; ------------------- -- To_Mixed_Case -- ------------------- function To_Mixed_Case (S : String) return String is begin return SMC : String := S do GNAT.Case_Util.To_Mixed (SMC); end return; end To_Mixed_Case; ----------------------- -- Image_Abbreviated -- ----------------------- function Image_Abbreviated (VS : Version_Set; Unicode : Boolean := False; Implicit_Equal : Boolean := False) return String is function Inner_Image (VS : Version_Set) return String is Cond : constant Restriction := VS.First_Element; Remain : Version_Set := VS; begin Remain.Delete_First; return Operator_Image (Cond, Unicode, Implicit_Equal) & (if VS.Length > Natural'(1) then " " & Separator & " " & Inner_Image (Remain) else ""); end Inner_Image; begin if VS.Is_Empty then return "*"; else return Inner_Image (VS); end if; end Image_Abbreviated; --------------- -- Image_Ada -- --------------- function Image_Ada (VS : Version_Set) return String is function Inner_Image (VS : Version_Set) return String is Cond : constant Restriction := VS.First_Element; Remain : Version_Set := VS; begin Remain.Delete_First; return To_Mixed_Case (Cond.Condition'Img) & " (" & Image (Cond.On_Version) & ")" & (if VS.Length > Natural'(1) then " and " & Inner_Image (Remain) else ""); end Inner_Image; begin if VS.Is_Empty then return "Any"; else return Inner_Image (VS); end if; end Image_Ada; ----------- -- Is_In -- ----------- function Is_In (V : Version; VS : Version_Set) return Boolean is begin for R of VS loop if not Satisfies (V, R) then return False; end if; end loop; return True; end Is_In; ----------- -- Parse -- ----------- function Parse (S : String; Relaxed : Boolean := False; Unicode : Boolean := True) return Result is use Ada.Strings; use Ada.Strings.Fixed; Err_Empty : constant String := "Expression is empty"; Prev : Integer := S'First; Next : Integer := Prev + 1; Set : Version_Set; begin -- Check for emptiness first: if Trim (S, Side => Both) = "" then return Result'(Valid => False, Length => Err_Empty'Length, Error => Err_Empty); end if; loop while Next <= S'Last and then S (Next) /= Separator loop Next := Next + 1; end loop; exit when Prev > S'Last; declare Single_Set : constant Version_Set := To_Set (Trim (S (Prev .. Next - 1), Side => Both), Relaxed => Relaxed, Unicode => Unicode); begin Prev := Next + 1; Next := Prev + 1; Set := Set and Single_Set; end; end loop; return Result'(Valid => True, Length => 0, Set => Set); exception when E : others => declare Error : constant String := Ada.Exceptions.Exception_Message (E); begin return Result'(Valid => False, Length => Error'Length, Error => Error); end; end Parse; --------------- -- Satisfies -- --------------- function Satisfies (V : Version; R : Restriction) return Boolean is begin case R.Condition is when At_Least => return V = R.On_Version or else R.On_Version < V; when At_Most => return V < R.On_Version or else V = R.On_Version; when Exactly => return V = R.On_Version; when Except => return V /= R.On_Version; when Within_Major => return (R.On_Version < V or else R.On_Version = V) and then R.On_Version.Major = V.Major; when Within_Minor => return (R.On_Version < V or else R.On_Version = V) and Then R.On_Version.Major = V.Major and then R.On_Version.Minor = V.Minor; end case; end Satisfies; ------------ -- To_Set -- ------------ function To_Set (S : Version_String; Relaxed : Boolean := False; Unicode : Boolean := True) return Version_Set is subtype Numbers is Character range '0' .. '9'; -- Convenience to remove the operator, whatever its length function Remainder (S : String; Pattern : String) return String is (S (S'First + Pattern'Length .. S'Last)); package ACH renames Ada.Characters.Handling; begin -- Special cases first if ACH.To_Lower (S) = "any" or else S = "*" then return Any; elsif S = "" then raise Malformed_Input with "empty string"; elsif S (S'First) in Numbers then return Exactly (Parse (S, Relaxed)); end if; -- Simple cases declare Op : constant Character := S (S'First); Version : constant String := S (S'First + 1 .. S'Last); begin case Op is when '=' => return Exactly (Parse (Version, Relaxed)); when '^' => return Within_Major (Parse (Version, Relaxed)); when '~' => return Within_Minor (Parse (Version, Relaxed)); when others => null; -- Check next cases end case; end; -- Rest of cases if Begins_With (S, "/=") then return Except (Parse (Remainder (S, "/="), Relaxed)); elsif Unicode and then Begins_With (S, "≠") then return Except (Parse (Remainder (S, "≠"), Relaxed)); elsif Begins_With (S, ">=") then return At_Least (Parse (Remainder (S, ">="), Relaxed)); elsif Unicode and then Begins_With (S, "≥") then return At_Least (Parse (Remainder (S, "≥"), Relaxed)); elsif Begins_With (S, "<=") then return At_most (Parse (Remainder (S, "<="), Relaxed)); elsif Unicode and then Begins_With (S, "≤") then return At_Most (Parse (Remainder (S, "≤"), Relaxed)); elsif Begins_With (S, ">") then return More_Than (Parse (Remainder (S, ">"), Relaxed)); elsif Begins_With (S, "<") then return Less_Than (Parse (Remainder (S, "<"), Relaxed)); end if; -- All others raise Malformed_Input with "invalid set: " & S; end To_Set; ----------- -- Value -- ----------- function Value (S : String; Relaxed : Boolean := False; Unicode : Boolean := True) return Version_Set is R : constant Result := Parse (S, Relaxed => Relaxed, Unicode => Unicode); begin if R.Valid then return R.Set; else raise Malformed_Input with R.Error; end if; end Value; end Semantic_Versioning.Basic; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning-basic.ads000066400000000000000000000160241406505563300262270ustar00rootroot00000000000000private with Ada.Containers.Vectors; package Semantic_Versioning.Basic with Preelaborate is -- Collections of versions (usually a compatible subset). These basic sets -- only allow "and" conditions. type Version_Set is tagged private; type Result (Valid : Boolean; Length : Natural) is record case Valid is when True => Set : Version_Set; when False => Error : String (1 .. Length); end case; end record; Any : constant Version_Set; function Image_Ada (VS : Version_Set) return String; -- Ada-like textual representation. -- E.g., "Within_Major ("1.0.0") and Except ("1.0.5")" function Image_Abbreviated (VS : Version_Set; Unicode : Boolean := False; Implicit_Equal : Boolean := False) return String; -- '&' separated; e.g. "^1.0.0 & ≠1.0.5" -- If Unicode, the operator can be ≠, etc -- If implicit equal, "=" will be omitted function Image (VS : Version_Set; Unicode : Boolean := False; Implicit_Equal : Boolean := False) return String renames Image_Abbreviated; function To_Set (S : Version_String; Relaxed : Boolean := False; Unicode : Boolean := True) return Version_Set; -- Parses a single version set from a single restriction representation: -- The following operators are recognized: -- = /= ≠ > >= ≥ < ≤ <= ~ ^, with the meanings given in the following functions. -- In addition, a plain version is equivalent to =, and "any", "*" is any version. function Parse (S : String; Relaxed : Boolean := False; Unicode : Boolean := True) return Result; -- Parse an expression possibly containing several sets, "&"-separated. function Value (S : String; Relaxed : Boolean := False; Unicode : Boolean := True) return Version_Set; -- As Parse, but raises Malformed_Error with Error as message instead of -- returning a Result. function At_Least (V : Version) return Version_Set; -- >= ≥ function At_Most (V : Version) return Version_Set; -- <= ≤ function Less_Than (V : Version) return Version_Set; -- < function More_Than (V : Version) return Version_Set; -- > function Exactly (V : Version) return Version_Set; -- = function Except (V : Version) return Version_Set; -- /= ≠ function Within_Major (V : Version) return Version_Set; -- The "^" caret operator, any version from V up to Next_Major (V) function Within_Minor (V : Version) return Version_Set; -- Similar to "~" tilde operator, any version from V up to Next_Minor (V) -- BUT note that it is always up to minor (unlike usual ~ implementations) function "and" (VS1, VS2 : Version_Set) return Version_Set; function Contains (VS : Version_Set; V : Version) return Boolean; function Is_In (V : Version; VS : Version_Set) return Boolean; function Satisfies (V : Version; VS : Version_Set) return Boolean renames Is_In; function Is_Single_Version (VS : Version_Set) return Boolean; -- True when VS contains a single Exactly restriction -- Iteration over version sets contents type Conditions is (At_Least, At_Most, Exactly, Except, Within_Major, Within_Minor); function Operator (Condition : Conditions; Unicode : Boolean := False; Implicit_Equal : Boolean := False) return String; -- Returns a short string with the visible operator: =, /=, ~, ... -- If Unicode, the operator can be ≠, etc -- If implicit equal, "=" will be omitted type Restriction is private; function Operator_Image (R : Restriction; Unicode : Boolean := False; Implicit_Equal : Boolean := False) return String; -- Image using operator (e.g., <=1.0.1, ~2.0.0, /=0.1.2) -- See Image (Set) for Unicode, Implicit_Equal meaning function Condition (R : Restriction) return Conditions; function On_Version (R : Restriction) return Version; function Length (VS : Version_Set) return Natural; -- 0 is Any! function Element (VS : Version_Set; I : Positive) return Restriction; private type Restriction is record Condition : Conditions; On_Version : Version; end record; function Condition (R : Restriction) return Conditions is (R.Condition); function On_Version (R : Restriction) return Version is (R.On_Version); function Satisfies (V : Version; R : Restriction) return Boolean; package Restrictions is new Ada.Containers.Vectors (Positive, Restriction); type Version_Set is new Restrictions.Vector with null record; -- Generator functions function At_Least (V : Version) return Version_Set is (To_Vector ((At_Least, V), 1)); function At_Most (V : Version) return Version_Set is (To_Vector ((At_Most, V), 1)); function Exactly (V : Version) return Version_Set is (To_Vector ((Exactly, V), 1)); function Except (V : Version) return Version_Set is (To_Vector ((Except, V), 1)); function Within_Major (V : Version) return Version_Set is (To_Vector ((Within_Major, V), 1)); function Within_Minor (V : Version) return Version_Set is (To_Vector ((Within_Minor, V), 1)); -- Secondary functions function Less_Than (V : Version) return Version_Set is (At_Most (V) and Except (V)); function More_Than (V : Version) return Version_Set is (At_Least (V) and Except (V)); Any : constant Version_Set := (Restrictions.Empty_Vector with null record); function "and" (VS1, VS2 : Version_Set) return Version_Set is (VS1 & VS2); function Length (VS : Version_Set) return Natural is (Natural (Restrictions.Vector (VS).Length)); function Element (VS : Version_Set; I : Positive) return Restriction is (VS (I)); function Operator (Condition : Conditions; Unicode : Boolean := False; Implicit_Equal : Boolean := False) return String is (case Condition is when At_Least => (if Unicode then "≥" else ">="), when At_Most => (if Unicode then "≤" else "<="), when Exactly => (if Implicit_Equal then "" else "="), when Except => (if Unicode then "≠" else "/="), when Within_Major => "^", when Within_Minor => "~"); function Operator_Image (R : Restriction; Unicode : Boolean := False; Implicit_Equal : Boolean := False) return String is (Operator (R.Condition, Unicode, Implicit_Equal) & Image (R.On_Version)); function Contains (VS : Version_Set; V : Version) return Boolean is (Is_In (V, VS)); function Is_Single_Version (VS : Version_Set) return Boolean is (VS.Length = 1 and then VS.First_Element.Condition = Exactly); end Semantic_Versioning.Basic; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning-demo.adb000066400000000000000000000150611406505563300260510ustar00rootroot00000000000000with GNAT.IO; use GNAT.IO; with Semantic_Versioning.Basic; with Semantic_Versioning.Extended; procedure Semantic_Versioning.Demo is V1_0_0 : constant Version := New_Version (1); V1_1_0 : constant Version := New_Version (1, 1); V1_1_1 : constant Version := New_Version (1, 1, 1); V1_0_0_Alpha_Img : constant String := "1.0.0-alpha"; V1_0_0_Alpha : constant Version := New_Version (V1_0_0_Alpha_Img); V1_Beta : constant Version := New_Version ("1-beta+6699dd338e"); use Basic; use all type Extended.Version_Set; package B renames Basic; package X renames Extended; begin -- Builder pragma Assert (New_Version (1, 2, 3) = New_Version ("1.2.3")); -- Restrictions pragma Assert (Satisfies (V1_0_0, At_Least (V1_0_0))); pragma Assert (Satisfies (V1_0_0, At_Most (V1_0_0))); pragma Assert (Satisfies (V1_0_0, Exactly (V1_0_0))); pragma Assert (not Satisfies (V1_0_0, Less_Than (V1_0_0))); pragma Assert (not Satisfies (V1_0_0, Except (V1_0_0))); pragma Assert (Satisfies (V1_0_0, Less_Than (V1_1_0))); pragma Assert (Satisfies (V1_0_0, Except (V1_1_0))); pragma Assert (Satisfies (V1_1_0, At_Least (V1_0_0) and At_Most (V1_1_1))); pragma Assert (Satisfies (V ("1.1.9"), Within_Major (V ("1.1.0")))); pragma Assert (not Satisfies (V ("1.1.9"), Within_Major (V ("2.0.0-alpha")))); pragma Assert (not Satisfies (V ("2.0.0-alpha"), Within_Major (V ("1.0.0")))); pragma Assert (Satisfies (V ("1.1.9"), Within_Minor (V ("1.1.0")))); pragma Assert (not Satisfies (V ("1.1.9"), Within_Minor (V ("1.2.0-alpha")))); pragma Assert (not Satisfies (V ("1.2.0-alpha"), Within_Minor (V ("1.1.0")))); -- Reconstruction pragma Assert (Image (V1_0_0_Alpha) = V1_0_0_Alpha_Img); -- Ordering pragma Assert (V1_0_0_Alpha < V1_0_0); pragma Assert (not (V1_0_0 < V1_0_0_Alpha)); pragma Assert (V1_0_0_Alpha < V1_1_0); pragma Assert (V1_0_0_Alpha < V1_Beta); pragma Assert (V1_0_0 < V1_1_0); pragma Assert (V1_1_0 < V1_1_1); pragma Assert (not (V1_1_0 < V1_1_0)); pragma Assert (V1_0_0 < Next_Patch (V1_1_0)); pragma Assert (V1_0_0 < Next_Minor (V1_1_0)); pragma Assert (V1_0_0 < Next_Major (V1_1_0)); -- Build info is not taken into account: pragma Assert (not (V ("1.0.0+build0") < V ("1.0.0+build1"))); pragma Assert (not (V ("1.0.0+build1") < V ("1.0.0+build0"))); -- Field comparisons in the Pre-release part (taken from semver.org): pragma Assert (V ("1.0.0-alpha") < V ("1.0.0-alpha.1")); pragma Assert (V ("1.0.0-alpha.1") < V ("1.0.0-alpha.beta")); pragma Assert (V ("1.0.0-alpha.beta") < V ("1.0.0-beta")); pragma Assert (V ("1.0.0-beta") < V ("1.0.0-beta.2")); pragma Assert (V ("1.0.0-beta.2") < V ("1.0.0-beta.11")); pragma Assert (V ("1.0.0-beta.11") < V ("1.0.0-rc.1")); pragma Assert (V ("1.0.0-rc.1") < V ("1.0.0")); -- Next-ing pragma Assert (V ("1.1.1") = Next_Patch (V1_1_0)); pragma Assert (V ("1.2.0") = Next_Minor (V1_1_0)); pragma Assert (V ("2.0.0") = Next_Major (V1_1_0)); -- Same version pragma Assert (V ("1.0.0") = V ("1.0.0")); pragma Assert (V ("1.0.0") = V ("1.0.0+buildmetadata")); pragma Assert (V ("1.0.0") /= V ("1.0.0-prerelease")); -- To Set from string pragma Assert (Basic.Any = To_Set ("any")); pragma Assert (Basic.Any = To_Set ("*")); pragma Assert (Exactly (V1_0_0) = To_Set ("1.0.0")); pragma Assert (Exactly (V1_0_0) = To_Set ("=1.0.0")); pragma Assert (Except (V1_0_0) = To_Set ("/=1.0.0")); pragma Assert (Except (V1_0_0) = To_Set ("≠1.0.0")); pragma Assert (At_Least (V1_0_0) = To_Set (">=1.0.0")); pragma Assert (At_Least (V1_0_0) = To_Set ("≥1.0.0")); pragma Assert (At_Most (V1_0_0) = To_Set ("<=1.0.0")); pragma Assert (At_Most (V1_0_0) = To_Set ("≤1.0.0")); pragma Assert (More_Than (V1_0_0) = To_Set (">1.0.0")); pragma Assert (Less_Than (V1_0_0) = To_Set ("<1.0.0")); -- Basic expressions pragma Assert (B.Is_In (V ("1.0"), B.Value ("^1 & <2"))); pragma Assert (not B.Is_In (V ("1.1"), B.Value ("^1 & <2 & /=1.1"))); pragma Assert (not B.Parse ("/= 1").Valid); -- Because space pragma Assert (not B.Parse ("<1|>2").Valid); -- Because | pragma Assert (not B.Parse ("<1 | >2").Valid); -- Because | pragma Assert (not B.Parse ("&1").Valid); pragma Assert (not B.Parse ("&").Valid); pragma Assert (B.Value ("*").Image = B.Any.Image); pragma Assert (B.Value ("*").Image = B.Value ("any").Image); -- Extended expressions pragma Assert (X.Is_In (V ("1.0"), X.Value ("1"))); pragma Assert (X.Is_In (V ("1.0"), X.Value ("2|1"))); pragma Assert (X.Is_In (V ("1.1"), X.Value ("2|^1"))); pragma Assert (not X.Is_In (V ("1.1"), X.Value ("^1&/=1.1"))); pragma Assert (X.Is_In (V ("1.2"), X.Value ("^2|/=1.1"))); pragma Assert (X.Is_In (V ("1"), X.Value ("((4-rc))|(^3&~3)|^2+build|=1"))); pragma Assert (not X.Parse ("(").Valid); pragma Assert (not X.Parse ("()").Valid); pragma Assert (not X.Parse ("(1").Valid); pragma Assert (not X.Parse ("1&2|3").Valid); pragma Assert (not X.Parse ("&1").Valid); pragma Assert (not X.Parse ("&").Valid); pragma Assert (X.Parse ("1&(2|3)").Valid); pragma Assert (X.Parse ("((1&(2|3)))").Valid); pragma Assert (X.Value ("*").Image = X.Any.Image); pragma Assert (X.Value ("*").Image = X.Value ("any").Image); -- Simplifications within extended expressions pragma Assert (X.Value ("1") = (X.Value ("1") and X.Value ("1"))); pragma Assert (X.Value ("*") = (X.Value ("*") or X.Value ("1.0"))); pragma Assert (X.Value ("1.0") = (X.Value ("*") and X.Value ("1.0"))); pragma Assert ((X.Value ("1") and (X.Value ("2") and X.Value ("1"))) = (X.Value ("2") and X.Value ("1"))); pragma Assert ((X.Value ("1") or (X.Value ("2") or (X.Value ("3") or X.Value ("1")))) = (X.Value ("2") or (X.Value ("3") or X.Value ("1")))); -- X + Unicode pragma Assert (X.Is_In (V ("1.1"), X.Value ("≠1"))); pragma Assert (X.Is_In (V ("1.1"), X.Value ("≥1"))); pragma Assert (X.Is_In (V ("1.1"), X.Value ("≤1.1"))); -- Extended operators pragma Assert (((X.Value (">=1") and X.Value ("<2")) or X.Value ("=3")) = X.Value ("(>=1 & <2)|=3")); -- Updatable conversions pragma Assert (Updatable (V ("0.0.2")) = X.Value ("~0.0.2")); pragma Assert (Updatable (V ("0.3.2")) = X.Value ("~0.3.2")); pragma Assert (Updatable (V ("3.0.2")) = X.Value ("^3.0.2")); Put_Line ("OK"); end Semantic_Versioning.Demo; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning-expressions.ads000066400000000000000000000062621406505563300275330ustar00rootroot00000000000000with Semantic_Versioning.Basic; generic type LH (<>) is private; type Result (<>) is private; with function Build_Condition (L : LH; VS : Basic.Version_Set) return Result; Strict : Boolean := False; -- When parsing strings package Semantic_Versioning.Expressions with Preelaborate is -- Helper package to build more naturally-looking expressions -- Direct comparison against versions: LH >= "1.0", LH >= V_1.0 function "<" (L : LH; R : Version) return Result; function "<" (L : LH; R : String) return Result; function "<=" (L : LH; R : Version) return Result; function "<=" (L : LH; R : String) return Result; function "=" (L : LH; R : Version) return Result; function "=" (L : LH; R : String) return Result; function ">=" (L : LH; R : Version) return Result; function ">=" (L : LH; R : String) return Result; function ">" (L : LH; R : Version) return Result; function ">" (L : LH; R : String) return Result; function "/=" (L : LH; R : Version) return Result; function "/=" (L : LH; R : String) return Result; generic type RH (<>) is private; with function Get_Version (R : RH) return Version; package Against is -- Obtain version of some other type against which we compare function "<" (L : LH; R : RH) return Result; function "<=" (L : LH; R : RH) return Result; function "=" (L : LH; R : RH) return Result; function ">=" (L : LH; R : RH) return Result; function ">" (L : LH; R : RH) return Result; function "/=" (L : LH; R : RH) return Result; private function "<" (L : LH; R : RH) return Result is (L < Get_Version (R)); function "<=" (L : LH; R : RH) return Result is (L <= Get_Version (R)); function "=" (L : LH; R : RH) return Result is (L = Get_Version (R)); function ">=" (L : LH; R : RH) return Result is (L >= Get_Version (R)); function ">" (L : LH; R : RH) return Result is (L > Get_Version (R)); function "/=" (L : LH; R : RH) return Result is (L /= Get_Version (R)); end Against; private use Basic; function "<" (L : LH; R : Version) return Result is (Build_Condition (L, Less_Than (R))); function "<" (L : LH; R : String) return Result is (L < Parse (R, not Strict)); function "<=" (L : LH; R : Version) return Result is (Build_Condition (L, At_Most (R))); function "<=" (L : LH; R : String) return Result is (L <= Parse (R, not Strict)); function "=" (L : LH; R : Version) return Result is (Build_Condition (L, Exactly (R))); function "=" (L : LH; R : String) return Result is (L = Parse (R, not Strict)); function ">=" (L : LH; R : Version) return Result is (Build_Condition (L, At_Least (R))); function ">=" (L : LH; R : String) return Result is (L >= Parse (R, not Strict)); function ">" (L : LH; R : Version) return Result is (Build_Condition (L, More_Than (R))); function ">" (L : LH; R : String) return Result is (L > Parse (R, not Strict)); function "/=" (L : LH; R : Version) return Result is (Build_Condition (L, Except (R))); function "/=" (L : LH; R : String) return Result is (L /= Parse (R, not Strict)); end Semantic_Versioning.Expressions; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning-extended-parser.adb000066400000000000000000000014331406505563300302150ustar00rootroot00000000000000with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; -- Parse the first argument and re-emit its image. procedure Semantic_Versioning.Extended.Parser is begin if Argument_Count /= 1 then Put_Line ("Need exactly one argument (which is an extended version set)!"); return; end if; declare Result : constant Extended.Result := Extended.Parse (Argument (1)); begin if Result.Valid then Put_Line ("OK"); Put_Line (Image (Result.Set)); Put_Line (Synthetic_Image (Result.Set)); else Put_Line ("Parse error: " & Result.Error); end if; exception when Malformed_Input => Put_Line ("Uh oh... that was not a nice version!"); end; end Semantic_Versioning.Extended.Parser; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning-extended.adb000066400000000000000000000430031406505563300267220ustar00rootroot00000000000000with Ada.Characters.Handling; with Ada.Exceptions; use Ada.Exceptions; with GNAT.IO; use GNAT.IO; package body Semantic_Versioning.Extended is package ACH renames Ada.Characters.Handling; use type Ada.Containers.Count_Type; Debug : constant Boolean := False; ----------- -- Trace -- ----------- procedure Trace (Str : String) is begin if Debug then Put_Line (Str); end if; end Trace; type List_Kinds is (Any, Anded, Ored); -- Used to unify a few productions by parameterizing one. subtype Concrete_List_Kinds is List_Kinds range Anded .. Ored; Concrete_Images : constant array (Concrete_List_Kinds) of Character := (Anded => '&', Ored => '|'); -- Simpler tree manipulation ----------------- -- Root_Cursor -- ----------------- function Root_Cursor (Leaf : Version_Set) return Trees.Cursor is begin return Trees.First_Child (Leaf.Set.Root); end Root_Cursor; -------------- -- New_Leaf -- -------------- function New_Leaf (BVS : Basic.Version_Set; Img : String) return Version_Set is VS : Version_Set; begin VS.Image := To_Unbounded_String (Img); VS.Set.Append_Child (VS.Set.Root, Any_Node'(Kind => Leaf, VS => BVS)); Trace ("Creating leaf: " & Img); return VS; end New_Leaf; -------------- -- New_Pair -- -------------- function New_Pair (L, R : Version_Set; Kind : Concrete_List_Kinds) return Version_Set is Link : constant Any_Node := (case Kind is when Anded => (Kind => Anded), when Ored => (Kind => Ored)); -- Must be static expr. Link_Tree : Version_Set; Link_Pos : Trees.Cursor; -------------- -- New_Tree -- -------------- function New_Tree (Pos : Trees.Cursor) return Version_Set is -- Create a temporary version set with this subtree, so it can be -- compared via synthetic image. Tree : Trees.Tree; begin Trees.Copy_Subtree (Target => Tree, Parent => Tree.Root, Before => Trees.First_Child (Tree.Root), Source => Pos); return Version_Set'(Set => Tree, Image => UStrings.Null_Unbounded_String); end New_Tree; -------------- -- Contains -- -------------- function Contains (Pos : Trees.Cursor; VS : Version_Set) return Boolean is use Trees; Pos_Kind : constant Kinds := Element (Pos).Kind; begin -- Check subtrees for a match with the same operation for Child in Iterate_Subtree (Pos) loop if not Is_Root (Parent (Child)) and then -- Root lacks operation Pos_Kind = Element (Parent (Child)).Kind -- Operation matches then if New_Tree (Child) = VS then return True; end if; end if; end loop; return False; end Contains; begin -- See if this can be simplified, starting with trivial simplifications if L = R then return L; elsif Kind = Ored and then (L = Any or R = Any) then return Any; elsif Kind = Anded and then L = Any then return R; elsif Kind = Anded and then R = Any then return L; end if; -- Recursive simplifications if Contains (L.Root_Cursor, R) then return L; elsif Contains (R.Root_Cursor, L) then return R; end if; -- Proceed with construction Link_Tree.Set.Append_Child (Link_Tree.Set.Root, Link); Link_Pos := Trees.First_Child (Link_Tree.Set.Root); Link_Tree.Set.Copy_Subtree (Parent => Link_Pos, Before => Trees.No_Element, Source => Root_Cursor (L)); Link_Tree.Set.Copy_Subtree (Parent => Link_Pos, Before => Trees.No_Element, Source => Root_Cursor (R)); Link_tree.Image := "(" & L.Image & ") " & Concrete_Images (Kind) & " (" & R.Image & ")"; return Link_Tree; end New_Pair; --------- -- Any -- --------- function Any return Version_Set is (To_Extended (Basic.Any)); ------------ -- Is_Any -- ------------ function Is_Any (VS : Version_Set) return Boolean is (Vs = Any); --------- -- "=" -- --------- function "=" (L, R : Version_Set) return Boolean is (L.Synthetic_Image = R.Synthetic_Image); ----------- -- "and" -- ----------- function "and" (L, R : Version_Set) return Version_Set is (New_Pair (L, R, Anded)); ---------- -- "or" -- ---------- function "or" (L, R : Version_Set) return Version_Set is (New_Pair (L, R, Ored)); ----------- -- Is_In -- ----------- function Is_In (V : Version; VS : Version_Set) return Boolean is ----------- -- Is_In -- ----------- function Is_In (Pos : Trees.Cursor) return Boolean is Node : Any_Node renames Trees.Element (Pos); begin case Node.Kind is when Leaf => Trace ("Leaf: " & Basic.Image_Abbreviated (Node.Vs) & " " & Basic.Is_In (V, Node.VS)'Img); return Basic.Is_In (V, Node.VS); when Anded => return OK : Boolean := True do Trace ("AND children count:" & Trees.Child_Count (Pos)'Img); for Child in VS.Set.Iterate_Children (Pos) loop OK := OK and then Is_In (Child); end loop; end return; when Ored => Trace ("OR children count:" & Trees.Child_Count (Pos)'Img); return OK : Boolean := False do for Child in VS.Set.Iterate_Children (Pos) loop OK := OK or else Is_In (Child); end loop; end return; end case; end Is_In; begin if VS.Set.Is_Empty then Trace ("Is_In: EMPTY"); return False; else return Is_In (Trees.First_Child (VS.Set.Root)); end if; end Is_In; ----------------------- -- Is_Single_Version -- ----------------------- function Is_Single_Version (VS : Version_Set) return Boolean is (Trees.Child_Count (VS.Set.Root) = 1 and then Trees.Element (Root_Cursor (VS)).Kind = Leaf and then Basic.Is_Single_Version (Trees.Element (Root_Cursor (VS)).VS)); ----------- -- Image -- ----------- function Image (VS : Version_Set) return String is (To_String (VS.Image)); -------------- -- Simplify -- -------------- function Simplify (VS : Version_Set) return Version_Set is (VS); -- This is a fake function so it can be explained in the spec. -- Simplifications occur at New_Pair, to avoid the problem of the -- lost original image of subtrees --------------------- -- Synthetic_Image -- --------------------- function Synthetic_Image (VS : Version_Set; Unicode : Boolean := False) return String is function Img (Pos : Trees.Cursor) return String is Node : Any_Node renames Trees.Element (Pos); function List_Img return String is List : Ustring; I : Trees.Cursor := Trees.First_Child (Pos); First : Boolean := True; begin while Trees.Has_Element (I) loop if First then First := False; else List := List & Concrete_Images (List_Kinds'Value (Node.Kind'Img)); end if; if Trees.Element (I).Kind not in Leaf | Node.Kind then List := List & "("; end if; List := List & Img (I); if Trees.Element (I).Kind not in Leaf | Node.Kind then List := List & ")"; end if; I := Trees.Next_Sibling (I); end loop; return To_String (List); end List_Img; begin case Node.Kind is when Leaf => return Basic.Image_Abbreviated (Node.VS, Unicode => Unicode); when Anded | Ored => return List_Img; end case; end Img; begin if VS.Set.Is_Empty then return "(empty extended version set)"; else return Img (Trees.First_Child (VS.Set.Root)); end if; end Synthetic_Image; ----------------- -- To_Extended -- ----------------- function To_Extended (BVS : Basic.Version_Set) return Version_Set is (New_Leaf (BVS, Basic.Image_Abbreviated (BVS))); ----------- -- Parse -- ----------- function Parse (Str : String; Relaxed : Boolean := False; Unicode : Boolean := True) return Result is -- See grammar.txt for the recursive parser being implemented here. -- Since there is no need to backtrack, we can store here the partial -- solution: Parse_Error : exception; type Tokens is (Ampersand, Lparen, Rparen, Number, Pipe, Unknown, VS, End_Of_Input); I : Integer := Str'First; -- Next char to process Err : Unbounded_String; ----------- -- Error -- ----------- -- Set error and raise procedure Error (Msg : String; With_Pos : Boolean := True) is Extended_Msg : constant String := (if With_Pos then Msg & " (at char" & Integer'(I - Str'First + 1)'Img & ")" else Msg); begin Err := To_Unbounded_String (Extended_Msg); raise Parse_Error; end Error; ----------- -- Match -- ----------- procedure Match (C : Character) is begin if I > Str'Last then Error ("Incomplete expression when expecting character: " & C); elsif Str (I) /= C then Error ("Got a '" & Str (I) & "' when expecting a '" & C & "'"); else Trace ("Matching " & C & " at pos" & I'Img); I := I + 1; end if; end Match; ------------------- -- Next_Basic_VS -- ------------------- -- Get all characters until something that is not a version set function Next_Basic_VS return String is Last : Natural := I; begin if I > Str'Last then Error ("Incomplete expression when expecting a version set"); end if; while Last <= Str'Last and then Str (Last) not in '&' | '|' | ')' | ' ' | '(' loop Last := Last + 1; end loop; if Last = I then Error ("Empty version set substring"); end if; return Substr : constant String := Str (I .. Last - 1) do I := Last; end return; end Next_Basic_VS; ---------------- -- Next_Token -- ---------------- function Next_Token (Skip_Whitespace : Boolean := True) return Tokens is function Internal return Tokens is begin if I > Str'Last then return End_Of_Input; end if; if Skip_Whitespace then while I <= Str'Last and then Str (I) = ' ' loop I := I + 1; end loop; end if; if I > Str'Last then return End_Of_Input; end if; if Begins_With_Relational (Str (I .. Str'Last), Unicode) then return VS; end if; case Str (I) is when '&' => return Ampersand; when '(' => return Lparen; when ')' => return Rparen; when '0' .. '9' => return Number; when '|' => return Pipe; when '<' | '>' | '=' | '/' | '~' | '^' => return VS; -- already checked above, but... when others => return Unknown; end case; end Internal; begin return T : constant Tokens := Internal do Trace ("Next token: " & T'Img); end return; end Next_Token; function Prod_EVS_Nested return Version_Set; function Prod_List (Head : Version_Set; Kind : List_Kinds) return Version_Set; function Prod_VS return Version_Set; -------------- -- Prod_EVS -- -------------- function Prod_EVS (List_Kind : List_Kinds) return Version_Set is Next : Version_Set; begin Trace ("Prod EVS"); case Next_Token is when Lparen => Next := Prod_EVS_Nested; when Number | VS => Next := Prod_VS; when End_Of_Input => Error ("Incomplete expression"); return Empty_Set; -- Unreachable, Error raises. when others => Error ("Unexpected symbol: " & Str (I)); return Empty_Set; -- Unreachable, Error raises. end case; -- Optional continuation list if Next_Token in Ampersand | Pipe then Trace ("Prod EVS: optional list present"); return Prod_List (Next, List_Kind); else Trace ("Prod EVS: optional list missing"); return Next; end if; end Prod_EVS; --------------------- -- Prod_EVS_Nested -- --------------------- function Prod_EVS_Nested return Version_Set is begin Trace ("Prod EVS Nested"); Match ('('); return VS : Version_Set := Prod_EVS (Any) do VS.Image := '(' & VS.Image & ')'; Match (')'); end return; end Prod_EVS_Nested; --------------- -- Prod_List -- --------------- function Prod_List (Head : Version_Set; Kind : List_Kinds) return Version_Set is -------------------- -- Check_Mismatch -- -------------------- procedure Check_Mismatch is begin if I <= Str'Last then if (Kind = Anded and then Str (I) = '|') or else (Kind = Ored and then Str (I) = '&') then Error ("Cannot mix '&' and '|' operators, use parentheses"); end if; end if; end Check_Mismatch; begin Trace ("Prod List " & Kind'Img & " with head " & Image (Head)); case Kind is when Any => case Next_Token is when Ampersand => return Prod_List (Head, Anded); when Pipe => return Prod_List (Head, Ored); when others => Error ("Unexpected list concatenator: " & Str (I)); return Empty_Set; -- Unreachable, Error raises. end case; when Anded => Check_Mismatch; Match ('&'); return New_Pair (Head, Prod_EVS (Anded), Anded); when Ored => Check_Mismatch; Match ('|'); return New_Pair (Head, Prod_EVS (Ored), Ored); end case; end Prod_List; ------------- -- Prod_VS -- ------------- function Prod_VS return Version_Set is BVS_Image : constant String := Next_Basic_VS; begin Trace ("Prod VS"); return New_Leaf (Basic.To_Set (S => BVS_Image, Relaxed => Relaxed, Unicode => Unicode), BVS_Image); exception when Malformed_Input => Error ("Malformed basic version set: " & BVS_Image); return Empty_Set; -- Unreachable end Prod_VS; begin -- Special cases first if ACH.To_Lower (Str) = "any" or else Str = "*" then return New_Valid_Result (To_Extended (Basic.Any)); end if; return Set : Result := New_Valid_Result (Prod_EVS (Any)) do if Next_Token /= End_Of_Input then Error ("Unexpected input after parsing version set: " & Str (I)); else Set.Set.Image := To_Unbounded_String (Str); end if; end return; exception when E : Parse_Error => if Debug then Put_Line (Exception_Information (E)); end if; return (Valid => False, Length => Length (Err), Error => To_String (Err)); end Parse; ----------- -- Value -- ----------- function Value (Str : String; Relaxed : Boolean := False; Unicode : Boolean := True) return Version_Set is R : constant Result := Parse (Str => Str, Relaxed => Relaxed, Unicode => Unicode); begin if R.Valid then return R.Set; else raise Malformed_Input with R.Error; end if; end Value; end Semantic_Versioning.Extended; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning-extended.ads000066400000000000000000000064271406505563300267540ustar00rootroot00000000000000with Ada.Containers.Multiway_Trees; with Ada.Strings.Unbounded; with Semantic_Versioning.Basic; package Semantic_Versioning.Extended with Preelaborate is type Version_Set is tagged private; function Any return Version_Set; function Is_Any (VS : Version_Set) return Boolean; -- Same as VS = Any function "=" (L, R : Version_Set) return Boolean; type Result (Valid : Boolean; Length : Natural) is record case Valid is when True => Set : Version_Set; when False => Error : String (1 .. Length); end case; end record; function "and" (L, R : Version_Set) return Version_Set; -- Creates a new tree that is Simplify ((L) & (R)). function "or" (L, R : Version_Set) return Version_Set; -- Creates a new tree that is Simplify ((L) | (R)). function Simplify (VS : Version_Set) return Version_Set; -- Apply trivial and/or simplifications to the set: "* & =1.0" --> "=1.0", -- "* | =1.0" --> "*", "=1.0 & =1.0" --> "=1.0"... Won't be clever enough -- to simplify "^1.0 & ^1.1" --> "^1.1" and similar. function Is_In (V : Version; VS : Version_Set) return Boolean; function Is_Single_Version (VS : Version_Set) return Boolean; -- Says if this VS encapsulates a single "=x.y.z" condition function Contains (VS : Version_Set; V : Version) return Boolean is (Is_In (V, VS)); function To_Extended (BVS : Basic.Version_Set) return Version_Set; function Parse (Str : String; Relaxed : Boolean := False; Unicode : Boolean := True) return Result; -- Parse a string and return an extended version set or an error message -- pinpointing the error. -- If Unicode, plain and unicode sequences are both accepted. -- Relaxed is passed to Semantic_Versioning.To_Set for set conditions. function Value (Str : String; Relaxed : Boolean := False; Unicode : Boolean := True) return Version_Set; -- This version will raise Malformed_Input with the corresponding error as -- message, instead of returning a Result. function Image (VS : Version_Set) return String; -- Original image, as given to Value function Synthetic_Image (VS : Version_Set; Unicode : Boolean := False) return String; -- Reconstructed normalized image private use Ada.Strings.Unbounded; package Semver renames Semantic_Versioning; -- A version set is a binary tree of and/or lists, with leaves being -- basic version sets. type Kinds is (Anded, Ored, Leaf); type Any_Node (Kind : Kinds := Leaf) is record case Kind is when Leaf => VS : Basic.Version_Set; when others => null; end case; end record; package Trees is new Ada.Containers.Multiway_Trees (Any_Node); type Version_Set is tagged record Set : Trees.Tree; Image : Unbounded_String; end record; -- For internal use: ---------------------- -- New_Valid_Result -- ---------------------- function New_Valid_Result (VS : Version_Set) return Result is (Valid => True, Length => 0, Set => VS); Empty_Set : constant Version_Set := (others => <>); end Semantic_Versioning.Extended; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning-parser.adb000066400000000000000000000010421406505563300264130ustar00rootroot00000000000000with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; -- Parse the first argument and re-emit its image. procedure Semantic_Versioning.Parser is begin if Argument_Count /= 1 then Put_Line ("Need exactly one argument!"); return; end if; declare V : Version; begin V := Parse (Argument (1), Relaxed => True); Put_Line (Image (V)); exception when Malformed_Input => Put_Line ("Uh oh... that was not a nice version!"); end; end Semantic_Versioning.Parser; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning.adb000066400000000000000000000216131406505563300251270ustar00rootroot00000000000000with Ada.Strings.Maps; with Semantic_Versioning.Basic; with Semantic_Versioning.Extended; package body Semantic_Versioning is ----------------- -- Begins_With -- ----------------- -- See if a substring is at the beginning of another, subrange-safe function Begins_With (S : String; Pattern : String) return Boolean is (if Pattern'Length >= S'Length then False -- We need at least one extra character for the actual version else S (S'First .. S'First + Pattern'Length - 1) = Pattern); ---------------------------- -- Begins_With_Relational -- ---------------------------- function Begins_With_Relational (S : String; Unicode : Boolean := False) return Boolean is ((S'Length >= 1 and then S (S'First) in '<' | '>' | '=' | '/' | '~' | '^') or else (Unicode and then (Begins_With (S, "≠") or else Begins_With (S, "≥") or else Begins_With (S, "≤")))); ----------- -- Parse -- ----------- function Parse (Description : Version_String; Relaxed : Boolean := False) return Version is Next : Positive := Description'First; V : Version; type Tokens is (Number, Dot, Minus, Plus, Other, Done); type Foreseeable is (Major, Minor, Patch, Nothing); To_See : Foreseeable := Major; --------------- -- Next_Char -- --------------- function Next_Char return Character is (Description (Next)); ---------------- -- Next_Token -- ---------------- function Next_Token (At_Position : Natural := Next) return Tokens is (if At_Position > Description'Last then Done else (case Description (At_Position) is when '.' => Dot, when '+' => Plus, when '-' => Minus, when '0' .. '9' => Number, when others => Other)); ---------------- -- Eat_Number -- ---------------- function Eat_Number return Point is Last : Natural := Next + 1; begin while Last <= Description'Last and then Next_Token (Last) = Number loop Last := Last + 1; end loop; if Next > Description'Last or else Last = Next then raise Malformed_Input with "Empty point number"; end if; return Number : constant Point := Point'Value (Description (Next .. Last - 1)) do Next := Last; end return; end Eat_Number; -------------- -- Eat_Char -- -------------- procedure Eat_Char is begin Next := Next + 1; end Eat_Char; ------------------ -- Accept_Build -- ------------------ procedure Accept_Build is begin V.Build := Ustrings.To_Unbounded_String (Description (Next .. Description'Last)); Next := Description'Last + 1; end Accept_Build; ---------------- -- Accept_Pre -- ---------------- procedure Accept_Pre is Last : Natural := Next + 1; begin if Next > Description'Last then raise Malformed_Input with "Empty pre-release part: " & Description; end if; while Last <= Description'Last and then Description (Last) /= '+' loop Last := Last + 1; end loop; V.Pre_Release := UStrings.To_Unbounded_String (Description (Next .. Last - 1)); Next := Last; case Next_Token is when Done => null; when Plus => Eat_Char; Accept_Build; when others => raise Program_Error with "Unexpected token after pre-release: " & Description; end case; end Accept_Pre; ------------------- -- Accept_Number -- ------------------- procedure Accept_Number is begin case To_See is when Major => V.Major := Eat_Number; when Minor => V.Minor := Eat_Number; when Patch => V.Patch := Eat_Number; when others => raise Malformed_Input with "All foreseeable points already seen"; end case; To_See := Foreseeable'Succ (To_See); case Next_Token is when Number => raise Program_Error with "Number found after eating number"; when Dot => if To_See = Nothing then if Relaxed then Eat_Char; Accept_Build; else raise Malformed_Input with "Too many points in version: " & Description; end if; else Eat_Char; Accept_Number; end if; when Minus => Eat_Char; Accept_Pre; when Plus => Eat_Char; Accept_Build; when Other => if Relaxed Then Accept_Build; else raise Malformed_Input with "Invalid separator after major number: " & Next_Char; end if; when Done => null; end case; end Accept_Number; begin case Next_Token is when Number => Accept_Number; when others => raise Malformed_Input with "Major number expected"; end case; return V; end Parse; --------------------------- -- Less_Than_Pre_Release -- --------------------------- function Less_Than_Pre_Release (L, R : String) return Boolean is use Ada.Strings; use Ada.Strings.Fixed; use Ada.Strings.Maps; Dot : constant Character_Set := To_Set ("."); L_First, L_Last : Natural := L'First - 1; R_First, R_Last : Natural := R'First - 1; L_Num, R_Num : Integer; begin -- Special case if one of them is not really a pre-release: if L /= "" and then R = "" then return True; elsif L = "" and then R /= "" then return False; end if; loop if R_Last = R'Last then -- R depleted, at most L is depleted too return False; elsif L_Last = L'Last then -- L depleted, hence is < return True; else null; -- There are more tokens to compare end if; Find_Token (L, Dot, L_Last + 1, Outside, L_First, L_Last); Find_Token (R, Dot, R_Last + 1, Outside, R_First, R_Last); if R_Last = 0 then return False; -- L can't be less; at most equal (both empty) elsif L_Last = 0 then return True; -- Since R is not exhausted but L is. else -- Field against field -- Compare field numerically, if possible: declare L_Str : String renames L (L_First .. L_Last); R_Str : String renames R (R_First .. R_Last); begin L_Num := Integer'Value (L_Str); R_Num := Integer'Value (R_str); if L_Num /= R_Num then return L_Num < R_Num; else null; -- Try next fields end if; exception when Constraint_Error => -- Can't convert, compare lexicographically if L_Str /= R_Str then return L_Str < R_Str; else null; -- Try next fields end if; end; end if; end loop; end Less_Than_Pre_Release; --------- -- "<" -- --------- function "<" (L, R : Version) return Boolean is use UStrings; begin if L.Major < R.Major then return True; elsif L.Major = R.Major then if L.Minor < R.Minor then return True; elsif L.Minor = R.Minor then if L.Patch < R.Patch then return True; elsif L.Patch = R.Patch then -- Pre-release versions are earlier than regular versions return Less_Than_Pre_Release (To_String (L.Pre_Release), To_String (R.Pre_Release)); end if; end if; end if; return False; -- In all other cases end "<"; -------------- -- To_Basic -- -------------- function To_Basic (V : Version) return Basic.Version_Set is (Basic.Exactly (V)); ----------------- -- To_Extended -- ----------------- function To_Extended (V : Version) return Extended.Version_Set is (Extended.To_Extended (To_Basic (V))); ----------------- -- To_Extended -- ----------------- function To_Extended (VS : Basic.Version_Set) return Extended.Version_Set is (Extended.To_Extended (VS)); --------------- -- Updatable -- --------------- function Updatable (V : Version) return Extended.Version_Set is (if Major (V) = 0 then To_Extended (Basic.Within_Minor (V)) else To_Extended (Basic.Within_Major (V))); end Semantic_Versioning; alire-1.2.1/deps/semantic_versioning/src/semantic_versioning.ads000066400000000000000000000150341406505563300251500ustar00rootroot00000000000000private with Ada.Strings; private with Ada.Strings.Fixed; private with Ada.Strings.Unbounded; limited with Semantic_Versioning.Basic; limited with Semantic_Versioning.Extended; package Semantic_Versioning with Preelaborate is Malformed_Input : exception; -- Returned whenever bad data is received. This includes, at least: -- * Strings that do not follow semantic versioning, in strict parsing -- * Unknown operators in string restrictions type Point is range 0 .. 99_999_999; -- Enough to store a YYYYMMDD as a point function Image (P : Point) return String; subtype Version_String is String with Dynamic_Predicate => (for all S of Version_String => S /= ' '); type Version is tagged private; -- A version is a major, minor and patch number -- Optionally it may include pre-release name and build metadata, e.g.: -- 1.2.0-alpha+c3423fab -- A collection of versions (usually a compatible subset) function New_Version (Major : Point; Minor, Patch : Point := 0; Pre_Release, Build : String := "") return Version; -- Refer to http://semver.org/ for the exact meaning of each part. -- Only the three numbers are mandatory. function Parse (Description : Version_String; Relaxed : Boolean := False) return Version; -- See Relaxed subprogram below for the meaning of Relaxed. function New_Version (Description : Version_String) return Version is (Parse (Description)); function V (Description : Version_String) return Version renames New_Version; function "+" (Description : Version_String) return Version renames New_Version; -- These are strict parsers that will fail on versions not respecting the semver spec function Relaxed (Description : Version_String) return Version is (Parse (Description, Relaxed => True)); -- This parser will attempt to follow spec as much as possible. -- Anything not conforming will be shoved into the pre-release (if '-' separator) or build part (otherwise) function Image (V : Version) return Version_String; -- Back to string representation function "<" (L, R : Version) return Boolean; -- Refer to http://semver.org/ for the exact ordering. Most notably: -- A version with pre-release tag is earlier than its regular version. -- Build info is not taken into account to determine ordering. function "=" (L, R : Version) return Boolean; -- Conforming to Semver spec, the build metadata is not included in the comparison. function Major (V : Version) return Point; function Minor (V : Version) return Point; function Patch (V : Version) return Point; function Pre_Release (V : Version) return String; function Build (V : Version) return String; function Next_Patch (V : Version; Pre_Release, Build : String := "") return Version; function Next_Minor (V : Version; Pre_Release, Build : String := "") return Version; function Next_Major (V : Version; Pre_Release, Build : String := "") return Version; -- For convenience, the following conversion functions are made available -- in this top-level package: function To_Basic (V : Version) return Basic.Version_Set; function To_Extended (V : Version) return Extended.Version_Set; function To_Extended (VS : Basic.Version_Set) return Extended.Version_Set; function Updatable (V : Version) return Extended.Version_Set; -- Given a version, return its appropriate updatable set. E.g.: -- 0.0.1 --> ~0.0.1 -- 0.1.1 --> ~0.1.1 -- 1.0.1 --> ^1.0.1 private package UStrings renames Ada.Strings.Unbounded; subtype UString is UStrings.Unbounded_String; use all type UString; type Version is tagged record Major, Minor, Patch : Point := 0; Pre_Release, Build : UString := Ada.Strings.Unbounded.Null_Unbounded_String; end record; function "=" (L, R : Version) return Boolean is (L.Major = R.Major and then L.Minor = R.Minor and then L.Patch = R.Patch and then L.Pre_Release = R.Pre_Release); function Major (V : Version) return Point is (V.Major); function Minor (V : Version) return Point is (V.Minor); function Patch (V : Version) return Point is (V.Patch); function Pre_Release (V : Version) return String is (UStrings.To_String (V.Pre_Release)); function Build (V : Version) return String is (UStrings.To_String (V.Build)); function New_Version (Major : Point; Minor, Patch : Point := 0; Pre_Release, Build : String := "") return Version is (Major => Major, Minor => Minor, Patch => Patch, Pre_Release => UStrings.To_Unbounded_String (Pre_Release), Build => UStrings.To_Unbounded_String (Build)); function Next_Patch (V : Version; Pre_Release, Build : String := "") return Version is (New_Version (V.Major, V.Minor, V.Patch + 1, Pre_Release, Build)); function Next_Minor (V : Version; Pre_Release, Build : String := "") return Version is (New_Version (V.Major, V.Minor + 1, 0, Pre_Release, Build)); function Next_Major (V : Version; Pre_Release, Build : String := "") return Version is (New_Version (V.Major + 1, 0, 0, Pre_Release, Build)); function Image (P : Point) return String is (Ada.Strings.Fixed.Trim (P'Img, Ada.Strings.Both)); function Image (V : Version) return Version_String is (Image (V.Major) & "." & Image (V.Minor) & "." & Image (V.Patch) & (if V.Pre_Release /= "" then "-" & Ustrings.To_String (V.Pre_Release) else "") & (if V.Build /= "" then "+" & Ustrings.To_String (V.Build) else "")); function Begins_With (S : String; Pattern : String) return Boolean; function Begins_With_Relational (S : String; Unicode : Boolean := False) return Boolean; -- Checks if S starts with a relational operator, optionally in unicode. -- Includes tilde and caret. end Semantic_Versioning; pax_global_header00006660000000000000000000000064137432547430014526gustar00rootroot0000000000000052 comment=39de6478ba6d63c24dd34dd7205a6ce2cb971703 alire-1.2.1/deps/si_units/000077500000000000000000000000001374325474300154135ustar00rootroot00000000000000alire-1.2.1/deps/si_units/.github/000077500000000000000000000000001374325474300167535ustar00rootroot00000000000000alire-1.2.1/deps/si_units/.github/scripts/000077500000000000000000000000001374325474300204425ustar00rootroot00000000000000alire-1.2.1/deps/si_units/.github/scripts/ci-build.sh000066400000000000000000000006441374325474300224720ustar00rootroot00000000000000#!/usr/bin/env bash trap 'echo "ERROR at line ${LINENO} (code: $?)" >&2' ERR trap 'echo "Interrupted" >&2 ; exit 1' INT set -o errexit set -o nounset # For the record echo ENVIRONMENT: env | sort echo ............................ echo GNAT VERSION: gnatls -v echo ............................ # Build library project and then test program(s) gprbuild -j0 -P si_units.gpr && \ gprbuild -j0 -P test/si_units_test.gpr alire-1.2.1/deps/si_units/.github/scripts/ci-test.sh000066400000000000000000000004341374325474300223470ustar00rootroot00000000000000#!/usr/bin/env bash trap 'echo "ERROR at line ${LINENO} (code: $?)" >&2' ERR trap 'echo "Interrupted" >&2 ; exit 1' INT set -o errexit set -o nounset echo "Running tests:" ./test/obj/main_si_units_test # Test subprogram sets exit status depending on if all tests succeeded or not. alire-1.2.1/deps/si_units/.github/workflows/000077500000000000000000000000001374325474300210105ustar00rootroot00000000000000alire-1.2.1/deps/si_units/.github/workflows/build-linux.yaml000066400000000000000000000013731374325474300241340ustar00rootroot00000000000000name: Build Linux on: push: paths-ignore: - 'LICENSE' - 'README.md' - '_config.yml' jobs: build: name: CI on ${{ matrix.tag }} ${{ matrix.year }} runs-on: ubuntu-latest strategy: matrix: tag: - fsf - community year: - 2019 - 2020 steps: - name: Check out repository uses: actions/checkout@v2 - name: Install toolchain uses: ada-actions/toolchain@ce2020 with: distrib: ${{ matrix.tag }} target: native community_year: ${{ matrix.year }} - name: Build run: > bash .github/scripts/ci-build.sh - name: Run tests run: > bash .github/scripts/ci-test.sh alire-1.2.1/deps/si_units/.gitignore000066400000000000000000000000331374325474300173770ustar00rootroot00000000000000alire/ lib/ obj/ test/obj/ alire-1.2.1/deps/si_units/LICENSE000066400000000000000000000007431374325474300164240ustar00rootroot00000000000000 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. alire-1.2.1/deps/si_units/README.md000066400000000000000000000156571374325474300167100ustar00rootroot00000000000000![SI Units](https://raw.githubusercontent.com/HeisenbugLtd/heisenbugltd.github.io/master/assets/img/si_units/cover.png) Utility library to pretty print physical values in properly scaled [metric (SI) units](https://www.nist.gov/pml/weights-and-measures/metric-si/si-units). [![Build Linux](https://github.com/HeisenbugLtd/si_units/workflows/Build%20Linux/badge.svg)](https://github.com/HeisenbugLtd/si_units/actions?query=workflow%3A%22Build+Linux%22) [![Alire](https://img.shields.io/endpoint?url=https://alire.ada.dev/badges/si_units.json)](https://alire.ada.dev/crates/si_units.html) ### Problem Assuming you're writing software that deals with real world values (like frequency, speed, distance, pressure, etc. pp.), at some point you probably want to print values of such types. To be nice to the user, such values should be properly formatted. Ada provides formatting libraries (like `Float_Text_IO`, or even the simple `'Image` attribute) for that purpose, but these do not scale input values, they plainly output whatever you give them in whatever formatting you requested. So, if you are using a base value of "m" for your distance type, a distance of 42.0 km will be output as something like `42000.000` by some properly instantiated `Text_IO` package. Often this is still quite unsatisfactory, especially when dealing with very large or very small values, so that representations with exponents (like `42.424242E-9`) will be used by default. So, what do you do? Wrap up your own formatting subprograms, right? No, of course not, not anymore! Instead ... ### Solution ... **Use SI_Units!** It provides several `Image` function generics for formatting such values. What it does, is that it takes the given value into consideration before converting it into a string and returning an appropriately formatted string including the prefixed physical unit. ### Compiling SI_Units SI_Units is designed as a library to be linked statically. For this purpose, a library project is provided: ```sh gprbuild -P si_units.gpr ``` By default this builds an optimized version of the library with all runtime checks enabled. After compilation succeeded, you can install the library in your `gnat` installation like this: ```sh gprinstall -p -P si_units.gpr ``` Depending on how your GNAT installation is set up, the latter command may require elevated privileges to write into the installation directory, so if needed, prepend sudo /bin/ to the gprinstall instruction above. After that, all you need is to add the line `with "si_units";` to your project file and you're ready to go. #### Tests You can also build the tests, these are provided in the `test` subdirectory: ```sh gprbuild -P test/si_units_test.gpr ``` After that, an executable `./test/obj/main_si_units_test` should have been created which you can run. It should spit out something like ``` Test results: 9440 out of 9440 succeeded. ``` If you haven't changed anything in the provided sources, yet the last line of the output does not say ``, but rather ``, you should report a bug. ### Examples So, in the example from the introductory paragraph, you would first instantiate an appropriate `Image` subprogram for your `Distance` type: ```ada function Image is new SI_Units.Metric.Float_Image (Item => Distance, Default_Aft => 3, Unit => SI_Units.Meter); ``` This instantiates the subprogram `Image` for the type `Distance`, the default number of digits after the decimal point will be `3` and the unit name is `m` (meter). Then you can call this `Image` instantiated for your `Distance` type like this: ```ada Ada.Text_IO.Put_Line (Image (42000.0)); Ada.Text_IO.Put_Line (Image (4200.0)); Ada.Text_IO.Put_Line (Image (420.0)); Ada.Text_IO.Put_Line (Image (42.0)); Ada.Text_IO.Put_Line (Image (4.2)); Ada.Text_IO.Put_Line (Image (0.42)); Ada.Text_IO.Put_Line (Image (0.042)); Ada.Text_IO.Put_Line (Image (0.0042)); Ada.Text_IO.Put_Line (Image (0.00042)); ``` and you'll get: ``` 42.000 km 4.200 km 420.000 m 42.000 m 4.200 m 420.000 mm 42.000 mm 4.200 mm 420.0 µm ``` Neat, isn't it? `Default_Aft` is merely provided for convenience, the number of digits after the decimal point can be specified for each call to `Image`: `Ada.Text_IO.Put_Line (Image (4200.0, Aft => 1));` will output `4.2 km` instead. ### (More) Examples You may have noticed that the instantiation above used a package name `SI_Units.Metric`. Now, if you'd expect a child package named `Imperial`, you'd be wrong. After all, the library is called "SI Units", so sorry, I am not supporting things like *foot pound per square inch*. But, besides decimal prefixes (what it usually called "metric"), there's also an official definition for binary prefixes, good for your Megabits/s (Mebibits/s) connection speed and your Terabytes (Tebibytes) of storage. So yes, the other child package hierarchy is `SI_Units.Binary` and provides a similar[1] functionality for values that are better written with binary prefixes: ```ada function Image is new SI_Units.Binary.Mod_Image (Item => Transmission_Speed, Default_Aft => 1, Unit => "byte/s"); ``` ### Scaling support Sometimes, dealing with inputs from external sources means that values come in different scales than the ones you're using internally. For instance, the [JSON API from openweathermap.org](https://openweathermap.org/api) returns the atmospheric pressure in hPa (hecto-Pascal), not in the base unit Pa. Also, SI defines kg as the base unit, not g(ram), so if you're using values in kg within your program, you may need to convert such values to the prefixless version before feeding it to their respective `Image` subprogram. We got you covered, `SI_Units.Metric.Scaling` does that for you. Actually from any prefix into any other prefix. So, if you need to convert a value given in km into a value in mm, this got you covered. Just be careful, you may easily exceed the defined range of your type if you scale it around like a mad person. ### Unit names Unit names given in instantiations are standard strings, except for a tiny, little `Dynamic_Predicate` that states it can either be completely empty or shall not start with control characters or white space. For any proper use, this predicate can be ignored. I can't think of any use case that would warrant the use of a vertical tab between the value and the actual unit. In fact, the `Image` subprograms are designed to work in a way that both will be separated by a non-breaking space for better readability and to conform to what [SI has to say about it](https://www.nist.gov/pml/weights-and-measures/writing-metric-units). For your convenience, all the names of the SI defined physical units are declared in `SI_Units.Names`. [1] There are no SI prefixes defined for absolute values less than one, so the support for binary images is currently restricted to natural numbers. alire-1.2.1/deps/si_units/SECURITY.md000066400000000000000000000003031374325474300172000ustar00rootroot00000000000000# Security Policy ## Supported Versions | Version | Supported | | ------- | ------------------ | | 0.1.x | :white_check_mark: | ## Reporting a Vulnerability Use the issue tracker. alire-1.2.1/deps/si_units/_config.yml000066400000000000000000000002661374325474300175460ustar00rootroot00000000000000theme: jekyll-theme-minimal title: "SI Units" logo: "https://raw.githubusercontent.com/HeisenbugLtd/heisenbugltd.github.io/master/assets/img/si_units/cover.png" show_downloads: true alire-1.2.1/deps/si_units/alire.lock000066400000000000000000000001501374325474300173550ustar00rootroot00000000000000# THIS IS A MACHINE-GENERATED FILE. DO NOT EDIT MANUALLY. [solution] [solution.context] solved = true alire-1.2.1/deps/si_units/alire.toml000066400000000000000000000026401374325474300174060ustar00rootroot00000000000000description = "Pretty print physical values in properly scaled metric (SI) units." long-description = """ Provides generic conversion (`Image`) functions that convert values into human readable strings with appropriate SI prefixes. This is especially convenient when you have to deal with printing values from a potentially large interval, and you need to represent such values as something an average human will easily be able to read. Then you can use `SI_Units` to take care of the conversion into an appropriate string representation for you. Converting values into a string is supported with all SI prefixes which are a power of 1000 (yocto .. Yotta), additionally there is a generic that can deal with binary prefixes (i.e. prefixes that denote powers of 1024). Scaling (i.e. conversion between different prefixes, like from kilo(meter) to centi(meter)) between all defined SI prefixes is also supported, similar for binary prefixes. See the project's [website](https://github.heisenbug.eu/si_units) for more details. """ name = "si_units" version = "0.2.1" authors = ["Vinzent \"Jellix\" Saranen"] website = "https://github.heisenbug.eu/si_units" licenses = ["WTFPL"] tags = ["utilities", "formatting"] maintainers = ["vinzent@heisenbug.eu"] maintainers-logins = ["Jellix"] project-files = ["si_units.gpr", "test/si_units_test.gpr"] executables = ["main_si_units_test"] [gpr-externals] SI_UNITS_BUILD_MODE = ["debug", "release"] alire-1.2.1/deps/si_units/si_units.gpr000066400000000000000000000021321374325474300177600ustar00rootroot00000000000000library project SI_Units is for Languages use ("Ada"); for Library_Name use "si_units"; for Library_Dir use "lib"; for Library_Kind use "static"; for Create_Missing_Dirs use "True"; for Object_Dir use "obj"; for Source_Dirs use ("src"); type Build_Type is ("debug", "release"); Build_Mode : Build_Type := external ("SI_UNITS_BUILD_MODE", "release"); Compiler_Switches := ("-gnat12", "-gnatw.e.Y", "-gnatyAM80OSabcdefhiklnoprstu", "-gnata", "-gnato", "-fstack-check"); package Builder is case Build_Mode is when "debug" => for Switches ("ada") use ("-g"); when "release" => for Switches ("ada") use (""); end case; end Builder; package Compiler is case Build_Mode is when "debug" => for Switches ("ada") use Compiler_Switches & ("-g", "-O0"); when "release" => for Switches ("ada") use Compiler_Switches & ("-O2", "-gnatn", "-funroll-loops"); end case; end Compiler; package Binder is for Switches ("ada") use ("-E"); end Binder; end SI_Units; alire-1.2.1/deps/si_units/src/000077500000000000000000000000001374325474300162025ustar00rootroot00000000000000alire-1.2.1/deps/si_units/src/si_units-binary-scaling.adb000066400000000000000000000026021374325474300234070ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.Unchecked_Conversion; with SI_Units.Float_IO; package body SI_Units.Binary.Scaling is function To_Exponent is new Ada.Unchecked_Conversion (Source => Prefixes, Target => Integer); use type Float_IO.General_Float; function General_Scale (Value : in Float_IO.General_Float; From_Prefix : in Prefixes; To_Prefix : in Prefixes) return Float_IO.General_Float is (Value * 2.0 ** (To_Exponent (From_Prefix) - To_Exponent (To_Prefix))); function Mod_Scale (Value : in Item; From_Prefix : in Prefixes; To_Prefix : in Prefixes := None) return Item is (Item (General_Scale (Value => Float_IO.General_Float (Value), From_Prefix => From_Prefix, To_Prefix => To_Prefix))); end SI_Units.Binary.Scaling; alire-1.2.1/deps/si_units/src/si_units-binary-scaling.ads000066400000000000000000000030021374325474300234230ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); -------------------------------------------------------------------------------- -- Binary units scaling support. -- -- Conversion between differently prefixed raw values, i.e. from GBit to Bit. -------------------------------------------------------------------------------- package SI_Units.Binary.Scaling is pragma Warnings (Off, "declaration hides ""Prefixes"""); -- intentional type Prefixes is new SI_Units.Binary.Prefixes with Size => Integer'Size; pragma Warnings (On, "declaration hides ""Prefixes"""); for Prefixes use (None => 0, kibi => 10, mebi => 20, gibi => 30, tebi => 40, pebi => 50, exbi => 60, zebi => 70, yobi => 80); generic type Item is mod <>; function Mod_Scale (Value : Item; From_Prefix : Prefixes; To_Prefix : Prefixes := None) return Item; end SI_Units.Binary.Scaling; alire-1.2.1/deps/si_units/src/si_units-binary.adb000066400000000000000000000043161374325474300217750ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.Float_Text_IO; with Ada.IO_Exceptions; package body SI_Units.Binary is function Prefix (S : in Prefixes) return String is (case S is when None => "", when kibi => "Ki", when mebi => "Mi", when gibi => "Gi", when tebi => "Ti", when pebi => "Pi", when exbi => "Ei", when zebi => "Zi", when yobi => "Yi") with Inline => True; function Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String is Result : String (1 .. 5 + Ada.Text_IO.Field'Max (1, Aft)); -- "1023.[...]"; Temp : Float := Float (Value); Scale : Prefixes := None; begin if Unit /= No_Unit then -- No prefix matching if no unit name is given. while Temp >= Magnitude loop Scale := Prefixes'Succ (Scale); Temp := Temp / Magnitude; end loop; end if; Try_Numeric_To_String_Conversion : begin Ada.Float_Text_IO.Put (To => Result, Item => Temp, Aft => Aft, Exp => 0); exception when Ada.IO_Exceptions.Layout_Error => -- Value was larger than 9999 Yi and didn't fit into the -- string. -- Reset Scale and return "inf"inity instead. Result (1 .. 4) := "+inf"; Result (5 .. Result'Last) := (others => ' '); end Try_Numeric_To_String_Conversion; return Trim (Result & (if Unit = No_Unit then "" else No_Break_Space & Prefix (Scale) & Unit)); end Image; end SI_Units.Binary; alire-1.2.1/deps/si_units/src/si_units-binary.ads000066400000000000000000000035131374325474300220140ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.Text_IO; -------------------------------------------------------------------------------- -- Image subprograms for binary (i.e. information technology related) values. -------------------------------------------------------------------------------- package SI_Units.Binary is type Prefixes is (None, kibi, mebi, gibi, tebi, pebi, exbi, zebi, yobi); -- Prefixes supported in instantiated Image subprograms. Magnitude : constant := 1024.0; -- Magnitude change when trying to find the best representation for a given -- value. -- As this is intended for binary values (i.e. kibiBytes etc.), we neither -- support negative nor non-integral values. -- -- TODO: We could support non-modular integral types, though. generic type Item is mod <>; Default_Aft : in Ada.Text_IO.Field; Unit : in Unit_Name; function Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String with Global => null; -- Image function for modular types. -- -- Parameters: -- -- Item - the type you want an Image function instantiated for. -- Default_Aft - the default number of digits after the decimal point -- (regardless of the prefix finally used). -- Unit - The name of your unit, e.g. "Bytes", "Bit/s" or such. end SI_Units.Binary; alire-1.2.1/deps/si_units/src/si_units-float_io.ads000066400000000000000000000026521374325474300223270ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.Text_IO; -------------------------------------------------------------------------------- -- SI_Units, internal support package. -- -- To ease implementation and avoid duplicating code, most generic subprograms -- implementing value/string conversion for different types will work by first -- converting the input value into a floating point value and then call a -- common subprogram to do the actual conversion. -------------------------------------------------------------------------------- private package SI_Units.Float_IO is type General_Float is new Standard.Long_Long_Float; -- General_Float can be replaced by any other float type. For now, we use -- Long_Long_Float which is standard Ada and should have a sufficient -- precision for all practical purposes. package General_Float_IO is new Ada.Text_IO.Float_IO (Num => General_Float); -- Instantiate the appropriate IO package for the type. end SI_Units.Float_IO; alire-1.2.1/deps/si_units/src/si_units-metric-scaling.adb000066400000000000000000000034041374325474300234070ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.Unchecked_Conversion; with SI_Units.Float_IO; package body SI_Units.Metric.Scaling is function To_Exponent is new Ada.Unchecked_Conversion (Source => Prefixes, Target => Integer); use type Float_IO.General_Float; function General_Scale (Value : in Float_IO.General_Float; From_Prefix : in Prefixes; To_Prefix : in Prefixes) return Float_IO.General_Float is (Value * 10.0 ** (To_Exponent (From_Prefix) - To_Exponent (To_Prefix))); function Fixed_Scale (Value : in Item; From_Prefix : in Prefixes; To_Prefix : in Prefixes := None) return Item is (Item (General_Scale (Value => Float_IO.General_Float (Value), From_Prefix => From_Prefix, To_Prefix => To_Prefix))); function Float_Scale (Value : in Item; From_Prefix : in Prefixes; To_Prefix : in Prefixes := None) return Item is (Item (General_Scale (Value => Float_IO.General_Float (Value), From_Prefix => From_Prefix, To_Prefix => To_Prefix))); end SI_Units.Metric.Scaling; alire-1.2.1/deps/si_units/src/si_units-metric-scaling.ads000066400000000000000000000045311374325474300234320ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); -------------------------------------------------------------------------------- -- Metric (SI) units scaling support. -- -- Conversion between differently prefixed raw values, i.e. from hPa to Pa. -------------------------------------------------------------------------------- package SI_Units.Metric.Scaling is pragma Warnings (Off, "declaration hides ""Prefixes"""); -- intentional type Prefixes is (yocto, zepto, atto, femto, pico, nano, micro, milli, centi, deci, None, Deka, Hecto, kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta); pragma Warnings (On, "declaration hides ""Prefixes"""); for Prefixes'Size use Integer'Size; for Prefixes use (yocto => -24, zepto => -21, atto => -18, femto => -15, pico => -12, nano => -9, micro => -6, milli => -3, centi => -2, deci => -1, None => 0, Deka => 1, Hecto => 2, kilo => 3, Mega => 6, Giga => 9, Tera => 12, Peta => 15, Exa => 18, Zetta => 21, Yotta => 24); generic type Item is delta <>; function Fixed_Scale (Value : Item; From_Prefix : Prefixes; To_Prefix : Prefixes := None) return Item; generic type Item is digits <>; function Float_Scale (Value : Item; From_Prefix : Prefixes; To_Prefix : Prefixes := None) return Item; end SI_Units.Metric.Scaling; alire-1.2.1/deps/si_units/src/si_units-metric.adb000066400000000000000000000150251374325474300217730ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.IO_Exceptions; with SI_Units.Float_IO; package body SI_Units.Metric is function Prefix (S : in Prefixes) return String is (case S is when yocto => "y", when zepto => "z", when atto => "a", when femto => "f", when pico => "p", when nano => "n", when micro => Micro_Sign, when milli => "m", when None => "", when kilo => "k", when Mega => "M", when Giga => "G", when Tera => "T", when Peta => "P", when Exa => "E", when Zetta => "Z", when Yotta => "Y") with Inline => True; function General_Image (Value : in Float_IO.General_Float; Aft : in Ada.Text_IO.Field; Unit : in String) return String; -- The actual implementation of each of the Image subprograms. -- -- Finds the best match for a value such that the value to be displayed will -- be in the interval (0.0 .. 1000.0] with an appropriate prefix for the -- unit name, i.e. a call to -- -- General_Image (123_456_789.0, 3, "Hz"); -- -- will return the string -- -- 123.457 MHz function General_Image (Value : in Float_IO.General_Float; Aft : in Ada.Text_IO.Field; Unit : in String) return String is use type Float_IO.General_Float; Temp : Float_IO.General_Float := abs Value; -- Ignore sign for temporary value. Scale : Prefixes := None; begin -- No prefix if no unit is given or value is exactly zero. if Unit /= No_Unit and then Temp /= 0.0 then -- We ignored the sign of the input value, so we only have to cope -- with positive values here. if Temp < 1.0 then Handle_Small_Prefixes : declare -- Set threshold, if the value is less than that it will be -- rounded down. Please note, that an Aft of 0 will be handled -- like an Aft of 1 (as we always emit at least one digit after -- the decimal point. Threshold : constant Float_IO.General_Float := 1.0 - (0.1 ** (Ada.Text_IO.Field'Max (1, Aft))) / 2.0; begin Find_Best_Small_Prefix : while Temp <= Threshold loop exit Find_Best_Small_Prefix when Scale = Prefixes'First; -- Value is too small to be optimally represented. -- Down to next prefix. Scale := Prefixes'Pred (Scale); Temp := Temp * Magnitude; end loop Find_Best_Small_Prefix; -- Value is (still) too small to be properly represented, treat -- as zero. if Temp < 1.0 - Threshold then Temp := 0.0; Scale := None; end if; end Handle_Small_Prefixes; else Handle_Large_Prefixes : declare Threshold : constant Float_IO.General_Float := Magnitude - ((0.1 ** Aft) / 2.0); -- If the value is greater than that it will be rounded up. begin Find_Best_Large_Prefix : while Temp >= Threshold loop exit Find_Best_Large_Prefix when Scale = Prefixes'Last; -- Value is too large to be optimally represented. -- Up to next prefix. Scale := Prefixes'Succ (Scale); Temp := Temp / Magnitude; end loop Find_Best_Large_Prefix; end Handle_Large_Prefixes; end if; end if; -- Restore sign before converting into string. if Value < 0.0 then Temp := -Temp; end if; Convert_To_Postfixed_String : declare Result : String (1 .. 5 + Ada.Text_IO.Field'Max (1, Aft)); -- "-999.[...]"; begin Try_Numeric_To_String_Conversion : begin Float_IO.General_Float_IO.Put (To => Result, Item => Temp, Aft => Aft, Exp => 0); exception when Ada.IO_Exceptions.Layout_Error => -- Value was larger than 999 Yunits and didn't fit into the -- string. -- Reset Scale and return ""inity instead. Scale := None; Result (1 .. 4) := (if Temp < 0.0 then Minus_Sign else Plus_Sign) & "inf"; Result (5 .. Result'Last) := (others => ' '); end Try_Numeric_To_String_Conversion; return Trim (Result & (if Unit = No_Unit then "" else No_Break_Space & Prefix (Scale) & Unit)); end Convert_To_Postfixed_String; end General_Image; function Fixed_Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String is (General_Image (Value => Float_IO.General_Float (Value), Aft => Aft, Unit => Unit)); function Float_Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String is (General_Image (Value => Float_IO.General_Float (Value), Aft => Aft, Unit => Unit)); function Integer_Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String is (General_Image (Value => Float_IO.General_Float (Value), Aft => Aft, Unit => Unit)); function Mod_Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String is (General_Image (Value => Float_IO.General_Float (Value), Aft => Aft, Unit => Unit)); end SI_Units.Metric; alire-1.2.1/deps/si_units/src/si_units-metric.ads000066400000000000000000000060271374325474300220160ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.Text_IO; -------------------------------------------------------------------------------- -- Image subprograms for metric (SI) physical values. -- -- Please note that the rather unusual prefixes centi, deci, Deka, and Hecto -- are not supported by these subprograms. You can use the Scaling package to -- convert between differently prefixed value and work from there, though. -------------------------------------------------------------------------------- package SI_Units.Metric is type Prefixes is (yocto, zepto, atto, femto, pico, nano, micro, milli, None, kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta); -- Prefixes supported in instantiated Image subprograms. Magnitude : constant := 1000.0; -- Magnitude change when trying to find the best representation for a given -- value. -- -- Generic image function for different types. -- -- Parameters: -- -- Item - the type you want an Image function instantiated for. -- Default_Aft - the default number of digits after the decimal point -- (regardless of the prefix finally used). -- Unit - The name of your unit, e.g. "Hz", "m" or such (also see -- package SI_Units.Names). -- generic type Item is delta <>; Default_Aft : in Ada.Text_IO.Field; Unit : in Unit_Name; function Fixed_Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String with Global => null; -- Image subroutine that can be instantiated for fixed types. generic type Item is digits <>; Default_Aft : in Ada.Text_IO.Field; Unit : in Unit_Name; function Float_Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String with Global => null; -- Image subroutine that can be instantiated for floating point types. generic type Item is range <>; Default_Aft : in Ada.Text_IO.Field; Unit : in Unit_Name; function Integer_Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String with Global => null; -- Image subroutine that can be instantiated for integer types. generic type Item is mod <>; Default_Aft : in Ada.Text_IO.Field; Unit : in Unit_Name; function Mod_Image (Value : in Item; Aft : in Ada.Text_IO.Field := Default_Aft) return String with Global => null; -- Image subroutine that can be instantiated for modular types. end SI_Units.Metric; alire-1.2.1/deps/si_units/src/si_units-names.ads000066400000000000000000000075701374325474300216420ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); -------------------------------------------------------------------------------- -- Names of all officially defined SI units (including derived units). -- -- Please note that due to current lack of proper unicode support, the symbol -- for electric resistance is defined as "Ohm" here, not the Greek letter -- Omega. The library itself is unicode agnostic, so you can just instantiate -- your Image subprograms with the proper UTF-8 string. -------------------------------------------------------------------------------- package SI_Units.Names is -- Unit names (as defined by SI). Ampere : constant Unit_Name; Becquerel : constant Unit_Name; Candela : constant Unit_Name; Coulomb : constant Unit_Name; Degree_Celsius : constant Unit_Name; Farad : constant Unit_Name; Gram : constant Unit_Name; -- official SI base unit is kilogram Gray : constant Unit_Name; Henry : constant Unit_Name; Hertz : constant Unit_Name; Joule : constant Unit_Name; Katal : constant Unit_Name; Kelvin : constant Unit_Name; Lumen : constant Unit_Name; Lux : constant Unit_Name; Metre : constant Unit_Name; Mole : constant Unit_Name; Newton : constant Unit_Name; Ohm : constant Unit_Name; Pascal : constant Unit_Name; Percent : constant Unit_Name; Radian : constant Unit_Name; Second : constant Unit_Name; Siemens : constant Unit_Name; Sievert : constant Unit_Name; Steradian : constant Unit_Name; Tesla : constant Unit_Name; Volt : constant Unit_Name; Watt : constant Unit_Name; Weber : constant Unit_Name; private Ampere : constant Unit_Name := "A"; Becquerel : constant Unit_Name := "Bq"; Candela : constant Unit_Name := "cd"; Coulomb : constant Unit_Name := "C"; Degree_Celsius : constant Unit_Name := Character'Val (16#E2#) & Character'Val (16#84#) & Character'Val (16#83#); -- U+2103 Farad : constant Unit_Name := "F"; Gram : constant Unit_Name := "g"; Gray : constant Unit_Name := "Gy"; Henry : constant Unit_Name := "H"; Hertz : constant Unit_Name := "Hz"; Joule : constant Unit_Name := "J"; Katal : constant Unit_Name := "kat"; Kelvin : constant Unit_Name := "K"; Lumen : constant Unit_Name := "lm"; Lux : constant Unit_Name := "lx"; Metre : constant Unit_Name := "m"; Mole : constant Unit_Name := "mol"; Newton : constant Unit_Name := "N"; Ohm : constant Unit_Name := Character'Val (16#E2#) & Character'Val (16#84#) & Character'Val (16#A6#); -- U+2126 Pascal : constant Unit_Name := "Pa"; Percent : constant Unit_Name := "%"; Radian : constant Unit_Name := "rad"; Second : constant Unit_Name := "s"; Siemens : constant Unit_Name := "S"; Sievert : constant Unit_Name := "Sv"; Steradian : constant Unit_Name := "sr"; Tesla : constant Unit_Name := "T"; Volt : constant Unit_Name := "V"; Watt : constant Unit_Name := "W"; Weber : constant Unit_Name := "Wb"; end SI_Units.Names; alire-1.2.1/deps/si_units/src/si_units.ads000066400000000000000000000046551374325474300205420ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.Characters.Handling; with Ada.Strings.UTF_Encoding; private with Ada.Characters.Latin_1; private with Ada.Strings.Fixed; package SI_Units with Preelaborate => True is No_Unit : constant Ada.Strings.UTF_Encoding.UTF_8_String; -- Designated value for "no unit name", i.e. the empty string. -- -- Normally, when this package and its children are used, we would expect a -- non-empty string for any unit (hence the type predicate below), but we -- allow the empty string as a special exception. subtype Unit_Name is Ada.Strings.UTF_Encoding.UTF_8_String with Dynamic_Predicate => (Unit_Name = No_Unit or else (Unit_Name'Length > 0 and then (for all C of Unit_Name (Unit_Name'First .. Unit_Name'First) => -- FIXME: UTF-8 encoding scheme *may* result in what Latin_1 -- considers "Control" characters -- FIXME: UTF-8 encoding has additional WS characters not Ada.Characters.Handling.Is_Control (C) and not Ada.Characters.Handling.Is_Space (C)))); -- Restrict the possibility of a unit name: A unit name can be empty (see -- No_Unit), but if it isn't, it shall not start with something weird like -- control characters (which includes tabs), or whitespace. It could start -- with digits and other weird stuff, though. private Degree_Sign : String := Character'Val (16#C2#) & Character'Val (16#B0#); No_Break_Space : String := Character'Val (16#C2#) & Character'Val (16#A0#); Micro_Sign : String := Character'Val (16#C2#) & Character'Val (16#B5#); Minus_Sign : Character renames Ada.Characters.Latin_1.Minus_Sign; Plus_Sign : Character renames Ada.Characters.Latin_1.Plus_Sign; No_Unit : constant String := ""; function Trim (Source : in String; Side : in Ada.Strings.Trim_End := Ada.Strings.Left) return String renames Ada.Strings.Fixed.Trim; end SI_Units; alire-1.2.1/deps/si_units/test/000077500000000000000000000000001374325474300163725ustar00rootroot00000000000000alire-1.2.1/deps/si_units/test/main_si_units_test.adb000066400000000000000000001247531374325474300227560ustar00rootroot00000000000000-------------------------------------------------------------------------------- -- Copyright (C) 2020 by Heisenbug Ltd. (gh+si_units@heisenbug.eu) -- -- This work is free. You can redistribute it and/or modify it under the -- terms of the Do What The Fuck You Want To Public License, Version 2, -- as published by Sam Hocevar. See the LICENSE file for more details. -------------------------------------------------------------------------------- pragma License (Unrestricted); with Ada.Command_Line; with Ada.Text_IO; with SI_Units.Binary.Scaling; pragma Unreferenced (SI_Units.Binary.Scaling); with SI_Units.Metric.Scaling; with SI_Units.Names; -------------------------------------------------------------------------------- -- SI_Units - Test run. -------------------------------------------------------------------------------- procedure Main_SI_Units_Test is type Scalar is delta 1.0 / 2 ** 32 range -2.0 ** 31 .. 2.0 ** 31 - 1.0 / 2 ** 32; type Modular is mod 2 ** 64; function Modular_BI is new SI_Units.Binary.Image (Item => Modular, Default_Aft => 3, Unit => "Mod"); function Modular_MI is new SI_Units.Metric.Mod_Image (Item => Modular, Default_Aft => 3, Unit => "Mod"); function Fixed_MI is new SI_Units.Metric.Fixed_Image (Item => Scalar, Default_Aft => 6, Unit => SI_Units.Names.Ampere); function Float_MI is new SI_Units.Metric.Float_Image (Item => Long_Float, Default_Aft => 3, Unit => SI_Units.Names.Volt); function Scale_Float is new SI_Units.Metric.Scaling.Float_Scale (Item => Long_Float); package Test_Cases is procedure Add (Passed : in Boolean; Message : in String); function Num_Total return Natural; function Num_Passed return Natural; end Test_Cases; package body Test_Cases is Num_Test_Cases : Natural := 0; Num_Succeeded : Natural := 0; procedure Add (Passed : in Boolean; Message : in String) is begin Num_Test_Cases := Num_Test_Cases + 1; if Passed then Num_Succeeded := Num_Succeeded + 1; else Ada.Text_IO.Put_Line (Item => "Test_Case" & Num_Test_Cases'Image & " failed: " & Message); end if; end Add; function Num_Passed return Natural is (Num_Succeeded); function Num_Total return Natural is (Num_Test_Cases); end Test_Cases; Micro_Sign : constant String := Character'Val (16#C2#) & Character'Val (16#B5#); No_Break_Space : constant String := Character'Val (16#C2#) & Character'Val (16#A0#); type String_Access is not null access String; begin Test_Cases.Add (Passed => Modular_BI (-1) = "16.000" & No_Break_Space & "EiMod", Message => "Modular_BI (-1)"); Test_Cases.Add (Passed => Modular_MI (-1) = "18.447" & No_Break_Space & "EMod", Message => "Modular_MI (-1)"); Test_Cases.Add (Passed => Modular_BI (1023) = "1023.000" & No_Break_Space & "Mod", Message => "Modular_BI (1023)"); Test_Cases.Add (Passed => Modular_MI (1023) = "1.023" & No_Break_Space & "kMod", Message => "Modular_MI (1023)"); Test_Cases.Add (Passed => Modular_BI (1024) = "1.000" & No_Break_Space & "KiMod", Message => "Modular_BI (1024)"); Test_Cases.Add (Passed => Modular_MI (1024) = "1.024" & No_Break_Space & "kMod", Message => "Modular_MI (1024)"); Test_Cases.Add (Passed => Modular_BI (1025) = "1.001" & No_Break_Space & "KiMod", Message => "Modular_BI (1025)"); Test_Cases.Add (Passed => Modular_MI (1025) = "1.025" & No_Break_Space & "kMod", Message => "Modular_MI (1025)"); Test_Cases.Add (Passed => Fixed_MI (0.0) = "0.000000" & No_Break_Space & SI_Units.Names.Ampere, Message => "Fixed_MI (0.0)"); Test_Cases.Add (Passed => Fixed_MI (Scalar'Small) = "232.830644" & No_Break_Space & "p" & SI_Units.Names.Ampere, Message => "Fixed_MI (Scalar'Small)"); Test_Cases.Add (Passed => Fixed_MI (Scalar'First) = "-2.147484" & No_Break_Space & "G" & SI_Units.Names.Ampere, Message => "Fixed_MI (Scalar'First)"); Test_Cases.Add (Passed => Fixed_MI (Scalar'Last) = "2.147484" & No_Break_Space & "G" & SI_Units.Names.Ampere, Message => "Fixed_MI (Scalar'Last)"); declare Normal_Suffix : constant String := No_Break_Space & SI_Units.Names.Ampere; Kilo_Suffix : constant String := No_Break_Space & "k" & SI_Units.Names.Ampere; type Loop_Iteration is range 1 .. 32; type Expected_List is array (Loop_Iteration) of String_Access; Median : constant Scalar := 1000.0; Operand : Scalar := 1.0; begin declare -- Known memory leak due to string creation. As this is a test program -- only run once we don't care. Expected_Results : constant Expected_List := (32 => new String'("999.000000" & Normal_Suffix), 31 => new String'("999.500000" & Normal_Suffix), 30 => new String'("999.750000" & Normal_Suffix), 29 => new String'("999.875000" & Normal_Suffix), 28 => new String'("999.937500" & Normal_Suffix), 27 => new String'("999.968750" & Normal_Suffix), 26 => new String'("999.984375" & Normal_Suffix), 25 => new String'("999.992188" & Normal_Suffix), 24 => new String'("999.996094" & Normal_Suffix), 23 => new String'("999.998047" & Normal_Suffix), 22 => new String'("999.999023" & Normal_Suffix), 21 => new String'("999.999512" & Normal_Suffix), 20 => new String'("999.999756" & Normal_Suffix), 19 => new String'("999.999878" & Normal_Suffix), 18 => new String'("999.999939" & Normal_Suffix), 17 => new String'("999.999969" & Normal_Suffix), 16 => new String'("999.999985" & Normal_Suffix), 15 => new String'("999.999992" & Normal_Suffix), 14 => new String'("999.999996" & Normal_Suffix), 13 => new String'("999.999998" & Normal_Suffix), 12 => new String'("999.999999" & Normal_Suffix), 1 .. 11 => new String'("1.000000" & Kilo_Suffix)); begin for Exponent in reverse Loop_Iteration loop Test_Cases.Add (Passed => Fixed_MI (Median - Operand) = Expected_Results (Exponent).all, Message => "Fixed_MI (Median - Operand)/" & Exponent'Image); Operand := Operand / 2.0; end loop; end; Test_Cases.Add (Passed => Fixed_MI (Median) = "1.000000" & No_Break_Space & "k" & SI_Units.Names.Ampere, Message => "Fixed_MI (Median)"); declare -- Known memory leak due to string creation. As this is a test program -- only run once we don't care. Expected_Results : constant Expected_List := (1 .. 22 => new String'("1.000000" & Kilo_Suffix), 23 => new String'("1.000001" & Kilo_Suffix), 24 => new String'("1.000002" & Kilo_Suffix), 25 => new String'("1.000004" & Kilo_Suffix), 26 => new String'("1.000008" & Kilo_Suffix), 27 => new String'("1.000016" & Kilo_Suffix), 28 => new String'("1.000031" & Kilo_Suffix), 29 => new String'("1.000062" & Kilo_Suffix), 30 => new String'("1.000125" & Kilo_Suffix), 31 => new String'("1.000250" & Kilo_Suffix), 32 => new String'("1.000500" & Kilo_Suffix)); begin for Exponent in Loop_Iteration loop Test_Cases.Add (Passed => Fixed_MI (Median + Operand) = Expected_Results (Exponent).all, Message => "Fixed_MI (Median + Operand)/" & Exponent'Image); Operand := Operand * 2.0; end loop; end; end; declare subtype Loop_Iteration is Natural range 1 .. 18; type Less_Equal_Greater is (LT, EQ, GT); type Expected_List is array (Loop_Iteration, Less_Equal_Greater) of String_Access; Median : constant Scalar := 1000.0; LT_Median : constant Scalar := Median - Scalar'Small; GT_Median : constant Scalar := Median + Scalar'Small; Normal_Suffix : constant String := No_Break_Space & SI_Units.Names.Ampere; Kilo_Suffix : constant String := No_Break_Space & "k" & SI_Units.Names.Ampere; Expected_Results : constant Expected_List := (01 => (LT => new String'("1.0" & Kilo_Suffix), EQ => new String'("1.0" & Kilo_Suffix), GT => new String'("1.0" & Kilo_Suffix)), 02 => (LT => new String'("1.00" & Kilo_Suffix), EQ => new String'("1.00" & Kilo_Suffix), GT => new String'("1.00" & Kilo_Suffix)), 03 => (LT => new String'("1.000" & Kilo_Suffix), EQ => new String'("1.000" & Kilo_Suffix), GT => new String'("1.000" & Kilo_Suffix)), 04 => (LT => new String'("1.0000" & Kilo_Suffix), EQ => new String'("1.0000" & Kilo_Suffix), GT => new String'("1.0000" & Kilo_Suffix)), 05 => (LT => new String'("1.00000" & Kilo_Suffix), EQ => new String'("1.00000" & Kilo_Suffix), GT => new String'("1.00000" & Kilo_Suffix)), 06 => (LT => new String'("1.000000" & Kilo_Suffix), EQ => new String'("1.000000" & Kilo_Suffix), GT => new String'("1.000000" & Kilo_Suffix)), 07 => (LT => new String'("1.0000000" & Kilo_Suffix), EQ => new String'("1.0000000" & Kilo_Suffix), GT => new String'("1.0000000" & Kilo_Suffix)), 08 => (LT => new String'("1.00000000" & Kilo_Suffix), EQ => new String'("1.00000000" & Kilo_Suffix), GT => new String'("1.00000000" & Kilo_Suffix)), 09 => (LT => new String'("1.000000000" & Kilo_Suffix), EQ => new String'("1.000000000" & Kilo_Suffix), GT => new String'("1.000000000" & Kilo_Suffix)), 10 => (LT => new String'("999.9999999998" & Normal_Suffix), EQ => new String'("1.0000000000" & Kilo_Suffix), GT => new String'("1.0000000000" & Kilo_Suffix)), 11 => (LT => new String'("999.99999999977" & Normal_Suffix), EQ => new String'("1.00000000000" & Kilo_Suffix), GT => new String'("1.00000000000" & Kilo_Suffix)), 12 => (LT => new String'("999.999999999767" & Normal_Suffix), EQ => new String'("1.000000000000" & Kilo_Suffix), GT => new String'("1.000000000000" & Kilo_Suffix)), 13 => (LT => new String'("999.9999999997672" & Normal_Suffix), EQ => new String'("1.0000000000000" & Kilo_Suffix), GT => new String'("1.0000000000002" & Kilo_Suffix)), 14 => (LT => new String'("999.99999999976717" & Normal_Suffix), EQ => new String'("1.00000000000000" & Kilo_Suffix), GT => new String'("1.00000000000023" & Kilo_Suffix)), 15 => (LT => new String'("999.999999999767169" & Normal_Suffix), EQ => new String'("1.000000000000000" & Kilo_Suffix), GT => new String'("1.000000000000233" & Kilo_Suffix)), 16 => (LT => new String'("999.9999999997671690" & Normal_Suffix), EQ => new String'("1.0000000000000000" & Kilo_Suffix), GT => new String'("1.0000000000002328" & Kilo_Suffix)), 17 => (LT => new String'("999.99999999976716900" & Normal_Suffix), EQ => new String'("1.00000000000000000" & Kilo_Suffix), GT => new String'("1.00000000000023283" & Kilo_Suffix)), 18 => (LT => new String'("999.999999999767169000" & Normal_Suffix), EQ => new String'("1.000000000000000000" & Kilo_Suffix), GT => new String'("1.000000000000232830" & Kilo_Suffix))); begin for Aft in Loop_Iteration loop Test_Cases.Add (Passed => Fixed_MI (Value => LT_Median, Aft => Aft) = Expected_Results (Aft, LT).all, Message => "Fixed_MI (Value => LT_Median, Aft =>" & Aft'Image & ")"); Test_Cases.Add (Passed => Fixed_MI (Value => Median, Aft => Aft) = Expected_Results (Aft, EQ).all, Message => "Fixed_MI (Value => Median, Aft =>" & Aft'Image & ")"); Test_Cases.Add (Passed => Fixed_MI (Value => GT_Median, Aft => Aft) = Expected_Results (Aft, GT).all, Message => "Fixed_MI (Value => GT_Median, Aft =>" & Aft'Image & ")"); end loop; end; Test_Cases.Add (Passed => Float_MI (0.0) = "0.000" & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (0.0)"); Test_Cases.Add (Passed => Float_MI (Long_Float'Safe_Small) = "0.000" & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (Long_Float'Safe_Small)"); Test_Cases.Add (Passed => Float_MI (Long_Float'Safe_First) = "-inf " & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (Long_Float'Safe_First)"); Test_Cases.Add (Passed => Float_MI (Long_Float'Safe_Last) = "+inf " & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (Long_Float'Safe_Last)"); Test_Cases.Add (Passed => Float_MI (-9.999_999_49E27) = "-inf " & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (-9.999_999_49E27)"); Test_Cases.Add (Passed => Float_MI (9.999_999_49E27) = "9999.999" & No_Break_Space & "Y" & SI_Units.Names.Volt, Message => "Float_MI (9.999_999_49E27)"); -- "infinity" Test_Cases.Add (Passed => Float_MI (-1.0E27) = "-inf " & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (-1.0E27)"); Test_Cases.Add (Passed => Float_MI (1.0E27) = "1000.000" & No_Break_Space & "Y" & SI_Units.Names.Volt, Message => "Float_MI (1.0E27)"); -- Yotta Test_Cases.Add (Passed => Float_MI (-1.0E24) = "-1.000" & No_Break_Space & "Y" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E24)"); Test_Cases.Add (Passed => Float_MI (1.0E24) = "1.000" & No_Break_Space & "Y" & SI_Units.Names.Volt, Message => "Float_MI (1.0E24)"); -- Zeta Test_Cases.Add (Passed => Float_MI (-1.0E21) = "-1.000" & No_Break_Space & "Z" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E21)"); Test_Cases.Add (Passed => Float_MI (1.0E21) = "1.000" & No_Break_Space & "Z" & SI_Units.Names.Volt, Message => "Float_MI (1.0E21)"); -- Exa Test_Cases.Add (Passed => Float_MI (-1.0E18) = "-1.000" & No_Break_Space & "E" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E18)"); Test_Cases.Add (Passed => Float_MI (1.0E18) = "1.000" & No_Break_Space & "E" & SI_Units.Names.Volt, Message => "Float_MI (1.0E18)"); -- Peta Test_Cases.Add (Passed => Float_MI (-1.0E15) = "-1.000" & No_Break_Space & "P" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E15)"); Test_Cases.Add (Passed => Float_MI (1.0E15) = "1.000" & No_Break_Space & "P" & SI_Units.Names.Volt, Message => "Float_MI (1.0E15)"); -- Tera Test_Cases.Add (Passed => Float_MI (-1.0E12) = "-1.000" & No_Break_Space & "T" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E12)"); Test_Cases.Add (Passed => Float_MI (1.0E12) = "1.000" & No_Break_Space & "T" & SI_Units.Names.Volt, Message => "Float_MI (1.0E12)"); -- Giga Test_Cases.Add (Passed => Float_MI (-1.0E9) = "-1.000" & No_Break_Space & "G" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E9)"); Test_Cases.Add (Passed => Float_MI (1.0E9) = "1.000" & No_Break_Space & "G" & SI_Units.Names.Volt, Message => "Float_MI (1.0E9)"); -- Mega Test_Cases.Add (Passed => Float_MI (-1.0E6) = "-1.000" & No_Break_Space & "M" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E6)"); Test_Cases.Add (Passed => Float_MI (1.0E6) = "1.000" & No_Break_Space & "M" & SI_Units.Names.Volt, Message => "Float_MI (1.0E6)"); -- kilo Test_Cases.Add (Passed => Float_MI (-1.0E3) = "-1.000" & No_Break_Space & "k" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E3)"); Test_Cases.Add (Passed => Float_MI (1.0E3) = "1.000" & No_Break_Space & "k" & SI_Units.Names.Volt, Message => "Float_MI (1.0E3)"); -- None Test_Cases.Add (Passed => Float_MI (-1.0E0) = "-1.000" & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (-1.0E0)"); Test_Cases.Add (Passed => Float_MI (1.0E0) = "1.000" & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (1.0E0)"); -- milli Test_Cases.Add (Passed => Float_MI (-1.0E-3) = "-1.000" & No_Break_Space & "m" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E-3)"); Test_Cases.Add (Passed => Float_MI (1.0E-3) = "1.000" & No_Break_Space & "m" & SI_Units.Names.Volt, Message => "Float_MI (1.0E-3)"); -- micro Test_Cases.Add (Passed => Float_MI (-1.0E-6) = "-1.000" & No_Break_Space & Micro_Sign & SI_Units.Names.Volt, Message => "Float_MI (-1.0E-6)"); Test_Cases.Add (Passed => Float_MI (1.0E-6) = "1.000" & No_Break_Space & Micro_Sign & SI_Units.Names.Volt, Message => "Float_MI (1.0E-6)"); -- nano Test_Cases.Add (Passed => Float_MI (-1.0E-9) = "-1.000" & No_Break_Space & "n" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E-9)"); Test_Cases.Add (Passed => Float_MI (1.0E-9) = "1.000" & No_Break_Space & "n" & SI_Units.Names.Volt, Message => "Float_MI (1.0E-9)"); -- pico Test_Cases.Add (Passed => Float_MI (-1.0E-12) = "-1.000" & No_Break_Space & "p" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E-12)"); Test_Cases.Add (Passed => Float_MI (1.0E-12) = "1.000" & No_Break_Space & "p" & SI_Units.Names.Volt, Message => "Float_MI (1.0E-12)"); -- femto Test_Cases.Add (Passed => Float_MI (-1.0E-15) = "-1.000" & No_Break_Space & "f" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E-15)"); Test_Cases.Add (Passed => Float_MI (1.0E-15) = "1.000" & No_Break_Space & "f" & SI_Units.Names.Volt, Message => "Float_MI (1.0E-15)"); -- atto Test_Cases.Add (Passed => Float_MI (-1.0E-18) = "-1.000" & No_Break_Space & "a" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E-18)"); Test_Cases.Add (Passed => Float_MI (1.0E-18) = "1.000" & No_Break_Space & "a" & SI_Units.Names.Volt, Message => "Float_MI (1.0E-18)"); -- zepto Test_Cases.Add (Passed => Float_MI (-1.0E-21) = "-1.000" & No_Break_Space & "z" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E-21)"); Test_Cases.Add (Passed => Float_MI (1.0E-21) = "1.000" & No_Break_Space & "z" & SI_Units.Names.Volt, Message => "Float_MI (1.0E-21)"); -- yocto Test_Cases.Add (Passed => Float_MI (-1.0E-24) = "-1.000" & No_Break_Space & "y" & SI_Units.Names.Volt, Message => "Float_MI (-1.0E-24)"); Test_Cases.Add (Passed => Float_MI (1.0E-24) = "1.000" & No_Break_Space & "y" & SI_Units.Names.Volt, Message => "Float_MI (1.0E-24)"); -- almost zero, still with (smallest) prefix Test_Cases.Add (Passed => Float_MI (-5.0E-28) = "-0.001" & No_Break_Space & "y" & SI_Units.Names.Volt, Message => "Float_MI (-5.0E-28)"); Test_Cases.Add (Passed => Float_MI (5.0E-28) = "0.001" & No_Break_Space & "y" & SI_Units.Names.Volt, Message => "Float_MI (5.0E-28)"); -- virtually zero, no prefix Test_Cases.Add (Passed => Float_MI (-4.999_999_999_999_999E-28) = "-0.000" & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (-4.999_999_999_999_999E-28)"); Test_Cases.Add (Passed => Float_MI (4.999_999_999_999_999E-28) = "0.000" & No_Break_Space & SI_Units.Names.Volt, Message => "Float_MI (4.999_999_999_999_999E-28)"); -- Scaling tests for From_Prefix in SI_Units.Metric.Scaling.Prefixes loop for To_Prefix in SI_Units.Metric.Scaling.Prefixes loop Build_Lookup : -- Calculate expected value by hand. declare type Prefix_Matrix is array (SI_Units.Metric.Scaling.Prefixes, SI_Units.Metric.Scaling.Prefixes) of Long_Float; use all type SI_Units.Metric.Scaling.Prefixes; Scale_Lookup : constant Prefix_Matrix := (yocto => (yocto => 1.0E0, zepto => 1.0E-3, atto => 1.0E-6, femto => 1.0E-9, pico => 1.0E-12, nano => 1.0E-15, micro => 1.0E-18, milli => 1.0E-21, centi => 1.0E-22, deci => 1.0E-23, None => 1.0E-24, Deka => 1.0E-25, Hecto => 1.0E-26, kilo => 1.0E-27, Mega => 1.0E-30, Giga => 1.0E-33, Tera => 1.0E-36, Peta => 1.0E-39, Exa => 1.0E-42, Zetta => 1.0E-45, Yotta => 1.0E-48), zepto => (yocto => 1.0E3, zepto => 1.0E0, atto => 1.0E-3, femto => 1.0E-6, pico => 1.0E-9, nano => 1.0E-12, micro => 1.0E-15, milli => 1.0E-18, centi => 1.0E-19, deci => 1.0E-20, None => 1.0E-21, Deka => 1.0E-22, Hecto => 1.0E-23, kilo => 1.0E-24, Mega => 1.0E-27, Giga => 1.0E-30, Tera => 1.0E-33, Peta => 1.0E-36, Exa => 1.0E-39, Zetta => 1.0E-42, Yotta => 1.0E-45), atto => (yocto => 1.0E6, zepto => 1.0E3, atto => 1.0E0, femto => 1.0E-3, pico => 1.0E-6, nano => 1.0E-9, micro => 1.0E-12, milli => 1.0E-15, centi => 1.0E-16, deci => 1.0E-17, None => 1.0E-18, Deka => 1.0E-19, Hecto => 1.0E-20, kilo => 1.0E-21, Mega => 1.0E-24, Giga => 1.0E-27, Tera => 1.0E-30, Peta => 1.0E-33, Exa => 1.0E-36, Zetta => 1.0E-39, Yotta => 1.0E-42), femto => (yocto => 1.0E9, zepto => 1.0E6, atto => 1.0E3, femto => 1.0E0, pico => 1.0E-3, nano => 1.0E-6, micro => 1.0E-9, milli => 1.0E-12, centi => 1.0E-13, deci => 1.0E-14, None => 1.0E-15, Deka => 1.0E-16, Hecto => 1.0E-17, kilo => 1.0E-18, Mega => 1.0E-21, Giga => 1.0E-24, Tera => 1.0E-27, Peta => 1.0E-30, Exa => 1.0E-33, Zetta => 1.0E-36, Yotta => 1.0E-39), pico => (yocto => 1.0E12, zepto => 1.0E9, atto => 1.0E6, femto => 1.0E3, pico => 1.0E0, nano => 1.0E-3, micro => 1.0E-6, milli => 1.0E-9, centi => 1.0E-10, deci => 1.0E-11, None => 1.0E-12, Deka => 1.0E-13, Hecto => 1.0E-14, kilo => 1.0E-15, Mega => 1.0E-18, Giga => 1.0E-21, Tera => 1.0E-24, Peta => 1.0E-27, Exa => 1.0E-30, Zetta => 1.0E-33, Yotta => 1.0E-36), nano => (yocto => 1.0E15, zepto => 1.0E12, atto => 1.0E9, femto => 1.0E6, pico => 1.0E3, nano => 1.0E0, micro => 1.0E-3, milli => 1.0E-6, centi => 1.0E-7, deci => 1.0E-8, None => 1.0E-9, Deka => 1.0E-10, Hecto => 1.0E-11, kilo => 1.0E-12, Mega => 1.0E-15, Giga => 1.0E-18, Tera => 1.0E-21, Peta => 1.0E-24, Exa => 1.0E-27, Zetta => 1.0E-30, Yotta => 1.0E-33), micro => (yocto => 1.0E18, zepto => 1.0E15, atto => 1.0E12, femto => 1.0E9, pico => 1.0E6, nano => 1.0E3, micro => 1.0E0, milli => 1.0E-3, centi => 1.0E-4, deci => 1.0E-5, None => 1.0E-6, Deka => 1.0E-7, Hecto => 1.0E-8, kilo => 1.0E-9, Mega => 1.0E-12, Giga => 1.0E-15, Tera => 1.0E-18, Peta => 1.0E-21, Exa => 1.0E-24, Zetta => 1.0E-27, Yotta => 1.0E-30), milli => (yocto => 1.0E21, zepto => 1.0E18, atto => 1.0E15, femto => 1.0E12, pico => 1.0E9, nano => 1.0E6, micro => 1.0E3, milli => 1.0E0, centi => 1.0E-1, deci => 1.0E-2, None => 1.0E-3, Deka => 1.0E-4, Hecto => 1.0E-5, kilo => 1.0E-6, Mega => 1.0E-9, Giga => 1.0E-12, Tera => 1.0E-15, Peta => 1.0E-18, Exa => 1.0E-21, Zetta => 1.0E-24, Yotta => 1.0E-27), centi => (yocto => 1.0E22, zepto => 1.0E19, atto => 1.0E16, femto => 1.0E13, pico => 1.0E10, nano => 1.0E7, micro => 1.0E4, milli => 1.0E1, centi => 1.0E0, deci => 1.0E-1, None => 1.0E-2, Deka => 1.0E-3, Hecto => 1.0E-4, kilo => 1.0E-5, Mega => 1.0E-8, Giga => 1.0E-11, Tera => 1.0E-14, Peta => 1.0E-17, Exa => 1.0E-20, Zetta => 1.0E-23, Yotta => 1.0E-26), deci => (yocto => 1.0E23, zepto => 1.0E20, atto => 1.0E17, femto => 1.0E14, pico => 1.0E11, nano => 1.0E8, micro => 1.0E5, milli => 1.0E2, centi => 1.0E1, deci => 1.0E0, None => 1.0E-1, Deka => 1.0E-2, Hecto => 1.0E-3, kilo => 1.0E-4, Mega => 1.0E-7, Giga => 1.0E-10, Tera => 1.0E-13, Peta => 1.0E-16, Exa => 1.0E-19, Zetta => 1.0E-22, Yotta => 1.0E-25), None => (yocto => 1.0E24, zepto => 1.0E21, atto => 1.0E18, femto => 1.0E15, pico => 1.0E12, nano => 1.0E9, micro => 1.0E6, milli => 1.0E3, centi => 1.0E2, deci => 1.0E1, None => 1.0E0, Deka => 1.0E-1, Hecto => 1.0E-2, kilo => 1.0E-3, Mega => 1.0E-6, Giga => 1.0E-9, Tera => 1.0E-12, Peta => 1.0E-15, Exa => 1.0E-18, Zetta => 1.0E-21, Yotta => 1.0E-24), Deka => (yocto => 1.0E25, zepto => 1.0E22, atto => 1.0E19, femto => 1.0E16, pico => 1.0E13, nano => 1.0E10, micro => 1.0E7, milli => 1.0E4, centi => 1.0E3, deci => 1.0E2, None => 1.0E1, Deka => 1.0E0, Hecto => 1.0E-1, kilo => 1.0E-2, Mega => 1.0E-5, Giga => 1.0E-8, Tera => 1.0E-11, Peta => 1.0E-14, Exa => 1.0E-17, Zetta => 1.0E-20, Yotta => 1.0E-23), Hecto => (yocto => 1.0E26, zepto => 1.0E23, atto => 1.0E20, femto => 1.0E17, pico => 1.0E14, nano => 1.0E11, micro => 1.0E8, milli => 1.0E5, centi => 1.0E4, deci => 1.0E3, None => 1.0E2, Deka => 1.0E1, Hecto => 1.0E0, kilo => 1.0E-1, Mega => 1.0E-4, Giga => 1.0E-7, Tera => 1.0E-10, Peta => 1.0E-13, Exa => 1.0E-16, Zetta => 1.0E-19, Yotta => 1.0E-22), kilo => (yocto => 1.0E27, zepto => 1.0E24, atto => 1.0E21, femto => 1.0E18, pico => 1.0E15, nano => 1.0E12, micro => 1.0E9, milli => 1.0E6, centi => 1.0E5, deci => 1.0E4, None => 1.0E3, Deka => 1.0E2, Hecto => 1.0E1, kilo => 1.0E0, Mega => 1.0E-3, Giga => 1.0E-6, Tera => 1.0E-9, Peta => 1.0E-12, Exa => 1.0E-15, Zetta => 1.0E-18, Yotta => 1.0E-21), Mega => (yocto => 1.0E30, zepto => 1.0E27, atto => 1.0E24, femto => 1.0E21, pico => 1.0E18, nano => 1.0E15, micro => 1.0E12, milli => 1.0E9, centi => 1.0E8, deci => 1.0E7, None => 1.0E6, Deka => 1.0E5, Hecto => 1.0E4, kilo => 1.0E3, Mega => 1.0E0, Giga => 1.0E-3, Tera => 1.0E-6, Peta => 1.0E-9, Exa => 1.0E-12, Zetta => 1.0E-15, Yotta => 1.0E-18), Giga => (yocto => 1.0E33, zepto => 1.0E30, atto => 1.0E27, femto => 1.0E24, pico => 1.0E21, nano => 1.0E18, micro => 1.0E15, milli => 1.0E12, centi => 1.0E11, deci => 1.0E10, None => 1.0E9, Deka => 1.0E8, Hecto => 1.0E7, kilo => 1.0E6, Mega => 1.0E3, Giga => 1.0E0, Tera => 1.0E-3, Peta => 1.0E-6, Exa => 1.0E-9, Zetta => 1.0E-12, Yotta => 1.0E-15), Tera => (yocto => 1.0E36, zepto => 1.0E33, atto => 1.0E30, femto => 1.0E27, pico => 1.0E24, nano => 1.0E21, micro => 1.0E18, milli => 1.0E15, centi => 1.0E14, deci => 1.0E13, None => 1.0E12, Deka => 1.0E11, Hecto => 1.0E10, kilo => 1.0E9, Mega => 1.0E6, Giga => 1.0E3, Tera => 1.0E0, Peta => 1.0E-3, Exa => 1.0E-6, Zetta => 1.0E-9, Yotta => 1.0E-12), Peta => (yocto => 1.0E39, zepto => 1.0E36, atto => 1.0E33, femto => 1.0E30, pico => 1.0E27, nano => 1.0E24, micro => 1.0E21, milli => 1.0E18, centi => 1.0E17, deci => 1.0E16, None => 1.0E15, Deka => 1.0E14, Hecto => 1.0E13, kilo => 1.0E12, Mega => 1.0E9, Giga => 1.0E6, Tera => 1.0E3, Peta => 1.0E0, Exa => 1.0E-3, Zetta => 1.0E-6, Yotta => 1.0E-9), Exa => (yocto => 1.0E42, zepto => 1.0E39, atto => 1.0E36, femto => 1.0E33, pico => 1.0E30, nano => 1.0E27, micro => 1.0E24, milli => 1.0E21, centi => 1.0E20, deci => 1.0E19, None => 1.0E18, Deka => 1.0E17, Hecto => 1.0E16, kilo => 1.0E15, Mega => 1.0E12, Giga => 1.0E9, Tera => 1.0E6, Peta => 1.0E3, Exa => 1.0E0, Zetta => 1.0E-3, Yotta => 1.0E-6), Zetta => (yocto => 1.0E45, zepto => 1.0E42, atto => 1.0E39, femto => 1.0E36, pico => 1.0E33, nano => 1.0E30, micro => 1.0E27, milli => 1.0E24, centi => 1.0E23, deci => 1.0E22, None => 1.0E21, Deka => 1.0E20, Hecto => 1.0E19, kilo => 1.0E18, Mega => 1.0E15, Giga => 1.0E12, Tera => 1.0E9, Peta => 1.0E6, Exa => 1.0E3, Zetta => 1.0E0, Yotta => 1.0E-3), Yotta => (yocto => 1.0E48, zepto => 1.0E45, atto => 1.0E42, femto => 1.0E39, pico => 1.0E36, nano => 1.0E33, micro => 1.0E30, milli => 1.0E27, centi => 1.0E26, deci => 1.0E25, None => 1.0E24, Deka => 1.0E23, Hecto => 1.0E22, kilo => 1.0E21, Mega => 1.0E18, Giga => 1.0E15, Tera => 1.0E12, Peta => 1.0E9, Exa => 1.0E6, Zetta => 1.0E3, Yotta => 1.0E0)); begin for X in -10 .. 10 loop Calculate_Expected : declare Origin_Value : constant Long_Float := 2.0 ** X; Expected : constant Long_Float := Origin_Value * Scale_Lookup (From_Prefix, To_Prefix); begin if Expected /= 0.0 then Test_Cases.Add (Passed => Scale_Float (Value => Origin_Value, From_Prefix => From_Prefix, To_Prefix => To_Prefix) = Expected, Message => "Scale_Float (Value => " & Origin_Value'Image & ", From_Prefix => " & From_Prefix'Image & ", To_Prefix => " & To_Prefix'Image & ")"); end if; end Calculate_Expected; end loop; end Build_Lookup; end loop; end loop; pragma Warnings (Off, "static fixed-point value is not a multiple of Small"); Test_Cases.Add (Passed => Fixed_MI (Value => 0.55, Aft => 0) = "550.0" & No_Break_Space & "m" & SI_Units.Names.Ampere, Message => "Fixed_MI (0.55)"); Test_Cases.Add (Passed => Fixed_MI (Value => 0.55, Aft => 1) = "550.0" & No_Break_Space & "m" & SI_Units.Names.Ampere, Message => "Fixed_MI (0.55)"); pragma Warnings (On, "static fixed-point value is not a multiple of Small"); Print_Test_Summary : declare Total : constant Natural := Test_Cases.Num_Total; Passed : constant Natural := Test_Cases.Num_Passed; begin Ada.Text_IO.Put_Line (Item => "Test results:" & Passed'Image & " out of" & Total'Image & " succeeded."); Ada.Text_IO.Put_Line (Item => (if Passed = Total then "" else "")); Ada.Command_Line.Set_Exit_Status (Code => (if Passed = Total then Ada.Command_Line.Success else Ada.Command_Line.Failure)); end Print_Test_Summary; end Main_SI_Units_Test; alire-1.2.1/deps/si_units/test/si_units_test.gpr000066400000000000000000000005721374325474300220040ustar00rootroot00000000000000with "../si_units"; project SI_Units_Test is for Languages use ("Ada"); for Source_Dirs use ("."); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Main use ("main_si_units_test.adb"); package Compiler renames SI_Units.Compiler; package Builder renames SI_Units.Builder; package Binder renames SI_Units.Binder; end SI_Units_Test; pax_global_header00006660000000000000000000000064140273502740014516gustar00rootroot0000000000000052 comment=02a7de7568af6af7cedd1048901fae8e9477b1d9 alire-1.2.1/deps/simple_logging/000077500000000000000000000000001402735027400165455ustar00rootroot00000000000000alire-1.2.1/deps/simple_logging/.github/000077500000000000000000000000001402735027400201055ustar00rootroot00000000000000alire-1.2.1/deps/simple_logging/.github/workflows/000077500000000000000000000000001402735027400221425ustar00rootroot00000000000000alire-1.2.1/deps/simple_logging/.github/workflows/build.yml000066400000000000000000000005611402735027400237660ustar00rootroot00000000000000name: Build on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Set up GNAT toolchain run: > sudo apt-get update && sudo apt-get install gnat gprbuild - name: Build run: gprbuild -j0 -p alire-1.2.1/deps/simple_logging/.gitignore000066400000000000000000000001411402735027400205310ustar00rootroot00000000000000# Object files lib obj # Ada Library Information *.ali # Miscellaneous cruft *.cgpr *.db *.xml alire-1.2.1/deps/simple_logging/LICENSE000066400000000000000000000167431402735027400175650ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. alire-1.2.1/deps/simple_logging/README.md000066400000000000000000000026271402735027400200330ustar00rootroot00000000000000[![build](https://github.com/alire-project/simple_logging/workflows/Build/badge.svg)](https://github.com/alire-project/simple_logging/actions) # simple_logging Easy-to-use logging facilities for output to console in Ada programs. Preelaborable package. For example: ```ada with Simple_Logging; use Simple_Logging; procedure Hello_World is begin Log ("Hello, world!"); -- Info level (default) Log ("Bye!", Warning); -- Warning level Log ("That took 3 mins to write", Debug); -- Won't show with default log level. Simple_Logging.Level := Debug; -- Lower the threshold for output Log ("Checking...", Debug); -- Now it will show. Log ("Something failed", Error); -- Error! end Hello_World; ``` The corresponding output will be: ``` Hello, world! Warning: Bye! -->> Checking... ERROR: Something failed ``` Alternatively, you can not use the package and do it like this: ```ada with Simple_Logging; procedure Hello_World is package Log renames Simple_Logging; begin Log.Info ("Hello, world!"); Log.Warning ("Bye!"); -- Warning level Log.Debug ("That took 3 mins to write"); Simple_Logging.Level := Debug; Log.Debug ("Checking..."); Log.Error ("Something failed"); end Hello_World; ``` With the possible benefit that you cannot forget the logging level. alire-1.2.1/deps/simple_logging/alire.toml000066400000000000000000000004031402735027400205330ustar00rootroot00000000000000name = "simple_logging" version = "1.2-dev" description = "Simple logging to console" licenses = "LGPL-3.0-only" authors = [ "Alejandro R. Mosteo", ] maintainers = [ "alejandro@mosteo.com", ] maintainers-logins = [ "mosteo", ] tags = ["logging", "utility"] alire-1.2.1/deps/simple_logging/simple_logging.gpr000066400000000000000000000010311402735027400222510ustar00rootroot00000000000000project Simple_Logging is for Library_Name use "simple_logging"; for Library_Version use "1.0.0"; for Source_Dirs use ("src"); for Object_Dir use "obj"; for Library_Dir use "lib"; package Builder is for Switches ("ada") use ("-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnata", "-gnat12", "-gnato", "-fstack-check"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; end Simple_Logging; alire-1.2.1/deps/simple_logging/src/000077500000000000000000000000001402735027400173345ustar00rootroot00000000000000alire-1.2.1/deps/simple_logging/src/simple_logging-decorators.adb000066400000000000000000000033431402735027400251510ustar00rootroot00000000000000with Simple_Logging.Support; package body Simple_Logging.Decorators is ------------ -- Prefix -- ------------ function Prefix (Level : Levels) return String is (case Level is when Always => "", when Error => "ERROR: ", when WARNING => "Warning: ", when Info => "", when Detail => "-> ", when Debug => "-->> "); ----------------------------- -- Default_Level_Decorator -- ----------------------------- function Default_Level_Decorator (Level : Levels; Message : String) return String is (Prefix (Level) & Message); -------------------------------- -- Default_Location_Decorator -- -------------------------------- function No_Location_Decorator (Entity, Location, Message : String) return String is pragma Unreferenced (Location, Entity); begin return Message; end No_Location_Decorator; ------------------------------- -- Simple_Location_Decorator -- ------------------------------- function Simple_Location_Decorator (Entity, Location, Message : String) return String is ("[" & Support.Rpad ((if Entity'Length <= Entity_Width then Entity else Support.Elide (Entity, Entity_Width)), Entity_Width) & "]" & " (" & Support.Rpad ((if Location'Length <= Location_Width then Location else Support.Elide (Location, Location_Width)), Location_Width) & ")" & " " & Message); end Simple_Logging.Decorators; alire-1.2.1/deps/simple_logging/src/simple_logging-decorators.ads000066400000000000000000000036631402735027400251770ustar00rootroot00000000000000package Simple_Logging.Decorators with Preelaborate is -------------- -- Defaults -- -------------- -- These functions are used by default for log decoration. -- They take the log message and modify it somehow. function Default_Level_Decorator (Level : Levels; Message : String) return String; -- Prefixes the log message with ERROR/Warning/(nothing)/->/-->>. function No_Location_Decorator (Entity, Location, Message : String) return String; -- Does not use the location/entity information, Message is kept as-is. Location_Width : Positive range 2 .. Positive'Last := 24; Entity_Width : Positive range 2 .. Positive'Last := 24; function Simple_Location_Decorator (Entity, Location, Message : String) return String; -- Prefixes the log message with fixed-with entity/location. -- Uses the previous two declared variables for the width. ------------------- -- Configuration -- ------------------- -- These are the functions that the user can set to other preferred values. -- The output message is: -- Location_Decorator (Level_Decorator (Message)) Level_Decorator : access function (Level : Levels; Message : String) return String := Default_Level_Decorator'Access; -- Use simple text prefixes for normal levels, markers for verbose levels. Location_Decorator : access function (Entity, Location, Message : String) return String := No_Location_Decorator'Access; -- No entity/location information by default. -- See Simple_Location_Decorator above for a "[entity] (location) Msg" option. end Simple_Logging.Decorators; alire-1.2.1/deps/simple_logging/src/simple_logging-filtering.adb000066400000000000000000000166271402735027400250000ustar00rootroot00000000000000with Ada.Characters.Handling; with Ada.Containers.Indefinite_Ordered_Sets; with Ada.Exceptions; with Ada.Strings.Fixed; with GNAT.IO; with Simple_Logging.Decorators; package body Simple_Logging.Filtering is package String_Sets is new Ada.Containers.Indefinite_Ordered_Sets (String); Substrings : String_Sets.Set; Exceptions : String_Sets.Set; -------------- -- Contains -- -------------- function Contains (Text, Substring : String) return Boolean is (Ada.Strings.Fixed.Index (Ada.Characters.Handling.To_Lower (Text), Substring) > 0); -- patterns are lowercased on agregation. -------------------- -- Default_Filter -- -------------------- function Default_Filter (Message : String; Level : Levels; Entity : String; Location : String) return Boolean is pragma Unreferenced (Message, Level); Found : Boolean := False; Except : Boolean := False; begin for Str of Substrings loop if Contains (Entity, Str) or else Contains (Location, Str) then Found := True; exit; end if; end loop; if Found then for Str of Exceptions loop if Contains (Entity, Str) or else Contains (Location, Str) then Except := True; exit; end if; end loop; end if; return (Mode = Blacklist and then (not Found or else Except)) or else (Mode = Whitelist and then (Found and then not Except)); end Default_Filter; ------------------- -- Add_Substring -- ------------------- procedure Add_Substring (Str : String) is begin Substrings.Include (Ada.Characters.Handling.To_Lower (Str)); end Add_Substring; ------------------- -- Add_Exception -- ------------------- procedure Add_Exception (Str : String) is begin Exceptions.Include (Ada.Characters.Handling.To_Lower (Str)); end Add_Exception; --------------------- -- Add_From_String -- --------------------- function Add_From_String (Str : String; Say : Boolean := False) return Boolean is Bad_Syntax : exception; ---------------- -- Add_Scopes -- ---------------- procedure Add_Scopes (Debug_Arg : String) is -- Receives as-is the --debug/-d[ARG] argument. This is a list of -- optionally comma-separated, plus/minus prefixed substrings that will -- be used for filtering against the enclosing entity/source location. -- Example whitelisting argument: +commands,-search -- Example blacklisting argument: -commands,+search -- The first sign puts the filter in (-) blacklist / (+) whitelist mode. -- In whitelist mode, only the given substrings are logged, unless later -- added as exception. E.g., in the "+commands,-search" example, only -- commands traces would be logged (because of whitelist mode), except -- the ones for the search command (because given as an exception). -- In the "-commands,+search" example for blacklist mode, everything but -- command traces would be logged, but search command traces would be -- logged because that's the exception. -- Once scopes are used, we activate logging of enclosing entity and -- location to provide full logging information. Pos : Integer := Debug_Arg'First; -- Points to the beginning of the next scope in Debug_Arg -------------------- -- Next_With_Sign -- -------------------- function Next_With_Sign return String is -- Look from Debug_Arg (Pos) onwards to find a comma, sign, or end. -- Returns "" when no more scopes. Otherwise, returns a single scope -- with its sign (e.g., "+commands") Old_Pos : constant Integer := Pos; begin if Pos >= Debug_Arg'Last then return ""; end if; for I in Pos + 1 .. Debug_Arg'Last loop if Debug_Arg (I) in ',' | '+' | '-' then if Pos = I - 1 then -- Means consecutive separators, i.e. no-no raise Bad_Syntax with "Invalid logging scope separator: " & Debug_Arg; end if; Pos := I; if Debug_Arg (Pos) = ',' then Pos := Pos + 1; end if; return Debug_Arg (Old_Pos .. I - 1); end if; end loop; -- We reached the end: Pos := Debug_Arg'Last + 1; return Debug_Arg (Old_Pos .. Debug_Arg'Last); end Next_With_Sign; begin if Str = "" then return; end if; -- Activate scope logging: Decorators.Location_Decorator := Decorators.Simple_Location_Decorator'Access; case Debug_Arg (Str'First) is when '+' => Simple_Logging.Filtering.Mode := Whitelist; when '-' => Simple_Logging.Filtering.Mode := Blacklist; when others => raise Bad_Syntax with "Debug filters must be prefixed with + or -."; end case; -- Output how we are going to filter: if Say then GNAT.IO.Put_Line ("Filtering mode: " & Simple_Logging.Filtering.Mode'Img); end if; -- Process scopes according to mode and sign loop declare Scope_With_Sign : constant String := Next_With_Sign; begin -- Nothing more to process if Scope_With_Sign = "" then return; end if; -- Add a single scope declare Sign : constant Character := Scope_With_Sign (Scope_With_Sign'First); Scope : constant String := Scope_With_Sign (Scope_With_Sign'First + 1 .. Scope_With_Sign'Last); begin if Sign not in '-' | '+' then raise Bad_Syntax with "ERROR: Missing +/- before filter: " & Scope_With_Sign; end if; if (Filtering.Mode = Filtering.Blacklist and then Sign = '-') or (Filtering.Mode = Filtering.Whitelist and then Sign = '+') then if Say then GNAT.IO.Put_Line ("Filtering substring: " & Scope); end if; Filtering.Add_Substring (Scope); else if Say then GNAT.IO.Put_Line ("Filtering exception: " & Scope); end if; Filtering.Add_Exception (Scope); end if; end; end; end loop; end Add_Scopes; begin Add_Scopes (Str); return True; exception when E : Bad_Syntax => Mode := Blacklist; Substrings.Clear; Exceptions.Clear; if Say then GNAT.IO.Put_Line (Ada.Exceptions.Exception_Message (E)); end if; return False; end Add_From_String; end Simple_Logging.Filtering; alire-1.2.1/deps/simple_logging/src/simple_logging-filtering.ads000066400000000000000000000053751402735027400250170ustar00rootroot00000000000000package Simple_Logging.Filtering with Preelaborate is -- Filtering enables to accept/filter out messages that will get displayed. -- By default, no filtering occurs. -- See below how to configure the default filter. function Default_Filter (Message : String; Level : Levels; Entity : String; Location : String) return Boolean; -- The default filter accepts everything, unless configured with the calls -- below. -- The implementation doesn't strive to be super-efficient; it only -- guarantees logarithmic degradation on look-up times. ------------------- -- Configuration -- ------------------- -- The following function can be changed to an entirely new filter. -- Otherwise, see below for configuration options for the default filter. Accept_Message : access function (Message : String; Level : Levels; Entity : String; Location : String) return Boolean := Default_Filter'Access; type Filtering_Modes is (Blacklist, Whitelist); -- In blacklist mode, by default all passes but explicitly blacklisted. -- In whitelist mode, nothing passes but whitelisted. -- En each mode, you can further add exceptions to the list that operate -- in the contrary mode. Mode : Filtering_Modes := Blacklist; -- MOde for the Default_Filter procedure Add_Substring (Str : String); -- Something that will be blacklisted/whitelisted. -- It case-insensitively checks the Location and the Entity of the message. procedure Add_Exception (Str : String); -- Add an exception to the regular mode. For example, in Blacklist mode: -- Add_Substring ("foo"); -- blacklists messages containing "foo" -- Add_Exception ("bar"); -- unless they contain "bar" too. -- In whitelist mode, something similar but in reverse will happen. function Add_From_String (Str : String; Say : Boolean := False) return Boolean; -- Process an entire string (e.g. coming from a command-line argument) to -- configure filtering. String syntax is: (+|-)[scope][[,](+|-)scope]... -- Will return False if syntax is wrong. Lists will be emptied in that case. -- If Say = True, the mode/scopes will be written to stdout for reference. -- Examples: -- + (empty whitelist, nothing will pass) -- +foo,-bar (whitelist foo, except bar) -- - (empty blacklist, nothing will be blocked) -- -foo,+bar (blacklist foo, except bar) -- -foo+bar (commas are optional) -- The very first sign sets the mode to whitelist (+) or blacklist (-). end Simple_Logging.Filtering; alire-1.2.1/deps/simple_logging/src/simple_logging-support.adb000066400000000000000000000012001402735027400245060ustar00rootroot00000000000000package body Simple_Logging.Support is ----------- -- Elide -- ----------- function Elide (Str : String; Len : Natural; Ellipsis : String := "..") return String is (if Str'Length <= Len then Str else Ellipsis & Str (Str'First + (Str'Length - Len + Ellipsis'Length) .. Str'Last)); ---------- -- Rpad -- ---------- function Rpad (Str : String; Len : Natural; Char : Character := ' ') return String is (if Str'Length >= Len then Str else Str & String'(1 .. Len - Str'Length => Char)); end Simple_Logging.Support; alire-1.2.1/deps/simple_logging/src/simple_logging-support.ads000066400000000000000000000007771402735027400245510ustar00rootroot00000000000000package Simple_Logging.Support with Preelaborate is ----------- -- Elide -- ----------- function Elide (Str : String; Len : Natural; Ellipsis : String := "..") return String; -- If Str'Lenght > Len, return "..remainder_of_string". ---------- -- Rpad -- ---------- function Rpad (Str : String; Len : Natural; Char : Character := ' ') return String; -- Left-justify String by padding with Char on the right. end Simple_Logging.Support; alire-1.2.1/deps/simple_logging/src/simple_logging.adb000066400000000000000000000147361402735027400230160ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Multisets; with GNAT.IO; with Simple_Logging.Decorators; with Simple_Logging.Filtering; pragma Warnings (Off); -- This is compiler-internal unit. We only use the Clock, which is highly -- unlikely to change its specification. with System.OS_Primitives; pragma Warnings (On); package body Simple_Logging is --------- -- Log -- --------- procedure Log (Message : String; Level : Levels := Info; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location) is begin if Level <= Simple_Logging.Level and then Filtering.Accept_Message (Message, Level, Entity, Location) then Clear_Status_Line; GNAT.IO.Put_Line (Decorators.Location_Decorator (Entity, Location, Decorators.Level_Decorator (Level, Message))); end if; end Log; ------------ -- Always -- ------------ procedure Always (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location) is begin Log (Msg, Always, Entity, Location); end Always; ----------- -- Error -- ----------- procedure Error (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location) is begin Log (Msg, Error, Entity, Location); end Error; ------------- -- Warning -- ------------- procedure Warning (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location) is begin Log (Msg, Warning, Entity, Location); end Warning; ---------- -- Info -- ---------- procedure Info (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location) is begin Log (Msg, Info, Entity, Location); end Info; ------------ -- Detail -- ------------ procedure Detail (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location) is begin Log (Msg, Detail, Entity, Location); end Detail; ----------- -- Debug -- ----------- procedure Debug (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location) is begin Log (Msg, Debug, Entity, Location); end Debug; ----------------- -- STATUS LINE -- ----------------- package Status_Sets is new Ada.Containers.Indefinite_Ordered_Multisets (Ongoing_Data); function Internal_Clock return Duration renames System.OS_Primitives.Clock; -- We need a preelaborable source of time with sub-second granularity, -- which discards GNAT.OS_Lib date functions. Statuses : Status_Sets.Set; subtype Indicator_Range is Positive range 1 .. 4; Indicator_Nice : constant array (Indicator_Range) of String (1 .. 3) := ("â—´", "â—·", "â—¶", "â—µ"); Indicator_Basic : constant array (Indicator_Range) of String (1 .. 1) := (".", "o", "O", "o"); Ind_Pos : Positive := 1; Last_Step : Duration := 0.0; function Indicator return String is (if Is_TTY and then not ASCII_Only then Indicator_Nice (Ind_Pos) else Indicator_Basic (Ind_Pos)); -------------- -- Activity -- -------------- function Activity (Text : String; Level : Levels := Info) return Ongoing is begin return This : Ongoing := (Ada.Finalization.Limited_Controlled with Data => (Level => Level, Start => Internal_Clock, Text => To_Unbounded_String (Text))) do Debug ("Status start: " & To_String (This.Data.Text)); Statuses.Insert (This.Data); This.Step; end return; end Activity; ----------------------- -- Build_Status_Line -- ----------------------- function Build_Status_Line return String is Line : Unbounded_String; begin for Status of Statuses loop if Status.Level <= Simple_Logging.Level then Append (Line, Status.Text & "... "); end if; end loop; if Length (Line) > 0 then Line := Indicator & " " & Line; end if; return To_String (Line); end Build_Status_Line; ----------------------- -- Clear_Status_Line -- ----------------------- procedure Clear_Status_Line is Line : constant String := Build_Status_Line; begin if Is_TTY and then Line'Length > 0 then GNAT.IO.Put (ASCII.CR & (1 .. Line'Length => ' ') & ASCII.CR); end if; end Clear_Status_Line; -------------- -- Finalize -- -------------- overriding procedure Finalize (This : in out Ongoing) is begin Debug ("Status ended: " & To_String (This.Data.Text)); Clear_Status_Line; Statuses.Difference (Status_Sets.To_Set (This.Data)); This.Step; end Finalize; ---------- -- Step -- ---------- procedure Step (This : in out Ongoing; New_Text : String := "") is Line : constant String := Build_Status_Line; begin -- Update status if needed if New_Text /= "" then Statuses.Delete (This.Data); This.Data.Text := To_Unbounded_String (New_Text); Statuses.Insert (This.Data); end if; if Is_TTY and then Line'Length > 0 then Clear_Status_Line; GNAT.IO.Put (ASCII.CR & Line); -- Advance the spinner if Last_Step = 0.0 or else Internal_Clock - Last_Step >= 1.0 then Last_Step := Internal_Clock; Ind_Pos := Ind_Pos + 1; if Ind_Pos > Indicator_Range'Last then Ind_Pos := Indicator_Range'First; end if; end if; end if; end Step; end Simple_Logging; alire-1.2.1/deps/simple_logging/src/simple_logging.ads000066400000000000000000000106251402735027400230300ustar00rootroot00000000000000with GNAT.Source_Info; private with Ada.Finalization; private with Ada.Strings.Unbounded; package Simple_Logging with Preelaborate is -- NOTE: this library is thread-unsafe. Using it with multithreaded -- applications will likely result in mangled output. -- Since the purpose is to have simultaneously "simple" yet flexible -- logging, this package enables the configuration of a single logger -- to console. -- That said, a number of customization options are available with the -- Decorators/Filtering child packages. type Levels is (Always, Error, Warning, Info, Detail, Debug); -- From most important to less important -- Or, from less verbose to more verbose Level : Levels := Info; -- Any message at the same level or below will be output to console Is_TTY : Boolean := False; -- Set this to True when you know log is not being redirected. This flag -- suppresses the use of busy statuses (see below) which, by relying -- on ASCII.CR, will greatly pollute logfiles. ASCII_Only : Boolean := True; -- Restrict the deliberate use of non-ASCII chars (currently only for the -- busy status spinner). procedure Log (Message : String; Level : Levels := Info; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location); -- Report a log message -- Log by level. -- Useful if you want to use a package renaming as prefix, -- e.g. : Log.Info ("Blah"); procedure Always (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location); procedure Error (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location); procedure Warning (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location); procedure Info (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location); procedure Detail (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location); procedure Debug (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location); procedure Never (Msg : String; Entity : String := Gnat.Source_Info.Enclosing_Entity; Location : String := Gnat.Source_Info.Source_Location) is null; -- Quietly drop ----------------- -- Status line -- ----------------- type Ongoing (<>) is tagged limited private; -- The status line is used to present an ongoing activity. This is done -- through a scoped type. Several nested statuses can be created, and the -- trailing '...' is added by this prompt. The rest of logging subprograms -- will emit normally over the status line. function Activity (Text : String; Level : Levels := Info) return Ongoing; procedure Step (This : in out Ongoing; New_Text : String := ""); -- Say that progress was made, which will advance the spinner. Optionally, -- update the text to display in this activity. private use Ada.Strings.Unbounded; type Ongoing_Data is record Start : Duration; Level : Levels; Text : Unbounded_String; end record; -- Non-limited data to be stored in collections type Ongoing is new Ada.Finalization.Limited_Controlled with record Data : Ongoing_Data; end record; function "<" (L, R : Ongoing_Data) return Boolean is (L.Start < R.Start or else (L.Start = R.Start and then L.Level < R.Level) or else (L.Start = R.Start and then L.Level = R.Level and then L.Text < R.Text)); overriding procedure Finalize (This : in out Ongoing); function Build_Status_Line return String; procedure Clear_Status_Line; end Simple_Logging; pax_global_header00006660000000000000000000000064137571556420014531gustar00rootroot0000000000000052 comment=2df9b1182544359c751544e52e14c94830d99fa6 alire-1.2.1/deps/spdx/000077500000000000000000000000001375715564200145375ustar00rootroot00000000000000alire-1.2.1/deps/spdx/.github/000077500000000000000000000000001375715564200160775ustar00rootroot00000000000000alire-1.2.1/deps/spdx/.github/workflows/000077500000000000000000000000001375715564200201345ustar00rootroot00000000000000alire-1.2.1/deps/spdx/.github/workflows/main.yml000066400000000000000000000021651375715564200216070ustar00rootroot00000000000000name: Build and test on: [pull_request, push] jobs: linux-build: name: Build and test on Linux runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: ada-actions/toolchain@ce2020 with: distrib: community - uses: alire-project/setup-alire@latest-stable - uses: reviewdog/action-setup@v1 - name: Build env: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | status=0 GPRBUILD_FLAGS="-XSPDX_COMPILE_CHECKS=enabled -XSPDX_RUNTIME_CHECKS=enabled -XSPDX_STYLE_CHECKS=enabled -XSPDX_CONTRACTS=enabled" gprbuild -P tests/tests.gpr ${GPRBUILD_FLAGS} -gnatef > output.txt 2>&1 || status=$? cat output.txt cat output.txt | reviewdog -efm="%f:%l:%c: %m" -diff="git diff master" --reporter=github-pr-review # Check for errors if [ $status -ne 0 ]; then echo "ERROR: gprbuild returned $status" # This will cause the workflow to exit with $status bash -c "exit $status" fi - name: Alire build run: alr build - name: Tests run: ./tests/obj/main alire-1.2.1/deps/spdx/.gitignore000066400000000000000000000000661375715564200165310ustar00rootroot00000000000000obj/ lib/ alire/ alire.lock tests/obj/ scripts/*.json alire-1.2.1/deps/spdx/LICENSE000066400000000000000000000020601375715564200155420ustar00rootroot00000000000000MIT License Copyright (c) 2020 Fabien Chouteau Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. alire-1.2.1/deps/spdx/README.md000066400000000000000000000000641375715564200160160ustar00rootroot00000000000000# spdx_ada Ada library for SPDX License Expressions alire-1.2.1/deps/spdx/alire.toml000066400000000000000000000004671375715564200165370ustar00rootroot00000000000000name = "spdx" description = "SPDX License Expression Validator" version = "0.2.0" authors = ["Fabien Chouteau"] maintainers = ["Fabien Chouteau "] maintainers-logins = ["Fabien-Chouteau"] licenses = ["MIT"] website="https://github.com/Fabien-Chouteau/spdx_ada" tags = ['spdx', 'license'] alire-1.2.1/deps/spdx/scripts/000077500000000000000000000000001375715564200162265ustar00rootroot00000000000000alire-1.2.1/deps/spdx/scripts/gen_license_list.py000066400000000000000000000070341375715564200221120ustar00rootroot00000000000000import wget import json import os os.path.abspath(__file__) licenses_url='https://raw.githubusercontent.com/spdx/license-list-data/master/json/licenses.json' exceptions_url='https://raw.githubusercontent.com/spdx/license-list-data/master/json/exceptions.json' def get(url): with open(wget.download(url)) as json_file: return json.load(json_file) def To_Ada_Id(id): if id[0].isnumeric(): id = 'Id_' + id return id.replace('-', '_').replace('.', '_').replace('+', 'p') def To_Ada_String(str): return '"' + str.encode("ascii","ignore").replace('"', '""') + '"' raw_licenses = get(licenses_url) licenses_version = raw_licenses['licenseListVersion'] licenses = [] # licenses.append({"id": u"Unknown", 'name': u"Unknown license"}) for lic in raw_licenses['licenses']: if not lic['isDeprecatedLicenseId']: licenses.append({'id': lic['licenseId'], 'name': lic['name']}) raw_exceptions = get(exceptions_url) exceptions_version = raw_exceptions['licenseListVersion'] exceptions = [] for lic in raw_exceptions['exceptions']: if not lic['isDeprecatedLicenseId']: exceptions.append({'id': lic['licenseExceptionId'], 'name': lic['name']}) def gen(package, filename, data, version): with open(filename, 'w') as file: file.write("package SPDX.%s is\n" % package) file.write("\n") file.write(" pragma Style_Checks (Off); -- Genrated code\n") file.write("\n") file.write(" Version : constant String :=\"%s\";\n" % version) file.write("\n") file.write(" type Id is (\n") for i, lic in enumerate(data): if i != len(data) - 1: file.write(" %s,\n" % To_Ada_Id(lic['id'])) else: file.write(" %s);\n" % To_Ada_Id(lic['id'])) file.write("\n") file.write(" type String_Access is not null access constant String;\n") file.write(" Img_Ptr : constant array (Id) of String_Access :=\n") file.write(" (\n") for i, lic in enumerate(data): if i != len(data) - 1: file.write (" %s => new String'(%s),\n" % (To_Ada_Id(lic['id']), To_Ada_String(lic['id']))) else: file.write (" %s => new String'(%s));\n" % (To_Ada_Id(lic['id']), To_Ada_String(lic['id']))) file.write("\n"); file.write(" function Img (I : Id) return String\n") file.write(" is (Img_Ptr (I).all);\n") file.write("\n"); file.write(" Name_Ptr : constant array (Id) of String_Access :=\n") file.write(" (\n") for i, lic in enumerate(data): if i != len(data) - 1: file.write (" %s => new String'(%s),\n" % (To_Ada_Id(lic['id']), To_Ada_String(lic['name']))) else: file.write (" %s => new String'(%s));\n" % (To_Ada_Id(lic['id']), To_Ada_String(lic['name']))) file.write("\n"); file.write(" function Name (I : Id) return String\n") file.write(" is (Name_Ptr (I).all);\n") file.write("\n"); file.write(" function Valid_Id (Str : String) return Boolean;\n") file.write(" function From_Id (Str : String) return Id;\n") file.write("\n"); file.write("end SPDX.%s;\n" % package) src_dir=os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'src') gen('Licenses', os.path.join(src_dir, 'spdx-licenses.ads'), licenses, licenses_version) gen('Exceptions', os.path.join(src_dir, 'spdx-exceptions.ads'), exceptions, exceptions_version) alire-1.2.1/deps/spdx/spdx.gpr000066400000000000000000000053371375715564200162370ustar00rootroot00000000000000project Spdx is for Library_Name use "Spdx"; for Library_Version use "0.1.0"; for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Library_Dir use "lib"; type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := external ("SPDX_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); for Library_Kind use Library_Type; type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("SPDX_COMPILE_CHECKS", "disabled"); Runtime_Checks : Enabled_Kind := External ("SPDX_RUNTIME_CHECKS", "disabled"); Style_Checks : Enabled_Kind := External ("SPDX_STYLE_CHECKS", "disabled"); Contracts_Checks : Enabled_Kind := External ("SPDX_CONTRACTS", "disabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("SPDX_BUILD_MODE", "optimize"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Supress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => null; Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-d", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnatyO"); -- Overriding subprograms explicitly marked as such when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => null; Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Spdx; alire-1.2.1/deps/spdx/src/000077500000000000000000000000001375715564200153265ustar00rootroot00000000000000alire-1.2.1/deps/spdx/src/spdx-exceptions.adb000066400000000000000000000007661375715564200211440ustar00rootroot00000000000000package body SPDX.Exceptions is -------------- -- Valid_Id -- -------------- function Valid_Id (Str : String) return Boolean is begin return (for some I in Id => Str = Img (I)); end Valid_Id; ------------- -- From_Id -- ------------- function From_Id (Str : String) return Id is begin for I in Id loop if Str = Img (I) then return I; end if; end loop; raise Program_Error; end From_Id; end SPDX.Exceptions; alire-1.2.1/deps/spdx/src/spdx-exceptions.ads000066400000000000000000000167041375715564200211640ustar00rootroot00000000000000package SPDX.Exceptions is pragma Style_Checks (Off); -- Genrated code Version : constant String :="3.10-14-g0fb8a59"; type Id is ( GCC_exception_2_0, openvpn_openssl_exception, GPL_3_0_linking_exception, Fawkes_Runtime_exception, u_boot_exception_2_0, PS_or_PDF_font_exception_20170817, gnu_javamail_exception, LGPL_3_0_linking_exception, DigiRule_FOSS_exception, LLVM_exception, Linux_syscall_note, GPL_3_0_linking_source_exception, Qwt_exception_1_0, Id_389_exception, mif_exception, eCos_exception_2_0, CLISP_exception_2_0, Bison_exception_2_2, Libtool_exception, LZMA_exception, OpenJDK_assembly_exception_1_0, Font_exception_2_0, OCaml_LGPL_linking_exception, GCC_exception_3_1, Bootloader_exception, SHL_2_0, Classpath_exception_2_0, Swift_exception, Autoconf_exception_2_0, FLTK_exception, freertos_exception_2_0, Universal_FOSS_exception_1_0, WxWindows_exception_3_1, OCCT_exception_1_0, Autoconf_exception_3_0, i2p_gpl_java_exception, GPL_CC_1_0, Qt_LGPL_exception_1_1, SHL_2_1, Qt_GPL_exception_1_0); type String_Access is not null access constant String; Img_Ptr : constant array (Id) of String_Access := ( GCC_exception_2_0 => new String'("GCC-exception-2.0"), openvpn_openssl_exception => new String'("openvpn-openssl-exception"), GPL_3_0_linking_exception => new String'("GPL-3.0-linking-exception"), Fawkes_Runtime_exception => new String'("Fawkes-Runtime-exception"), u_boot_exception_2_0 => new String'("u-boot-exception-2.0"), PS_or_PDF_font_exception_20170817 => new String'("PS-or-PDF-font-exception-20170817"), gnu_javamail_exception => new String'("gnu-javamail-exception"), LGPL_3_0_linking_exception => new String'("LGPL-3.0-linking-exception"), DigiRule_FOSS_exception => new String'("DigiRule-FOSS-exception"), LLVM_exception => new String'("LLVM-exception"), Linux_syscall_note => new String'("Linux-syscall-note"), GPL_3_0_linking_source_exception => new String'("GPL-3.0-linking-source-exception"), Qwt_exception_1_0 => new String'("Qwt-exception-1.0"), Id_389_exception => new String'("389-exception"), mif_exception => new String'("mif-exception"), eCos_exception_2_0 => new String'("eCos-exception-2.0"), CLISP_exception_2_0 => new String'("CLISP-exception-2.0"), Bison_exception_2_2 => new String'("Bison-exception-2.2"), Libtool_exception => new String'("Libtool-exception"), LZMA_exception => new String'("LZMA-exception"), OpenJDK_assembly_exception_1_0 => new String'("OpenJDK-assembly-exception-1.0"), Font_exception_2_0 => new String'("Font-exception-2.0"), OCaml_LGPL_linking_exception => new String'("OCaml-LGPL-linking-exception"), GCC_exception_3_1 => new String'("GCC-exception-3.1"), Bootloader_exception => new String'("Bootloader-exception"), SHL_2_0 => new String'("SHL-2.0"), Classpath_exception_2_0 => new String'("Classpath-exception-2.0"), Swift_exception => new String'("Swift-exception"), Autoconf_exception_2_0 => new String'("Autoconf-exception-2.0"), FLTK_exception => new String'("FLTK-exception"), freertos_exception_2_0 => new String'("freertos-exception-2.0"), Universal_FOSS_exception_1_0 => new String'("Universal-FOSS-exception-1.0"), WxWindows_exception_3_1 => new String'("WxWindows-exception-3.1"), OCCT_exception_1_0 => new String'("OCCT-exception-1.0"), Autoconf_exception_3_0 => new String'("Autoconf-exception-3.0"), i2p_gpl_java_exception => new String'("i2p-gpl-java-exception"), GPL_CC_1_0 => new String'("GPL-CC-1.0"), Qt_LGPL_exception_1_1 => new String'("Qt-LGPL-exception-1.1"), SHL_2_1 => new String'("SHL-2.1"), Qt_GPL_exception_1_0 => new String'("Qt-GPL-exception-1.0")); function Img (I : Id) return String is (Img_Ptr (I).all); Name_Ptr : constant array (Id) of String_Access := ( GCC_exception_2_0 => new String'("GCC Runtime Library exception 2.0"), openvpn_openssl_exception => new String'("OpenVPN OpenSSL Exception"), GPL_3_0_linking_exception => new String'("GPL-3.0 Linking Exception"), Fawkes_Runtime_exception => new String'("Fawkes Runtime Exception"), u_boot_exception_2_0 => new String'("U-Boot exception 2.0"), PS_or_PDF_font_exception_20170817 => new String'("PS/PDF font exception (2017-08-17)"), gnu_javamail_exception => new String'("GNU JavaMail exception"), LGPL_3_0_linking_exception => new String'("LGPL-3.0 Linking Exception"), DigiRule_FOSS_exception => new String'("DigiRule FOSS License Exception"), LLVM_exception => new String'("LLVM Exception"), Linux_syscall_note => new String'("Linux Syscall Note"), GPL_3_0_linking_source_exception => new String'("GPL-3.0 Linking Exception (with Corresponding Source)"), Qwt_exception_1_0 => new String'("Qwt exception 1.0"), Id_389_exception => new String'("389 Directory Server Exception"), mif_exception => new String'("Macros and Inline Functions Exception"), eCos_exception_2_0 => new String'("eCos exception 2.0"), CLISP_exception_2_0 => new String'("CLISP exception 2.0"), Bison_exception_2_2 => new String'("Bison exception 2.2"), Libtool_exception => new String'("Libtool Exception"), LZMA_exception => new String'("LZMA exception"), OpenJDK_assembly_exception_1_0 => new String'("OpenJDK Assembly exception 1.0"), Font_exception_2_0 => new String'("Font exception 2.0"), OCaml_LGPL_linking_exception => new String'("OCaml LGPL Linking Exception"), GCC_exception_3_1 => new String'("GCC Runtime Library exception 3.1"), Bootloader_exception => new String'("Bootloader Distribution Exception"), SHL_2_0 => new String'("Solderpad Hardware License v2.0"), Classpath_exception_2_0 => new String'("Classpath exception 2.0"), Swift_exception => new String'("Swift Exception"), Autoconf_exception_2_0 => new String'("Autoconf exception 2.0"), FLTK_exception => new String'("FLTK exception"), freertos_exception_2_0 => new String'("FreeRTOS Exception 2.0"), Universal_FOSS_exception_1_0 => new String'("Universal FOSS Exception, Version 1.0"), WxWindows_exception_3_1 => new String'("WxWindows Library Exception 3.1"), OCCT_exception_1_0 => new String'("Open CASCADE Exception 1.0"), Autoconf_exception_3_0 => new String'("Autoconf exception 3.0"), i2p_gpl_java_exception => new String'("i2p GPL+Java Exception"), GPL_CC_1_0 => new String'("GPL Cooperation Commitment 1.0"), Qt_LGPL_exception_1_1 => new String'("Qt LGPL exception 1.1"), SHL_2_1 => new String'("Solderpad Hardware License v2.1"), Qt_GPL_exception_1_0 => new String'("Qt GPL exception 1.0")); function Name (I : Id) return String is (Name_Ptr (I).all); function Valid_Id (Str : String) return Boolean; function From_Id (Str : String) return Id; end SPDX.Exceptions; alire-1.2.1/deps/spdx/src/spdx-licenses.adb000066400000000000000000000007621375715564200205640ustar00rootroot00000000000000package body SPDX.Licenses is -------------- -- Valid_Id -- -------------- function Valid_Id (Str : String) return Boolean is begin return (for some I in Id => Str = Img (I)); end Valid_Id; ------------- -- From_Id -- ------------- function From_Id (Str : String) return Id is begin for I in Id loop if Str = Img (I) then return I; end if; end loop; raise Program_Error; end From_Id; end SPDX.Licenses; alire-1.2.1/deps/spdx/src/spdx-licenses.ads000066400000000000000000001645511375715564200206140ustar00rootroot00000000000000package SPDX.Licenses is pragma Style_Checks (Off); -- Genrated code Version : constant String :="3.10-14-g0fb8a59"; type Id is ( Id_0BSD, AAL, ADSL, AFL_1_1, AFL_1_2, AFL_2_0, AFL_2_1, AFL_3_0, AGPL_1_0_only, AGPL_1_0_or_later, AGPL_3_0_only, AGPL_3_0_or_later, AMDPLPA, AML, AMPAS, ANTLR_PD, APAFML, APL_1_0, APSL_1_0, APSL_1_1, APSL_1_2, APSL_2_0, Abstyles, Adobe_2006, Adobe_Glyph, Afmparse, Aladdin, Apache_1_0, Apache_1_1, Apache_2_0, Artistic_1_0, Artistic_1_0_Perl, Artistic_1_0_cl8, Artistic_2_0, BSD_1_Clause, BSD_2_Clause, BSD_2_Clause_Patent, BSD_2_Clause_Views, BSD_3_Clause, BSD_3_Clause_Attribution, BSD_3_Clause_Clear, BSD_3_Clause_LBNL, BSD_3_Clause_No_Nuclear_License, BSD_3_Clause_No_Nuclear_License_2014, BSD_3_Clause_No_Nuclear_Warranty, BSD_3_Clause_Open_MPI, BSD_4_Clause, BSD_4_Clause_UC, BSD_Protection, BSD_Source_Code, BSL_1_0, Bahyph, Barr, Beerware, BitTorrent_1_0, BitTorrent_1_1, BlueOak_1_0_0, Borceux, CAL_1_0, CAL_1_0_Combined_Work_Exception, CATOSL_1_1, CC_BY_1_0, CC_BY_2_0, CC_BY_2_5, CC_BY_3_0, CC_BY_3_0_AT, CC_BY_4_0, CC_BY_NC_1_0, CC_BY_NC_2_0, CC_BY_NC_2_5, CC_BY_NC_3_0, CC_BY_NC_4_0, CC_BY_NC_ND_1_0, CC_BY_NC_ND_2_0, CC_BY_NC_ND_2_5, CC_BY_NC_ND_3_0, CC_BY_NC_ND_3_0_IGO, CC_BY_NC_ND_4_0, CC_BY_NC_SA_1_0, CC_BY_NC_SA_2_0, CC_BY_NC_SA_2_5, CC_BY_NC_SA_3_0, CC_BY_NC_SA_4_0, CC_BY_ND_1_0, CC_BY_ND_2_0, CC_BY_ND_2_5, CC_BY_ND_3_0, CC_BY_ND_4_0, CC_BY_SA_1_0, CC_BY_SA_2_0, CC_BY_SA_2_5, CC_BY_SA_3_0, CC_BY_SA_3_0_AT, CC_BY_SA_4_0, CC_PDDC, CC0_1_0, CDDL_1_0, CDDL_1_1, CDLA_Permissive_1_0, CDLA_Sharing_1_0, CECILL_1_0, CECILL_1_1, CECILL_2_0, CECILL_2_1, CECILL_B, CECILL_C, CERN_OHL_1_1, CERN_OHL_1_2, CERN_OHL_P_2_0, CERN_OHL_S_2_0, CERN_OHL_W_2_0, CNRI_Jython, CNRI_Python, CNRI_Python_GPL_Compatible, CPAL_1_0, CPL_1_0, CPOL_1_02, CUA_OPL_1_0, Caldera, ClArtistic, Condor_1_1, Crossword, CrystalStacker, Cube, D_FSL_1_0, DOC, DSDP, Dotseqn, ECL_1_0, ECL_2_0, EFL_1_0, EFL_2_0, EPICS, EPL_1_0, EPL_2_0, EUDatagrid, EUPL_1_0, EUPL_1_1, EUPL_1_2, Entessa, ErlPL_1_1, Eurosym, FSFAP, FSFUL, FSFULLR, FTL, Fair, Frameworx_1_0, FreeImage, GFDL_1_1_invariants_only, GFDL_1_1_invariants_or_later, GFDL_1_1_no_invariants_only, GFDL_1_1_no_invariants_or_later, GFDL_1_1_only, GFDL_1_1_or_later, GFDL_1_2_invariants_only, GFDL_1_2_invariants_or_later, GFDL_1_2_no_invariants_only, GFDL_1_2_no_invariants_or_later, GFDL_1_2_only, GFDL_1_2_or_later, GFDL_1_3_invariants_only, GFDL_1_3_invariants_or_later, GFDL_1_3_no_invariants_only, GFDL_1_3_no_invariants_or_later, GFDL_1_3_only, GFDL_1_3_or_later, GL2PS, GLWTPL, GPL_1_0_only, GPL_1_0_or_later, GPL_2_0_only, GPL_2_0_or_later, GPL_3_0_only, GPL_3_0_or_later, Giftware, Glide, Glulxe, HPND, HPND_sell_variant, HaskellReport, Hippocratic_2_1, IBM_pibs, ICU, IJG, IPA, IPL_1_0, ISC, ImageMagick, Imlib2, Info_ZIP, Intel, Intel_ACPI, Interbase_1_0, JPNIC, JSON, JasPer_2_0, LAL_1_2, LAL_1_3, LGPL_2_0_only, LGPL_2_0_or_later, LGPL_2_1_only, LGPL_2_1_or_later, LGPL_3_0_only, LGPL_3_0_or_later, LGPLLR, LPL_1_0, LPL_1_02, LPPL_1_0, LPPL_1_1, LPPL_1_2, LPPL_1_3a, LPPL_1_3c, Latex2e, Leptonica, LiLiQ_P_1_1, LiLiQ_R_1_1, LiLiQ_Rplus_1_1, Libpng, Linux_OpenIB, MIT, MIT_0, MIT_CMU, MIT_advertising, MIT_enna, MIT_feh, MITNFA, MPL_1_0, MPL_1_1, MPL_2_0, MPL_2_0_no_copyleft_exception, MS_PL, MS_RL, MTLL, MakeIndex, MirOS, Motosoto, MulanPSL_1_0, MulanPSL_2_0, Multics, Mup, NASA_1_3, NBPL_1_0, NCGL_UK_2_0, NCSA, NGPL, NIST_PD, NIST_PD_fallback, NLOD_1_0, NLPL, NOSL, NPL_1_0, NPL_1_1, NPOSL_3_0, NRL, NTP, NTP_0, Naumen, Net_SNMP, NetCDF, Newsletr, Nokia, Noweb, O_UDA_1_0, OCCT_PL, OCLC_2_0, ODC_By_1_0, ODbL_1_0, OFL_1_0, OFL_1_0_RFN, OFL_1_0_no_RFN, OFL_1_1, OFL_1_1_RFN, OFL_1_1_no_RFN, OGC_1_0, OGL_Canada_2_0, OGL_UK_1_0, OGL_UK_2_0, OGL_UK_3_0, OGTSL, OLDAP_1_1, OLDAP_1_2, OLDAP_1_3, OLDAP_1_4, OLDAP_2_0, OLDAP_2_0_1, OLDAP_2_1, OLDAP_2_2, OLDAP_2_2_1, OLDAP_2_2_2, OLDAP_2_3, OLDAP_2_4, OLDAP_2_5, OLDAP_2_6, OLDAP_2_7, OLDAP_2_8, OML, OPL_1_0, OSET_PL_2_1, OSL_1_0, OSL_1_1, OSL_2_0, OSL_2_1, OSL_3_0, OpenSSL, PDDL_1_0, PHP_3_0, PHP_3_01, PSF_2_0, Parity_6_0_0, Parity_7_0_0, Plexus, PolyForm_Noncommercial_1_0_0, PolyForm_Small_Business_1_0_0, PostgreSQL, Python_2_0, QPL_1_0, Qhull, RHeCos_1_1, RPL_1_1, RPL_1_5, RPSL_1_0, RSA_MD, RSCPL, Rdisc, Ruby, SAX_PD, SCEA, SGI_B_1_0, SGI_B_1_1, SGI_B_2_0, SHL_0_5, SHL_0_51, SISSL, SISSL_1_2, SMLNJ, SMPPL, SNIA, SPL_1_0, SSH_OpenSSH, SSH_short, SSPL_1_0, SWL, Saxpath, Sendmail, Sendmail_8_23, SimPL_2_0, Sleepycat, Spencer_86, Spencer_94, Spencer_99, SugarCRM_1_1_3, TAPR_OHL_1_0, TCL, TCP_wrappers, TMate, TORQUE_1_1, TOSL, TU_Berlin_1_0, TU_Berlin_2_0, UCL_1_0, UPL_1_0, Unicode_DFS_2015, Unicode_DFS_2016, Unicode_TOU, Unlicense, VOSTROM, VSL_1_0, Vim, W3C, W3C_19980720, W3C_20150513, WTFPL, Watcom_1_0, Wsuipa, X11, XFree86_1_1, XSkat, Xerox, Xnet, YPL_1_0, YPL_1_1, ZPL_1_1, ZPL_2_0, ZPL_2_1, Zed, Zend_2_0, Zimbra_1_3, Zimbra_1_4, Zlib, blessing, bzip2_1_0_5, bzip2_1_0_6, copyleft_next_0_3_0, copyleft_next_0_3_1, curl, diffmark, dvipdfm, eGenix, etalab_2_0, gSOAP_1_3b, gnuplot, iMatix, libpng_2_0, libselinux_1_0, libtiff, mpich2, psfrag, psutils, xinetd, xpp, zlib_acknowledgement); type String_Access is not null access constant String; Img_Ptr : constant array (Id) of String_Access := ( Id_0BSD => new String'("0BSD"), AAL => new String'("AAL"), ADSL => new String'("ADSL"), AFL_1_1 => new String'("AFL-1.1"), AFL_1_2 => new String'("AFL-1.2"), AFL_2_0 => new String'("AFL-2.0"), AFL_2_1 => new String'("AFL-2.1"), AFL_3_0 => new String'("AFL-3.0"), AGPL_1_0_only => new String'("AGPL-1.0-only"), AGPL_1_0_or_later => new String'("AGPL-1.0-or-later"), AGPL_3_0_only => new String'("AGPL-3.0-only"), AGPL_3_0_or_later => new String'("AGPL-3.0-or-later"), AMDPLPA => new String'("AMDPLPA"), AML => new String'("AML"), AMPAS => new String'("AMPAS"), ANTLR_PD => new String'("ANTLR-PD"), APAFML => new String'("APAFML"), APL_1_0 => new String'("APL-1.0"), APSL_1_0 => new String'("APSL-1.0"), APSL_1_1 => new String'("APSL-1.1"), APSL_1_2 => new String'("APSL-1.2"), APSL_2_0 => new String'("APSL-2.0"), Abstyles => new String'("Abstyles"), Adobe_2006 => new String'("Adobe-2006"), Adobe_Glyph => new String'("Adobe-Glyph"), Afmparse => new String'("Afmparse"), Aladdin => new String'("Aladdin"), Apache_1_0 => new String'("Apache-1.0"), Apache_1_1 => new String'("Apache-1.1"), Apache_2_0 => new String'("Apache-2.0"), Artistic_1_0 => new String'("Artistic-1.0"), Artistic_1_0_Perl => new String'("Artistic-1.0-Perl"), Artistic_1_0_cl8 => new String'("Artistic-1.0-cl8"), Artistic_2_0 => new String'("Artistic-2.0"), BSD_1_Clause => new String'("BSD-1-Clause"), BSD_2_Clause => new String'("BSD-2-Clause"), BSD_2_Clause_Patent => new String'("BSD-2-Clause-Patent"), BSD_2_Clause_Views => new String'("BSD-2-Clause-Views"), BSD_3_Clause => new String'("BSD-3-Clause"), BSD_3_Clause_Attribution => new String'("BSD-3-Clause-Attribution"), BSD_3_Clause_Clear => new String'("BSD-3-Clause-Clear"), BSD_3_Clause_LBNL => new String'("BSD-3-Clause-LBNL"), BSD_3_Clause_No_Nuclear_License => new String'("BSD-3-Clause-No-Nuclear-License"), BSD_3_Clause_No_Nuclear_License_2014 => new String'("BSD-3-Clause-No-Nuclear-License-2014"), BSD_3_Clause_No_Nuclear_Warranty => new String'("BSD-3-Clause-No-Nuclear-Warranty"), BSD_3_Clause_Open_MPI => new String'("BSD-3-Clause-Open-MPI"), BSD_4_Clause => new String'("BSD-4-Clause"), BSD_4_Clause_UC => new String'("BSD-4-Clause-UC"), BSD_Protection => new String'("BSD-Protection"), BSD_Source_Code => new String'("BSD-Source-Code"), BSL_1_0 => new String'("BSL-1.0"), Bahyph => new String'("Bahyph"), Barr => new String'("Barr"), Beerware => new String'("Beerware"), BitTorrent_1_0 => new String'("BitTorrent-1.0"), BitTorrent_1_1 => new String'("BitTorrent-1.1"), BlueOak_1_0_0 => new String'("BlueOak-1.0.0"), Borceux => new String'("Borceux"), CAL_1_0 => new String'("CAL-1.0"), CAL_1_0_Combined_Work_Exception => new String'("CAL-1.0-Combined-Work-Exception"), CATOSL_1_1 => new String'("CATOSL-1.1"), CC_BY_1_0 => new String'("CC-BY-1.0"), CC_BY_2_0 => new String'("CC-BY-2.0"), CC_BY_2_5 => new String'("CC-BY-2.5"), CC_BY_3_0 => new String'("CC-BY-3.0"), CC_BY_3_0_AT => new String'("CC-BY-3.0-AT"), CC_BY_4_0 => new String'("CC-BY-4.0"), CC_BY_NC_1_0 => new String'("CC-BY-NC-1.0"), CC_BY_NC_2_0 => new String'("CC-BY-NC-2.0"), CC_BY_NC_2_5 => new String'("CC-BY-NC-2.5"), CC_BY_NC_3_0 => new String'("CC-BY-NC-3.0"), CC_BY_NC_4_0 => new String'("CC-BY-NC-4.0"), CC_BY_NC_ND_1_0 => new String'("CC-BY-NC-ND-1.0"), CC_BY_NC_ND_2_0 => new String'("CC-BY-NC-ND-2.0"), CC_BY_NC_ND_2_5 => new String'("CC-BY-NC-ND-2.5"), CC_BY_NC_ND_3_0 => new String'("CC-BY-NC-ND-3.0"), CC_BY_NC_ND_3_0_IGO => new String'("CC-BY-NC-ND-3.0-IGO"), CC_BY_NC_ND_4_0 => new String'("CC-BY-NC-ND-4.0"), CC_BY_NC_SA_1_0 => new String'("CC-BY-NC-SA-1.0"), CC_BY_NC_SA_2_0 => new String'("CC-BY-NC-SA-2.0"), CC_BY_NC_SA_2_5 => new String'("CC-BY-NC-SA-2.5"), CC_BY_NC_SA_3_0 => new String'("CC-BY-NC-SA-3.0"), CC_BY_NC_SA_4_0 => new String'("CC-BY-NC-SA-4.0"), CC_BY_ND_1_0 => new String'("CC-BY-ND-1.0"), CC_BY_ND_2_0 => new String'("CC-BY-ND-2.0"), CC_BY_ND_2_5 => new String'("CC-BY-ND-2.5"), CC_BY_ND_3_0 => new String'("CC-BY-ND-3.0"), CC_BY_ND_4_0 => new String'("CC-BY-ND-4.0"), CC_BY_SA_1_0 => new String'("CC-BY-SA-1.0"), CC_BY_SA_2_0 => new String'("CC-BY-SA-2.0"), CC_BY_SA_2_5 => new String'("CC-BY-SA-2.5"), CC_BY_SA_3_0 => new String'("CC-BY-SA-3.0"), CC_BY_SA_3_0_AT => new String'("CC-BY-SA-3.0-AT"), CC_BY_SA_4_0 => new String'("CC-BY-SA-4.0"), CC_PDDC => new String'("CC-PDDC"), CC0_1_0 => new String'("CC0-1.0"), CDDL_1_0 => new String'("CDDL-1.0"), CDDL_1_1 => new String'("CDDL-1.1"), CDLA_Permissive_1_0 => new String'("CDLA-Permissive-1.0"), CDLA_Sharing_1_0 => new String'("CDLA-Sharing-1.0"), CECILL_1_0 => new String'("CECILL-1.0"), CECILL_1_1 => new String'("CECILL-1.1"), CECILL_2_0 => new String'("CECILL-2.0"), CECILL_2_1 => new String'("CECILL-2.1"), CECILL_B => new String'("CECILL-B"), CECILL_C => new String'("CECILL-C"), CERN_OHL_1_1 => new String'("CERN-OHL-1.1"), CERN_OHL_1_2 => new String'("CERN-OHL-1.2"), CERN_OHL_P_2_0 => new String'("CERN-OHL-P-2.0"), CERN_OHL_S_2_0 => new String'("CERN-OHL-S-2.0"), CERN_OHL_W_2_0 => new String'("CERN-OHL-W-2.0"), CNRI_Jython => new String'("CNRI-Jython"), CNRI_Python => new String'("CNRI-Python"), CNRI_Python_GPL_Compatible => new String'("CNRI-Python-GPL-Compatible"), CPAL_1_0 => new String'("CPAL-1.0"), CPL_1_0 => new String'("CPL-1.0"), CPOL_1_02 => new String'("CPOL-1.02"), CUA_OPL_1_0 => new String'("CUA-OPL-1.0"), Caldera => new String'("Caldera"), ClArtistic => new String'("ClArtistic"), Condor_1_1 => new String'("Condor-1.1"), Crossword => new String'("Crossword"), CrystalStacker => new String'("CrystalStacker"), Cube => new String'("Cube"), D_FSL_1_0 => new String'("D-FSL-1.0"), DOC => new String'("DOC"), DSDP => new String'("DSDP"), Dotseqn => new String'("Dotseqn"), ECL_1_0 => new String'("ECL-1.0"), ECL_2_0 => new String'("ECL-2.0"), EFL_1_0 => new String'("EFL-1.0"), EFL_2_0 => new String'("EFL-2.0"), EPICS => new String'("EPICS"), EPL_1_0 => new String'("EPL-1.0"), EPL_2_0 => new String'("EPL-2.0"), EUDatagrid => new String'("EUDatagrid"), EUPL_1_0 => new String'("EUPL-1.0"), EUPL_1_1 => new String'("EUPL-1.1"), EUPL_1_2 => new String'("EUPL-1.2"), Entessa => new String'("Entessa"), ErlPL_1_1 => new String'("ErlPL-1.1"), Eurosym => new String'("Eurosym"), FSFAP => new String'("FSFAP"), FSFUL => new String'("FSFUL"), FSFULLR => new String'("FSFULLR"), FTL => new String'("FTL"), Fair => new String'("Fair"), Frameworx_1_0 => new String'("Frameworx-1.0"), FreeImage => new String'("FreeImage"), GFDL_1_1_invariants_only => new String'("GFDL-1.1-invariants-only"), GFDL_1_1_invariants_or_later => new String'("GFDL-1.1-invariants-or-later"), GFDL_1_1_no_invariants_only => new String'("GFDL-1.1-no-invariants-only"), GFDL_1_1_no_invariants_or_later => new String'("GFDL-1.1-no-invariants-or-later"), GFDL_1_1_only => new String'("GFDL-1.1-only"), GFDL_1_1_or_later => new String'("GFDL-1.1-or-later"), GFDL_1_2_invariants_only => new String'("GFDL-1.2-invariants-only"), GFDL_1_2_invariants_or_later => new String'("GFDL-1.2-invariants-or-later"), GFDL_1_2_no_invariants_only => new String'("GFDL-1.2-no-invariants-only"), GFDL_1_2_no_invariants_or_later => new String'("GFDL-1.2-no-invariants-or-later"), GFDL_1_2_only => new String'("GFDL-1.2-only"), GFDL_1_2_or_later => new String'("GFDL-1.2-or-later"), GFDL_1_3_invariants_only => new String'("GFDL-1.3-invariants-only"), GFDL_1_3_invariants_or_later => new String'("GFDL-1.3-invariants-or-later"), GFDL_1_3_no_invariants_only => new String'("GFDL-1.3-no-invariants-only"), GFDL_1_3_no_invariants_or_later => new String'("GFDL-1.3-no-invariants-or-later"), GFDL_1_3_only => new String'("GFDL-1.3-only"), GFDL_1_3_or_later => new String'("GFDL-1.3-or-later"), GL2PS => new String'("GL2PS"), GLWTPL => new String'("GLWTPL"), GPL_1_0_only => new String'("GPL-1.0-only"), GPL_1_0_or_later => new String'("GPL-1.0-or-later"), GPL_2_0_only => new String'("GPL-2.0-only"), GPL_2_0_or_later => new String'("GPL-2.0-or-later"), GPL_3_0_only => new String'("GPL-3.0-only"), GPL_3_0_or_later => new String'("GPL-3.0-or-later"), Giftware => new String'("Giftware"), Glide => new String'("Glide"), Glulxe => new String'("Glulxe"), HPND => new String'("HPND"), HPND_sell_variant => new String'("HPND-sell-variant"), HaskellReport => new String'("HaskellReport"), Hippocratic_2_1 => new String'("Hippocratic-2.1"), IBM_pibs => new String'("IBM-pibs"), ICU => new String'("ICU"), IJG => new String'("IJG"), IPA => new String'("IPA"), IPL_1_0 => new String'("IPL-1.0"), ISC => new String'("ISC"), ImageMagick => new String'("ImageMagick"), Imlib2 => new String'("Imlib2"), Info_ZIP => new String'("Info-ZIP"), Intel => new String'("Intel"), Intel_ACPI => new String'("Intel-ACPI"), Interbase_1_0 => new String'("Interbase-1.0"), JPNIC => new String'("JPNIC"), JSON => new String'("JSON"), JasPer_2_0 => new String'("JasPer-2.0"), LAL_1_2 => new String'("LAL-1.2"), LAL_1_3 => new String'("LAL-1.3"), LGPL_2_0_only => new String'("LGPL-2.0-only"), LGPL_2_0_or_later => new String'("LGPL-2.0-or-later"), LGPL_2_1_only => new String'("LGPL-2.1-only"), LGPL_2_1_or_later => new String'("LGPL-2.1-or-later"), LGPL_3_0_only => new String'("LGPL-3.0-only"), LGPL_3_0_or_later => new String'("LGPL-3.0-or-later"), LGPLLR => new String'("LGPLLR"), LPL_1_0 => new String'("LPL-1.0"), LPL_1_02 => new String'("LPL-1.02"), LPPL_1_0 => new String'("LPPL-1.0"), LPPL_1_1 => new String'("LPPL-1.1"), LPPL_1_2 => new String'("LPPL-1.2"), LPPL_1_3a => new String'("LPPL-1.3a"), LPPL_1_3c => new String'("LPPL-1.3c"), Latex2e => new String'("Latex2e"), Leptonica => new String'("Leptonica"), LiLiQ_P_1_1 => new String'("LiLiQ-P-1.1"), LiLiQ_R_1_1 => new String'("LiLiQ-R-1.1"), LiLiQ_Rplus_1_1 => new String'("LiLiQ-Rplus-1.1"), Libpng => new String'("Libpng"), Linux_OpenIB => new String'("Linux-OpenIB"), MIT => new String'("MIT"), MIT_0 => new String'("MIT-0"), MIT_CMU => new String'("MIT-CMU"), MIT_advertising => new String'("MIT-advertising"), MIT_enna => new String'("MIT-enna"), MIT_feh => new String'("MIT-feh"), MITNFA => new String'("MITNFA"), MPL_1_0 => new String'("MPL-1.0"), MPL_1_1 => new String'("MPL-1.1"), MPL_2_0 => new String'("MPL-2.0"), MPL_2_0_no_copyleft_exception => new String'("MPL-2.0-no-copyleft-exception"), MS_PL => new String'("MS-PL"), MS_RL => new String'("MS-RL"), MTLL => new String'("MTLL"), MakeIndex => new String'("MakeIndex"), MirOS => new String'("MirOS"), Motosoto => new String'("Motosoto"), MulanPSL_1_0 => new String'("MulanPSL-1.0"), MulanPSL_2_0 => new String'("MulanPSL-2.0"), Multics => new String'("Multics"), Mup => new String'("Mup"), NASA_1_3 => new String'("NASA-1.3"), NBPL_1_0 => new String'("NBPL-1.0"), NCGL_UK_2_0 => new String'("NCGL-UK-2.0"), NCSA => new String'("NCSA"), NGPL => new String'("NGPL"), NIST_PD => new String'("NIST-PD"), NIST_PD_fallback => new String'("NIST-PD-fallback"), NLOD_1_0 => new String'("NLOD-1.0"), NLPL => new String'("NLPL"), NOSL => new String'("NOSL"), NPL_1_0 => new String'("NPL-1.0"), NPL_1_1 => new String'("NPL-1.1"), NPOSL_3_0 => new String'("NPOSL-3.0"), NRL => new String'("NRL"), NTP => new String'("NTP"), NTP_0 => new String'("NTP-0"), Naumen => new String'("Naumen"), Net_SNMP => new String'("Net-SNMP"), NetCDF => new String'("NetCDF"), Newsletr => new String'("Newsletr"), Nokia => new String'("Nokia"), Noweb => new String'("Noweb"), O_UDA_1_0 => new String'("O-UDA-1.0"), OCCT_PL => new String'("OCCT-PL"), OCLC_2_0 => new String'("OCLC-2.0"), ODC_By_1_0 => new String'("ODC-By-1.0"), ODbL_1_0 => new String'("ODbL-1.0"), OFL_1_0 => new String'("OFL-1.0"), OFL_1_0_RFN => new String'("OFL-1.0-RFN"), OFL_1_0_no_RFN => new String'("OFL-1.0-no-RFN"), OFL_1_1 => new String'("OFL-1.1"), OFL_1_1_RFN => new String'("OFL-1.1-RFN"), OFL_1_1_no_RFN => new String'("OFL-1.1-no-RFN"), OGC_1_0 => new String'("OGC-1.0"), OGL_Canada_2_0 => new String'("OGL-Canada-2.0"), OGL_UK_1_0 => new String'("OGL-UK-1.0"), OGL_UK_2_0 => new String'("OGL-UK-2.0"), OGL_UK_3_0 => new String'("OGL-UK-3.0"), OGTSL => new String'("OGTSL"), OLDAP_1_1 => new String'("OLDAP-1.1"), OLDAP_1_2 => new String'("OLDAP-1.2"), OLDAP_1_3 => new String'("OLDAP-1.3"), OLDAP_1_4 => new String'("OLDAP-1.4"), OLDAP_2_0 => new String'("OLDAP-2.0"), OLDAP_2_0_1 => new String'("OLDAP-2.0.1"), OLDAP_2_1 => new String'("OLDAP-2.1"), OLDAP_2_2 => new String'("OLDAP-2.2"), OLDAP_2_2_1 => new String'("OLDAP-2.2.1"), OLDAP_2_2_2 => new String'("OLDAP-2.2.2"), OLDAP_2_3 => new String'("OLDAP-2.3"), OLDAP_2_4 => new String'("OLDAP-2.4"), OLDAP_2_5 => new String'("OLDAP-2.5"), OLDAP_2_6 => new String'("OLDAP-2.6"), OLDAP_2_7 => new String'("OLDAP-2.7"), OLDAP_2_8 => new String'("OLDAP-2.8"), OML => new String'("OML"), OPL_1_0 => new String'("OPL-1.0"), OSET_PL_2_1 => new String'("OSET-PL-2.1"), OSL_1_0 => new String'("OSL-1.0"), OSL_1_1 => new String'("OSL-1.1"), OSL_2_0 => new String'("OSL-2.0"), OSL_2_1 => new String'("OSL-2.1"), OSL_3_0 => new String'("OSL-3.0"), OpenSSL => new String'("OpenSSL"), PDDL_1_0 => new String'("PDDL-1.0"), PHP_3_0 => new String'("PHP-3.0"), PHP_3_01 => new String'("PHP-3.01"), PSF_2_0 => new String'("PSF-2.0"), Parity_6_0_0 => new String'("Parity-6.0.0"), Parity_7_0_0 => new String'("Parity-7.0.0"), Plexus => new String'("Plexus"), PolyForm_Noncommercial_1_0_0 => new String'("PolyForm-Noncommercial-1.0.0"), PolyForm_Small_Business_1_0_0 => new String'("PolyForm-Small-Business-1.0.0"), PostgreSQL => new String'("PostgreSQL"), Python_2_0 => new String'("Python-2.0"), QPL_1_0 => new String'("QPL-1.0"), Qhull => new String'("Qhull"), RHeCos_1_1 => new String'("RHeCos-1.1"), RPL_1_1 => new String'("RPL-1.1"), RPL_1_5 => new String'("RPL-1.5"), RPSL_1_0 => new String'("RPSL-1.0"), RSA_MD => new String'("RSA-MD"), RSCPL => new String'("RSCPL"), Rdisc => new String'("Rdisc"), Ruby => new String'("Ruby"), SAX_PD => new String'("SAX-PD"), SCEA => new String'("SCEA"), SGI_B_1_0 => new String'("SGI-B-1.0"), SGI_B_1_1 => new String'("SGI-B-1.1"), SGI_B_2_0 => new String'("SGI-B-2.0"), SHL_0_5 => new String'("SHL-0.5"), SHL_0_51 => new String'("SHL-0.51"), SISSL => new String'("SISSL"), SISSL_1_2 => new String'("SISSL-1.2"), SMLNJ => new String'("SMLNJ"), SMPPL => new String'("SMPPL"), SNIA => new String'("SNIA"), SPL_1_0 => new String'("SPL-1.0"), SSH_OpenSSH => new String'("SSH-OpenSSH"), SSH_short => new String'("SSH-short"), SSPL_1_0 => new String'("SSPL-1.0"), SWL => new String'("SWL"), Saxpath => new String'("Saxpath"), Sendmail => new String'("Sendmail"), Sendmail_8_23 => new String'("Sendmail-8.23"), SimPL_2_0 => new String'("SimPL-2.0"), Sleepycat => new String'("Sleepycat"), Spencer_86 => new String'("Spencer-86"), Spencer_94 => new String'("Spencer-94"), Spencer_99 => new String'("Spencer-99"), SugarCRM_1_1_3 => new String'("SugarCRM-1.1.3"), TAPR_OHL_1_0 => new String'("TAPR-OHL-1.0"), TCL => new String'("TCL"), TCP_wrappers => new String'("TCP-wrappers"), TMate => new String'("TMate"), TORQUE_1_1 => new String'("TORQUE-1.1"), TOSL => new String'("TOSL"), TU_Berlin_1_0 => new String'("TU-Berlin-1.0"), TU_Berlin_2_0 => new String'("TU-Berlin-2.0"), UCL_1_0 => new String'("UCL-1.0"), UPL_1_0 => new String'("UPL-1.0"), Unicode_DFS_2015 => new String'("Unicode-DFS-2015"), Unicode_DFS_2016 => new String'("Unicode-DFS-2016"), Unicode_TOU => new String'("Unicode-TOU"), Unlicense => new String'("Unlicense"), VOSTROM => new String'("VOSTROM"), VSL_1_0 => new String'("VSL-1.0"), Vim => new String'("Vim"), W3C => new String'("W3C"), W3C_19980720 => new String'("W3C-19980720"), W3C_20150513 => new String'("W3C-20150513"), WTFPL => new String'("WTFPL"), Watcom_1_0 => new String'("Watcom-1.0"), Wsuipa => new String'("Wsuipa"), X11 => new String'("X11"), XFree86_1_1 => new String'("XFree86-1.1"), XSkat => new String'("XSkat"), Xerox => new String'("Xerox"), Xnet => new String'("Xnet"), YPL_1_0 => new String'("YPL-1.0"), YPL_1_1 => new String'("YPL-1.1"), ZPL_1_1 => new String'("ZPL-1.1"), ZPL_2_0 => new String'("ZPL-2.0"), ZPL_2_1 => new String'("ZPL-2.1"), Zed => new String'("Zed"), Zend_2_0 => new String'("Zend-2.0"), Zimbra_1_3 => new String'("Zimbra-1.3"), Zimbra_1_4 => new String'("Zimbra-1.4"), Zlib => new String'("Zlib"), blessing => new String'("blessing"), bzip2_1_0_5 => new String'("bzip2-1.0.5"), bzip2_1_0_6 => new String'("bzip2-1.0.6"), copyleft_next_0_3_0 => new String'("copyleft-next-0.3.0"), copyleft_next_0_3_1 => new String'("copyleft-next-0.3.1"), curl => new String'("curl"), diffmark => new String'("diffmark"), dvipdfm => new String'("dvipdfm"), eGenix => new String'("eGenix"), etalab_2_0 => new String'("etalab-2.0"), gSOAP_1_3b => new String'("gSOAP-1.3b"), gnuplot => new String'("gnuplot"), iMatix => new String'("iMatix"), libpng_2_0 => new String'("libpng-2.0"), libselinux_1_0 => new String'("libselinux-1.0"), libtiff => new String'("libtiff"), mpich2 => new String'("mpich2"), psfrag => new String'("psfrag"), psutils => new String'("psutils"), xinetd => new String'("xinetd"), xpp => new String'("xpp"), zlib_acknowledgement => new String'("zlib-acknowledgement")); function Img (I : Id) return String is (Img_Ptr (I).all); Name_Ptr : constant array (Id) of String_Access := ( Id_0BSD => new String'("BSD Zero Clause License"), AAL => new String'("Attribution Assurance License"), ADSL => new String'("Amazon Digital Services License"), AFL_1_1 => new String'("Academic Free License v1.1"), AFL_1_2 => new String'("Academic Free License v1.2"), AFL_2_0 => new String'("Academic Free License v2.0"), AFL_2_1 => new String'("Academic Free License v2.1"), AFL_3_0 => new String'("Academic Free License v3.0"), AGPL_1_0_only => new String'("Affero General Public License v1.0 only"), AGPL_1_0_or_later => new String'("Affero General Public License v1.0 or later"), AGPL_3_0_only => new String'("GNU Affero General Public License v3.0 only"), AGPL_3_0_or_later => new String'("GNU Affero General Public License v3.0 or later"), AMDPLPA => new String'("AMD's plpa_map.c License"), AML => new String'("Apple MIT License"), AMPAS => new String'("Academy of Motion Picture Arts and Sciences BSD"), ANTLR_PD => new String'("ANTLR Software Rights Notice"), APAFML => new String'("Adobe Postscript AFM License"), APL_1_0 => new String'("Adaptive Public License 1.0"), APSL_1_0 => new String'("Apple Public Source License 1.0"), APSL_1_1 => new String'("Apple Public Source License 1.1"), APSL_1_2 => new String'("Apple Public Source License 1.2"), APSL_2_0 => new String'("Apple Public Source License 2.0"), Abstyles => new String'("Abstyles License"), Adobe_2006 => new String'("Adobe Systems Incorporated Source Code License Agreement"), Adobe_Glyph => new String'("Adobe Glyph List License"), Afmparse => new String'("Afmparse License"), Aladdin => new String'("Aladdin Free Public License"), Apache_1_0 => new String'("Apache License 1.0"), Apache_1_1 => new String'("Apache License 1.1"), Apache_2_0 => new String'("Apache License 2.0"), Artistic_1_0 => new String'("Artistic License 1.0"), Artistic_1_0_Perl => new String'("Artistic License 1.0 (Perl)"), Artistic_1_0_cl8 => new String'("Artistic License 1.0 w/clause 8"), Artistic_2_0 => new String'("Artistic License 2.0"), BSD_1_Clause => new String'("BSD 1-Clause License"), BSD_2_Clause => new String'("BSD 2-Clause ""Simplified"" License"), BSD_2_Clause_Patent => new String'("BSD-2-Clause Plus Patent License"), BSD_2_Clause_Views => new String'("BSD 2-Clause with views sentence"), BSD_3_Clause => new String'("BSD 3-Clause ""New"" or ""Revised"" License"), BSD_3_Clause_Attribution => new String'("BSD with attribution"), BSD_3_Clause_Clear => new String'("BSD 3-Clause Clear License"), BSD_3_Clause_LBNL => new String'("Lawrence Berkeley National Labs BSD variant license"), BSD_3_Clause_No_Nuclear_License => new String'("BSD 3-Clause No Nuclear License"), BSD_3_Clause_No_Nuclear_License_2014 => new String'("BSD 3-Clause No Nuclear License 2014"), BSD_3_Clause_No_Nuclear_Warranty => new String'("BSD 3-Clause No Nuclear Warranty"), BSD_3_Clause_Open_MPI => new String'("BSD 3-Clause Open MPI variant"), BSD_4_Clause => new String'("BSD 4-Clause ""Original"" or ""Old"" License"), BSD_4_Clause_UC => new String'("BSD-4-Clause (University of California-Specific)"), BSD_Protection => new String'("BSD Protection License"), BSD_Source_Code => new String'("BSD Source Code Attribution"), BSL_1_0 => new String'("Boost Software License 1.0"), Bahyph => new String'("Bahyph License"), Barr => new String'("Barr License"), Beerware => new String'("Beerware License"), BitTorrent_1_0 => new String'("BitTorrent Open Source License v1.0"), BitTorrent_1_1 => new String'("BitTorrent Open Source License v1.1"), BlueOak_1_0_0 => new String'("Blue Oak Model License 1.0.0"), Borceux => new String'("Borceux license"), CAL_1_0 => new String'("Cryptographic Autonomy License 1.0"), CAL_1_0_Combined_Work_Exception => new String'("Cryptographic Autonomy License 1.0 (Combined Work Exception)"), CATOSL_1_1 => new String'("Computer Associates Trusted Open Source License 1.1"), CC_BY_1_0 => new String'("Creative Commons Attribution 1.0 Generic"), CC_BY_2_0 => new String'("Creative Commons Attribution 2.0 Generic"), CC_BY_2_5 => new String'("Creative Commons Attribution 2.5 Generic"), CC_BY_3_0 => new String'("Creative Commons Attribution 3.0 Unported"), CC_BY_3_0_AT => new String'("Creative Commons Attribution 3.0 Austria"), CC_BY_4_0 => new String'("Creative Commons Attribution 4.0 International"), CC_BY_NC_1_0 => new String'("Creative Commons Attribution Non Commercial 1.0 Generic"), CC_BY_NC_2_0 => new String'("Creative Commons Attribution Non Commercial 2.0 Generic"), CC_BY_NC_2_5 => new String'("Creative Commons Attribution Non Commercial 2.5 Generic"), CC_BY_NC_3_0 => new String'("Creative Commons Attribution Non Commercial 3.0 Unported"), CC_BY_NC_4_0 => new String'("Creative Commons Attribution Non Commercial 4.0 International"), CC_BY_NC_ND_1_0 => new String'("Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic"), CC_BY_NC_ND_2_0 => new String'("Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic"), CC_BY_NC_ND_2_5 => new String'("Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic"), CC_BY_NC_ND_3_0 => new String'("Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported"), CC_BY_NC_ND_3_0_IGO => new String'("Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO"), CC_BY_NC_ND_4_0 => new String'("Creative Commons Attribution Non Commercial No Derivatives 4.0 International"), CC_BY_NC_SA_1_0 => new String'("Creative Commons Attribution Non Commercial Share Alike 1.0 Generic"), CC_BY_NC_SA_2_0 => new String'("Creative Commons Attribution Non Commercial Share Alike 2.0 Generic"), CC_BY_NC_SA_2_5 => new String'("Creative Commons Attribution Non Commercial Share Alike 2.5 Generic"), CC_BY_NC_SA_3_0 => new String'("Creative Commons Attribution Non Commercial Share Alike 3.0 Unported"), CC_BY_NC_SA_4_0 => new String'("Creative Commons Attribution Non Commercial Share Alike 4.0 International"), CC_BY_ND_1_0 => new String'("Creative Commons Attribution No Derivatives 1.0 Generic"), CC_BY_ND_2_0 => new String'("Creative Commons Attribution No Derivatives 2.0 Generic"), CC_BY_ND_2_5 => new String'("Creative Commons Attribution No Derivatives 2.5 Generic"), CC_BY_ND_3_0 => new String'("Creative Commons Attribution No Derivatives 3.0 Unported"), CC_BY_ND_4_0 => new String'("Creative Commons Attribution No Derivatives 4.0 International"), CC_BY_SA_1_0 => new String'("Creative Commons Attribution Share Alike 1.0 Generic"), CC_BY_SA_2_0 => new String'("Creative Commons Attribution Share Alike 2.0 Generic"), CC_BY_SA_2_5 => new String'("Creative Commons Attribution Share Alike 2.5 Generic"), CC_BY_SA_3_0 => new String'("Creative Commons Attribution Share Alike 3.0 Unported"), CC_BY_SA_3_0_AT => new String'("Creative Commons Attribution-Share Alike 3.0 Austria"), CC_BY_SA_4_0 => new String'("Creative Commons Attribution Share Alike 4.0 International"), CC_PDDC => new String'("Creative Commons Public Domain Dedication and Certification"), CC0_1_0 => new String'("Creative Commons Zero v1.0 Universal"), CDDL_1_0 => new String'("Common Development and Distribution License 1.0"), CDDL_1_1 => new String'("Common Development and Distribution License 1.1"), CDLA_Permissive_1_0 => new String'("Community Data License Agreement Permissive 1.0"), CDLA_Sharing_1_0 => new String'("Community Data License Agreement Sharing 1.0"), CECILL_1_0 => new String'("CeCILL Free Software License Agreement v1.0"), CECILL_1_1 => new String'("CeCILL Free Software License Agreement v1.1"), CECILL_2_0 => new String'("CeCILL Free Software License Agreement v2.0"), CECILL_2_1 => new String'("CeCILL Free Software License Agreement v2.1"), CECILL_B => new String'("CeCILL-B Free Software License Agreement"), CECILL_C => new String'("CeCILL-C Free Software License Agreement"), CERN_OHL_1_1 => new String'("CERN Open Hardware Licence v1.1"), CERN_OHL_1_2 => new String'("CERN Open Hardware Licence v1.2"), CERN_OHL_P_2_0 => new String'("CERN Open Hardware Licence Version 2 - Permissive"), CERN_OHL_S_2_0 => new String'("CERN Open Hardware Licence Version 2 - Strongly Reciprocal"), CERN_OHL_W_2_0 => new String'("CERN Open Hardware Licence Version 2 - Weakly Reciprocal"), CNRI_Jython => new String'("CNRI Jython License"), CNRI_Python => new String'("CNRI Python License"), CNRI_Python_GPL_Compatible => new String'("CNRI Python Open Source GPL Compatible License Agreement"), CPAL_1_0 => new String'("Common Public Attribution License 1.0"), CPL_1_0 => new String'("Common Public License 1.0"), CPOL_1_02 => new String'("Code Project Open License 1.02"), CUA_OPL_1_0 => new String'("CUA Office Public License v1.0"), Caldera => new String'("Caldera License"), ClArtistic => new String'("Clarified Artistic License"), Condor_1_1 => new String'("Condor Public License v1.1"), Crossword => new String'("Crossword License"), CrystalStacker => new String'("CrystalStacker License"), Cube => new String'("Cube License"), D_FSL_1_0 => new String'("Deutsche Freie Software Lizenz"), DOC => new String'("DOC License"), DSDP => new String'("DSDP License"), Dotseqn => new String'("Dotseqn License"), ECL_1_0 => new String'("Educational Community License v1.0"), ECL_2_0 => new String'("Educational Community License v2.0"), EFL_1_0 => new String'("Eiffel Forum License v1.0"), EFL_2_0 => new String'("Eiffel Forum License v2.0"), EPICS => new String'("EPICS Open License"), EPL_1_0 => new String'("Eclipse Public License 1.0"), EPL_2_0 => new String'("Eclipse Public License 2.0"), EUDatagrid => new String'("EU DataGrid Software License"), EUPL_1_0 => new String'("European Union Public License 1.0"), EUPL_1_1 => new String'("European Union Public License 1.1"), EUPL_1_2 => new String'("European Union Public License 1.2"), Entessa => new String'("Entessa Public License v1.0"), ErlPL_1_1 => new String'("Erlang Public License v1.1"), Eurosym => new String'("Eurosym License"), FSFAP => new String'("FSF All Permissive License"), FSFUL => new String'("FSF Unlimited License"), FSFULLR => new String'("FSF Unlimited License (with License Retention)"), FTL => new String'("Freetype Project License"), Fair => new String'("Fair License"), Frameworx_1_0 => new String'("Frameworx Open License 1.0"), FreeImage => new String'("FreeImage Public License v1.0"), GFDL_1_1_invariants_only => new String'("GNU Free Documentation License v1.1 only - invariants"), GFDL_1_1_invariants_or_later => new String'("GNU Free Documentation License v1.1 or later - invariants"), GFDL_1_1_no_invariants_only => new String'("GNU Free Documentation License v1.1 only - no invariants"), GFDL_1_1_no_invariants_or_later => new String'("GNU Free Documentation License v1.1 or later - no invariants"), GFDL_1_1_only => new String'("GNU Free Documentation License v1.1 only"), GFDL_1_1_or_later => new String'("GNU Free Documentation License v1.1 or later"), GFDL_1_2_invariants_only => new String'("GNU Free Documentation License v1.2 only - invariants"), GFDL_1_2_invariants_or_later => new String'("GNU Free Documentation License v1.2 or later - invariants"), GFDL_1_2_no_invariants_only => new String'("GNU Free Documentation License v1.2 only - no invariants"), GFDL_1_2_no_invariants_or_later => new String'("GNU Free Documentation License v1.2 or later - no invariants"), GFDL_1_2_only => new String'("GNU Free Documentation License v1.2 only"), GFDL_1_2_or_later => new String'("GNU Free Documentation License v1.2 or later"), GFDL_1_3_invariants_only => new String'("GNU Free Documentation License v1.3 only - invariants"), GFDL_1_3_invariants_or_later => new String'("GNU Free Documentation License v1.3 or later - invariants"), GFDL_1_3_no_invariants_only => new String'("GNU Free Documentation License v1.3 only - no invariants"), GFDL_1_3_no_invariants_or_later => new String'("GNU Free Documentation License v1.3 or later - no invariants"), GFDL_1_3_only => new String'("GNU Free Documentation License v1.3 only"), GFDL_1_3_or_later => new String'("GNU Free Documentation License v1.3 or later"), GL2PS => new String'("GL2PS License"), GLWTPL => new String'("Good Luck With That Public License"), GPL_1_0_only => new String'("GNU General Public License v1.0 only"), GPL_1_0_or_later => new String'("GNU General Public License v1.0 or later"), GPL_2_0_only => new String'("GNU General Public License v2.0 only"), GPL_2_0_or_later => new String'("GNU General Public License v2.0 or later"), GPL_3_0_only => new String'("GNU General Public License v3.0 only"), GPL_3_0_or_later => new String'("GNU General Public License v3.0 or later"), Giftware => new String'("Giftware License"), Glide => new String'("3dfx Glide License"), Glulxe => new String'("Glulxe License"), HPND => new String'("Historical Permission Notice and Disclaimer"), HPND_sell_variant => new String'("Historical Permission Notice and Disclaimer - sell variant"), HaskellReport => new String'("Haskell Language Report License"), Hippocratic_2_1 => new String'("Hippocratic License 2.1"), IBM_pibs => new String'("IBM PowerPC Initialization and Boot Software"), ICU => new String'("ICU License"), IJG => new String'("Independent JPEG Group License"), IPA => new String'("IPA Font License"), IPL_1_0 => new String'("IBM Public License v1.0"), ISC => new String'("ISC License"), ImageMagick => new String'("ImageMagick License"), Imlib2 => new String'("Imlib2 License"), Info_ZIP => new String'("Info-ZIP License"), Intel => new String'("Intel Open Source License"), Intel_ACPI => new String'("Intel ACPI Software License Agreement"), Interbase_1_0 => new String'("Interbase Public License v1.0"), JPNIC => new String'("Japan Network Information Center License"), JSON => new String'("JSON License"), JasPer_2_0 => new String'("JasPer License"), LAL_1_2 => new String'("Licence Art Libre 1.2"), LAL_1_3 => new String'("Licence Art Libre 1.3"), LGPL_2_0_only => new String'("GNU Library General Public License v2 only"), LGPL_2_0_or_later => new String'("GNU Library General Public License v2 or later"), LGPL_2_1_only => new String'("GNU Lesser General Public License v2.1 only"), LGPL_2_1_or_later => new String'("GNU Lesser General Public License v2.1 or later"), LGPL_3_0_only => new String'("GNU Lesser General Public License v3.0 only"), LGPL_3_0_or_later => new String'("GNU Lesser General Public License v3.0 or later"), LGPLLR => new String'("Lesser General Public License For Linguistic Resources"), LPL_1_0 => new String'("Lucent Public License Version 1.0"), LPL_1_02 => new String'("Lucent Public License v1.02"), LPPL_1_0 => new String'("LaTeX Project Public License v1.0"), LPPL_1_1 => new String'("LaTeX Project Public License v1.1"), LPPL_1_2 => new String'("LaTeX Project Public License v1.2"), LPPL_1_3a => new String'("LaTeX Project Public License v1.3a"), LPPL_1_3c => new String'("LaTeX Project Public License v1.3c"), Latex2e => new String'("Latex2e License"), Leptonica => new String'("Leptonica License"), LiLiQ_P_1_1 => new String'("Licence Libre du Qubec Permissive version 1.1"), LiLiQ_R_1_1 => new String'("Licence Libre du Qubec Rciprocit version 1.1"), LiLiQ_Rplus_1_1 => new String'("Licence Libre du Qubec Rciprocit forte version 1.1"), Libpng => new String'("libpng License"), Linux_OpenIB => new String'("Linux Kernel Variant of OpenIB.org license"), MIT => new String'("MIT License"), MIT_0 => new String'("MIT No Attribution"), MIT_CMU => new String'("CMU License"), MIT_advertising => new String'("Enlightenment License (e16)"), MIT_enna => new String'("enna License"), MIT_feh => new String'("feh License"), MITNFA => new String'("MIT +no-false-attribs license"), MPL_1_0 => new String'("Mozilla Public License 1.0"), MPL_1_1 => new String'("Mozilla Public License 1.1"), MPL_2_0 => new String'("Mozilla Public License 2.0"), MPL_2_0_no_copyleft_exception => new String'("Mozilla Public License 2.0 (no copyleft exception)"), MS_PL => new String'("Microsoft Public License"), MS_RL => new String'("Microsoft Reciprocal License"), MTLL => new String'("Matrix Template Library License"), MakeIndex => new String'("MakeIndex License"), MirOS => new String'("The MirOS Licence"), Motosoto => new String'("Motosoto License"), MulanPSL_1_0 => new String'("Mulan Permissive Software License, Version 1"), MulanPSL_2_0 => new String'("Mulan Permissive Software License, Version 2"), Multics => new String'("Multics License"), Mup => new String'("Mup License"), NASA_1_3 => new String'("NASA Open Source Agreement 1.3"), NBPL_1_0 => new String'("Net Boolean Public License v1"), NCGL_UK_2_0 => new String'("Non-Commercial Government Licence"), NCSA => new String'("University of Illinois/NCSA Open Source License"), NGPL => new String'("Nethack General Public License"), NIST_PD => new String'("NIST Public Domain Notice"), NIST_PD_fallback => new String'("NIST Public Domain Notice with license fallback"), NLOD_1_0 => new String'("Norwegian Licence for Open Government Data"), NLPL => new String'("No Limit Public License"), NOSL => new String'("Netizen Open Source License"), NPL_1_0 => new String'("Netscape Public License v1.0"), NPL_1_1 => new String'("Netscape Public License v1.1"), NPOSL_3_0 => new String'("Non-Profit Open Software License 3.0"), NRL => new String'("NRL License"), NTP => new String'("NTP License"), NTP_0 => new String'("NTP No Attribution"), Naumen => new String'("Naumen Public License"), Net_SNMP => new String'("Net-SNMP License"), NetCDF => new String'("NetCDF license"), Newsletr => new String'("Newsletr License"), Nokia => new String'("Nokia Open Source License"), Noweb => new String'("Noweb License"), O_UDA_1_0 => new String'("Open Use of Data Agreement v1.0"), OCCT_PL => new String'("Open CASCADE Technology Public License"), OCLC_2_0 => new String'("OCLC Research Public License 2.0"), ODC_By_1_0 => new String'("Open Data Commons Attribution License v1.0"), ODbL_1_0 => new String'("ODC Open Database License v1.0"), OFL_1_0 => new String'("SIL Open Font License 1.0"), OFL_1_0_RFN => new String'("SIL Open Font License 1.0 with Reserved Font Name"), OFL_1_0_no_RFN => new String'("SIL Open Font License 1.0 with no Reserved Font Name"), OFL_1_1 => new String'("SIL Open Font License 1.1"), OFL_1_1_RFN => new String'("SIL Open Font License 1.1 with Reserved Font Name"), OFL_1_1_no_RFN => new String'("SIL Open Font License 1.1 with no Reserved Font Name"), OGC_1_0 => new String'("OGC Software License, Version 1.0"), OGL_Canada_2_0 => new String'("Open Government Licence - Canada"), OGL_UK_1_0 => new String'("Open Government Licence v1.0"), OGL_UK_2_0 => new String'("Open Government Licence v2.0"), OGL_UK_3_0 => new String'("Open Government Licence v3.0"), OGTSL => new String'("Open Group Test Suite License"), OLDAP_1_1 => new String'("Open LDAP Public License v1.1"), OLDAP_1_2 => new String'("Open LDAP Public License v1.2"), OLDAP_1_3 => new String'("Open LDAP Public License v1.3"), OLDAP_1_4 => new String'("Open LDAP Public License v1.4"), OLDAP_2_0 => new String'("Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)"), OLDAP_2_0_1 => new String'("Open LDAP Public License v2.0.1"), OLDAP_2_1 => new String'("Open LDAP Public License v2.1"), OLDAP_2_2 => new String'("Open LDAP Public License v2.2"), OLDAP_2_2_1 => new String'("Open LDAP Public License v2.2.1"), OLDAP_2_2_2 => new String'("Open LDAP Public License 2.2.2"), OLDAP_2_3 => new String'("Open LDAP Public License v2.3"), OLDAP_2_4 => new String'("Open LDAP Public License v2.4"), OLDAP_2_5 => new String'("Open LDAP Public License v2.5"), OLDAP_2_6 => new String'("Open LDAP Public License v2.6"), OLDAP_2_7 => new String'("Open LDAP Public License v2.7"), OLDAP_2_8 => new String'("Open LDAP Public License v2.8"), OML => new String'("Open Market License"), OPL_1_0 => new String'("Open Public License v1.0"), OSET_PL_2_1 => new String'("OSET Public License version 2.1"), OSL_1_0 => new String'("Open Software License 1.0"), OSL_1_1 => new String'("Open Software License 1.1"), OSL_2_0 => new String'("Open Software License 2.0"), OSL_2_1 => new String'("Open Software License 2.1"), OSL_3_0 => new String'("Open Software License 3.0"), OpenSSL => new String'("OpenSSL License"), PDDL_1_0 => new String'("ODC Public Domain Dedication & License 1.0"), PHP_3_0 => new String'("PHP License v3.0"), PHP_3_01 => new String'("PHP License v3.01"), PSF_2_0 => new String'("Python Software Foundation License 2.0"), Parity_6_0_0 => new String'("The Parity Public License 6.0.0"), Parity_7_0_0 => new String'("The Parity Public License 7.0.0"), Plexus => new String'("Plexus Classworlds License"), PolyForm_Noncommercial_1_0_0 => new String'("PolyForm Noncommercial License 1.0.0"), PolyForm_Small_Business_1_0_0 => new String'("PolyForm Small Business License 1.0.0"), PostgreSQL => new String'("PostgreSQL License"), Python_2_0 => new String'("Python License 2.0"), QPL_1_0 => new String'("Q Public License 1.0"), Qhull => new String'("Qhull License"), RHeCos_1_1 => new String'("Red Hat eCos Public License v1.1"), RPL_1_1 => new String'("Reciprocal Public License 1.1"), RPL_1_5 => new String'("Reciprocal Public License 1.5"), RPSL_1_0 => new String'("RealNetworks Public Source License v1.0"), RSA_MD => new String'("RSA Message-Digest License"), RSCPL => new String'("Ricoh Source Code Public License"), Rdisc => new String'("Rdisc License"), Ruby => new String'("Ruby License"), SAX_PD => new String'("Sax Public Domain Notice"), SCEA => new String'("SCEA Shared Source License"), SGI_B_1_0 => new String'("SGI Free Software License B v1.0"), SGI_B_1_1 => new String'("SGI Free Software License B v1.1"), SGI_B_2_0 => new String'("SGI Free Software License B v2.0"), SHL_0_5 => new String'("Solderpad Hardware License v0.5"), SHL_0_51 => new String'("Solderpad Hardware License, Version 0.51"), SISSL => new String'("Sun Industry Standards Source License v1.1"), SISSL_1_2 => new String'("Sun Industry Standards Source License v1.2"), SMLNJ => new String'("Standard ML of New Jersey License"), SMPPL => new String'("Secure Messaging Protocol Public License"), SNIA => new String'("SNIA Public License 1.1"), SPL_1_0 => new String'("Sun Public License v1.0"), SSH_OpenSSH => new String'("SSH OpenSSH license"), SSH_short => new String'("SSH short notice"), SSPL_1_0 => new String'("Server Side Public License, v 1"), SWL => new String'("Scheme Widget Library (SWL) Software License Agreement"), Saxpath => new String'("Saxpath License"), Sendmail => new String'("Sendmail License"), Sendmail_8_23 => new String'("Sendmail License 8.23"), SimPL_2_0 => new String'("Simple Public License 2.0"), Sleepycat => new String'("Sleepycat License"), Spencer_86 => new String'("Spencer License 86"), Spencer_94 => new String'("Spencer License 94"), Spencer_99 => new String'("Spencer License 99"), SugarCRM_1_1_3 => new String'("SugarCRM Public License v1.1.3"), TAPR_OHL_1_0 => new String'("TAPR Open Hardware License v1.0"), TCL => new String'("TCL/TK License"), TCP_wrappers => new String'("TCP Wrappers License"), TMate => new String'("TMate Open Source License"), TORQUE_1_1 => new String'("TORQUE v2.5+ Software License v1.1"), TOSL => new String'("Trusster Open Source License"), TU_Berlin_1_0 => new String'("Technische Universitaet Berlin License 1.0"), TU_Berlin_2_0 => new String'("Technische Universitaet Berlin License 2.0"), UCL_1_0 => new String'("Upstream Compatibility License v1.0"), UPL_1_0 => new String'("Universal Permissive License v1.0"), Unicode_DFS_2015 => new String'("Unicode License Agreement - Data Files and Software (2015)"), Unicode_DFS_2016 => new String'("Unicode License Agreement - Data Files and Software (2016)"), Unicode_TOU => new String'("Unicode Terms of Use"), Unlicense => new String'("The Unlicense"), VOSTROM => new String'("VOSTROM Public License for Open Source"), VSL_1_0 => new String'("Vovida Software License v1.0"), Vim => new String'("Vim License"), W3C => new String'("W3C Software Notice and License (2002-12-31)"), W3C_19980720 => new String'("W3C Software Notice and License (1998-07-20)"), W3C_20150513 => new String'("W3C Software Notice and Document License (2015-05-13)"), WTFPL => new String'("Do What The F*ck You Want To Public License"), Watcom_1_0 => new String'("Sybase Open Watcom Public License 1.0"), Wsuipa => new String'("Wsuipa License"), X11 => new String'("X11 License"), XFree86_1_1 => new String'("XFree86 License 1.1"), XSkat => new String'("XSkat License"), Xerox => new String'("Xerox License"), Xnet => new String'("X.Net License"), YPL_1_0 => new String'("Yahoo! Public License v1.0"), YPL_1_1 => new String'("Yahoo! Public License v1.1"), ZPL_1_1 => new String'("Zope Public License 1.1"), ZPL_2_0 => new String'("Zope Public License 2.0"), ZPL_2_1 => new String'("Zope Public License 2.1"), Zed => new String'("Zed License"), Zend_2_0 => new String'("Zend License v2.0"), Zimbra_1_3 => new String'("Zimbra Public License v1.3"), Zimbra_1_4 => new String'("Zimbra Public License v1.4"), Zlib => new String'("zlib License"), blessing => new String'("SQLite Blessing"), bzip2_1_0_5 => new String'("bzip2 and libbzip2 License v1.0.5"), bzip2_1_0_6 => new String'("bzip2 and libbzip2 License v1.0.6"), copyleft_next_0_3_0 => new String'("copyleft-next 0.3.0"), copyleft_next_0_3_1 => new String'("copyleft-next 0.3.1"), curl => new String'("curl License"), diffmark => new String'("diffmark license"), dvipdfm => new String'("dvipdfm License"), eGenix => new String'("eGenix.com Public License 1.1.0"), etalab_2_0 => new String'("Etalab Open License 2.0"), gSOAP_1_3b => new String'("gSOAP Public License v1.3b"), gnuplot => new String'("gnuplot License"), iMatix => new String'("iMatix Standard Function Library Agreement"), libpng_2_0 => new String'("PNG Reference Library version 2"), libselinux_1_0 => new String'("libselinux public domain notice"), libtiff => new String'("libtiff License"), mpich2 => new String'("mpich2 License"), psfrag => new String'("psfrag License"), psutils => new String'("psutils License"), xinetd => new String'("xinetd License"), xpp => new String'("XPP License"), zlib_acknowledgement => new String'("zlib/libpng License with Acknowledgement")); function Name (I : Id) return String is (Name_Ptr (I).all); function Valid_Id (Str : String) return Boolean; function From_Id (Str : String) return Id; end SPDX.Licenses; alire-1.2.1/deps/spdx/src/spdx.adb000066400000000000000000000265251375715564200167660ustar00rootroot00000000000000with Ada.Strings; with Ada.Strings.Fixed; with Ada.Characters.Handling; use Ada.Characters.Handling; with SPDX.Licenses; with SPDX.Exceptions; package body SPDX is function Token_Str (This : Expression; Loc : Location) return String; function Is_Custom_Id (Str : String) return Boolean; procedure Parse_License (This : in out Expression); procedure Parse_Compound_Expression (This : in out Expression); procedure Parse_Simple_Expression (This : in out Expression); procedure Parse_Exception (This : in out Expression); --------------- -- Token_Str -- --------------- function Token_Str (This : Expression; Loc : Location) return String is begin if Loc.From not in This.Str'Range or else Loc.To not in This.Str'Range then return ""; else return This.Str (Loc.From .. Loc.To); end if; end Token_Str; ------------------ -- Is_Custom_Id -- ------------------ function Is_Custom_Id (Str : String) return Boolean is Lower : constant String := To_Lower (Str); Prefix : constant String := "custom-"; begin return Lower'Length > Prefix'Length and then Lower (Lower'First .. Lower'First + Prefix'Length - 1) = Prefix; end Is_Custom_Id; ------------------- -- Parse_License -- ------------------- procedure Parse_License (This : in out Expression) is begin Parse_Compound_Expression (This); if This.Error /= None then return; end if; if not This.Tokens.Is_Empty then This.Error := Unexpected_Token; This.Err_Loc := This.Tokens.First_Element.Loc; end if; end Parse_License; ------------------------------- -- Parse_Compound_Expression -- ------------------------------- procedure Parse_Compound_Expression (This : in out Expression) is begin -- compound = ( compound ) -- | simple -- | simple AND compound -- | simple OR compound if This.Tokens.Is_Empty then This.Error := Empty_Expression; This.Err_Loc := (This.Str'Last, This.Str'Last); return; end if; case This.Tokens.First_Element.Kind is when Paren_Open => This.Tokens.Delete_First; Parse_Compound_Expression (This); if This.Error /= None then return; end if; if This.Tokens.Is_Empty then This.Error := Paren_Close_Expected; This.Err_Loc := (This.Str'Last, This.Str'Last); return; end if; if This.Tokens.First_Element.Kind /= Paren_Close then This.Error := Paren_Close_Expected; This.Err_Loc := This.Tokens.First_Element.Loc; return; end if; -- Delete the Paren_Close This.Tokens.Delete_First; when Id_Str => Parse_Simple_Expression (This); if This.Error /= None then return; end if; when others => This.Error := Unexpected_Token; This.Err_Loc := This.Tokens.First_Element.Loc; return; end case; if This.Tokens.Is_Empty then -- End of expression return; end if; if This.Tokens.First_Element.Kind in Op_And | Op_Or then -- Just skip operator as we do not build the AST This.Tokens.Delete_First; Parse_Compound_Expression (This); end if; end Parse_Compound_Expression; ----------------------------- -- Parse_Simple_Expression -- ----------------------------- procedure Parse_Simple_Expression (This : in out Expression) is begin -- simple = id -- | id+ -- | id exception -- | id+ exception if This.Tokens.Is_Empty then This.Error := License_Id_Expected; This.Err_Loc := (This.Str'Last, This.Str'Last); return; end if; if This.Tokens.First_Element.Kind /= Id_Str then This.Error := License_Id_Expected; This.Err_Loc := This.Tokens.First_Element.Loc; return; end if; declare License_Id : constant String := Token_Str (This, This.Tokens.First_Element.Loc); begin if This.Allow_Custom and then Is_Custom_Id (License_Id) then This.Has_Custom_Id := True; elsif not SPDX.Licenses.Valid_Id (License_Id) then This.Error := Invalid_License_Id; This.Err_Loc := This.Tokens.First_Element.Loc; end if; This.Tokens.Delete_First; if This.Tokens.Is_Empty then return; end if; -- + operator if This.Tokens.First_Element.Kind = Op_Or_Later then This.Tokens.Delete_First; end if; if This.Tokens.Is_Empty then return; end if; Parse_Exception (This); end; end Parse_Simple_Expression; --------------------- -- Parse_Exception -- --------------------- procedure Parse_Exception (This : in out Expression) is begin -- exception = -- | WITH id if This.Tokens.First_Element.Kind = Op_With then This.Tokens.Delete_First; if This.Tokens.Is_Empty then This.Error := Exception_Id_Expected; This.Err_Loc := (This.Str'Last, This.Str'Last); return; end if; if This.Tokens.First_Element.Kind /= Id_Str then This.Error := Exception_Id_Expected; This.Err_Loc := This.Tokens.First_Element.Loc; return; end if; declare Exception_Id : constant String := Token_Str (This, This.Tokens.First_Element.Loc); begin if not SPDX.Exceptions.Valid_Id (Exception_Id) then This.Error := Invalid_Exception_Id; This.Err_Loc := This.Tokens.First_Element.Loc; end if; This.Tokens.Delete_First; end; end if; end Parse_Exception; ----------- -- Parse -- ----------- function Parse (Str : String; Allow_Custom : Boolean := False) return Expression is Exp : Expression (Str'Length); begin Exp.Str := Str; Exp.Allow_Custom := Allow_Custom; Tokenize (Exp); if Exp.Error /= None then return Exp; end if; Parse_License (Exp); return Exp; end Parse; ----------- -- Error -- ----------- function Error (This : Expression) return String is function Img (N : Natural) return String; function Img (Loc : Location) return String; --------- -- Img -- --------- function Img (N : Natural) return String is (Ada.Strings.Fixed.Trim (N'Img, Ada.Strings.Left)); --------- -- Img -- --------- function Img (Loc : Location) return String is ((Img (Loc.From) & ":" & Img (Loc.To))); begin case This.Error is when None => return ""; when Or_Later_Misplaced => return "+ operator must follow and indentifier without " & "whitespace (" & Img (This.Err_Loc) & ")"; when Invalid_Char => return "Invalid character at " & Img (This.Err_Loc.From); when Operator_Lowcase => return "Operator must be uppercase at (" & Img (This.Err_Loc) & ")"; when Unexpected_Token => return "Unexpected token at (" & Img (This.Err_Loc) & ")"; when Paren_Close_Expected => return "Missing closing parentheses ')' at (" & Img (This.Err_Loc) & ")"; when License_Id_Expected => return "License id expected at (" & Img (This.Err_Loc) & ")"; when Invalid_License_Id => return "Invalid license ID: '" & Token_Str (This, This.Err_Loc) & "' (" & Img (This.Err_Loc) & ")"; when Exception_Id_Expected => return "License exception id expected at (" & Img (This.Err_Loc) & ")"; when Invalid_Exception_Id => return "Invalid license exception ID: '" & Token_Str (This, This.Err_Loc) & "' (" & Img (This.Err_Loc) & ")"; when Empty_Expression => return "Empty license expression at (" & Img (This.Err_Loc) & ")"; end case; end Error; ----------- -- Valid -- ----------- function Valid (This : Expression) return Boolean is begin return This.Error = None; end Valid; --------- -- Img -- --------- function Img (This : Expression) return String is begin return This.Str; end Img; ---------------- -- Has_Custom -- ---------------- function Has_Custom (This : Expression) return Boolean is (This.Has_Custom_Id); -------------- -- Tokenize -- -------------- procedure Tokenize (This : in out Expression) is Tokens : Token_Vector.Vector renames This.Tokens; Str : String renames This.Str; Index : Natural := Str'First; begin while Index in Str'Range loop if Str (Index) in Whitespace_Characters then Index := Index + 1; -- Skip whitespace elsif Str (Index) = '(' then Tokens.Append ((Paren_Open, (Index, Index))); Index := Index + 1; elsif Str (Index) = ')' then Tokens.Append ((Paren_Close, (Index, Index))); Index := Index + 1; elsif Str (Index) = '+' then This.Error := Or_Later_Misplaced; This.Err_Loc := (Index, Index); return; elsif Str (Index) in Id_Characters then -- Operator or identifier declare From : constant Natural := Index; begin while Index in Str'Range and then Str (Index) in Id_Characters | '+' loop Index := Index + 1; end loop; declare To : constant Natural := Index - 1; Substr : constant String := Str (From .. To); begin if Substr = "WITH" then Tokens.Append ((Op_With, (From, To))); elsif Substr = "OR" then Tokens.Append ((Op_Or, (From, To))); elsif Substr = "AND" then Tokens.Append ((Op_And, (From, To))); elsif To_Lower (Substr) = "with" or else To_Lower (Substr) = "or" or else To_Lower (Substr) = "and" then This.Error := Operator_Lowcase; This.Err_Loc := (From, To); return; else if Str (To) = '+' then -- + operator can be found after and id (without -- whitespace). Tokens.Append ((Id_Str, (From, To - 1))); Tokens.Append ((Op_Or_Later, (To, To))); else Tokens.Append ((Id_Str, (From, To))); end if; end if; end; end; else This.Error := Invalid_Char; This.Err_Loc := (Index, Index); return; end if; end loop; end Tokenize; end SPDX; alire-1.2.1/deps/spdx/src/spdx.ads000066400000000000000000000051141375715564200167760ustar00rootroot00000000000000with Ada.Containers.Vectors; package SPDX is type Expression (<>) is private; function Parse (Str : String; Allow_Custom : Boolean := False) return Expression; -- Parse an SPDX expression from string. -- -- If Allow_Custom is True, the parser will accept custom license id with -- the format: "custom-[0-9a-zA-Z.-]+". function Valid (This : Expression) return Boolean; -- Return True if the SPDX expression is valid function Error (This : Expression) return String with Pre => not Valid (This); -- Return the error message for an invalid SPDX expression function Img (This : Expression) return String with Pre => Valid (This); -- Return the string representation of a valid SPDX expression function Has_Custom (This : Expression) return Boolean; -- Return True if the expression contains a custom license ID private subtype Id_Characters is Character with Dynamic_Predicate => Id_Characters in 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '-' | '.'; subtype Id_String is String with Dynamic_Predicate => (for all C of Id_String => C in Id_Characters); subtype Whitespace_Characters is Character with Dynamic_Predicate => Whitespace_Characters in ' ' | ASCII.HT; type Token_Kind is (Op_Or_Later, Op_With, Op_Or, Op_And, Id_Str, Paren_Open, Paren_Close); subtype Operator is Token_Kind range Op_Or_Later .. Op_And; type Location is record From, To : Natural; end record; type Token is record Kind : Token_Kind; Loc : Location; -- Position in the parsed string end record; package Token_Vector is new Ada.Containers.Vectors (Index_Type => Natural, Element_Type => Token); type Error_Kind is (None, Or_Later_Misplaced, Invalid_Char, Operator_Lowcase, Unexpected_Token, Paren_Close_Expected, License_Id_Expected, Invalid_License_Id, Exception_Id_Expected, Invalid_Exception_Id, Empty_Expression); type Expression (Str_Len : Natural) is record Str : String (1 .. Str_Len); Tokens : Token_Vector.Vector; Error : Error_Kind := None; Err_Loc : Location; Allow_Custom : Boolean := False; Has_Custom_Id : Boolean := False; end record; procedure Tokenize (This : in out Expression) with Pre => This.Tokens.Is_Empty; end SPDX; alire-1.2.1/deps/spdx/tests/000077500000000000000000000000001375715564200157015ustar00rootroot00000000000000alire-1.2.1/deps/spdx/tests/src/000077500000000000000000000000001375715564200164705ustar00rootroot00000000000000alire-1.2.1/deps/spdx/tests/src/main.adb000066400000000000000000000102661375715564200200710ustar00rootroot00000000000000with Ada.Text_IO; use Ada.Text_IO; with Ada.Command_Line; with Ada.Exceptions; with SPDX; procedure Main is Fail_Cnt : Natural := 0; Pass_Cnt : Natural := 0; procedure Test (Str : String; Expected_Error : String := ""; Allow_Custom : Boolean := False); procedure Test (Str : String; Expected_Error : String := ""; Allow_Custom : Boolean := False) is begin declare Exp : constant SPDX.Expression := SPDX.Parse (Str, Allow_Custom); Error : constant String := (if SPDX.Valid (Exp) then "" else SPDX.Error (Exp)); begin if Error /= Expected_Error then Put_Line ("FAIL: '" & Str & "'"); if Expected_Error /= "" then Put_Line (" Expected error: '" & Expected_Error & "'"); Put_Line (" but got : '" & Error & "'"); else Put_Line (" Unexpected error: '" & Error & "'"); end if; Fail_Cnt := Fail_Cnt + 1; elsif Expected_Error = "" and then Allow_Custom and then not SPDX.Has_Custom (Exp) then Put_Line ("FAIL: '" & Str & "'"); Put_Line (" Has_Custom returned False"); Fail_Cnt := Fail_Cnt + 1; else Put_Line ("PASS: '" & Str & "'"); Pass_Cnt := Pass_Cnt + 1; end if; end; exception when E : others => Put_Line ("FAIL: '" & Str & "'"); Put_Line (" With exception: '" & Ada.Exceptions.Exception_Information (E) & "'"); Fail_Cnt := Fail_Cnt + 1; end Test; begin -- Test all invalid chars for C in Character loop if C not in 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '-' | '.' | '(' | ')' | '+' | ' ' | ASCII.HT then Test ("test" & C, "Invalid character at 5"); end if; end loop; Test ("", "Empty license expression at (0:0)"); Test ("test-3", "Invalid license ID: 'test-3' (1:6)"); Test ("test-3.0", "Invalid license ID: 'test-3.0' (1:8)"); Test ("MIT"); Test ("MIT+"); Test ("MIT OR MIT"); Test ("MIT AND MIT"); Test ("MIT Or MIT", "Operator must be uppercase at (5:6)"); Test ("MIT anD MIT", "Operator must be uppercase at (5:7)"); Test ("MIT WITH AND", "License exception id expected at (10:12)"); Test ("MIT WITH", "License exception id expected at (8:8)"); Test ("MIT WITH plop", "Invalid license exception ID: 'plop' (10:13)"); Test ("MIT WITH GPL-3.0-linking-exception"); Test ("(MIT)"); Test ("(MIT) AND MIT"); Test ("(MIT+) AND (MIT)"); Test ("((MIT) AND (MIT+))"); Test ("((MIT) AND (MIT+ OR MIT AND MIT AND (MIT WITH GPL-3.0-linking-exception AND MIT)))"); Test ("MIT +", "+ operator must follow and indentifier without whitespace (5:5)"); Test ("MIT AND +", "+ operator must follow and indentifier without whitespace (9:9)"); Test ("MIT+AND", "Invalid license ID: 'MIT+AND' (1:7)"); Test ("MIT AND", "Empty license expression at (7:7)"); Test ("MIT OR", "Empty license expression at (6:6)"); Test ("MIT MIT", "Unexpected token at (5:7)"); Test ("(MIT", "Missing closing parentheses ')' at (4:4)"); Test ("MIT)", "Unexpected token at (4:4)"); Test ("(MIT AND (MIT OR MIT)", "Missing closing parentheses ')' at (21:21)"); Test ("MIT AND (MIT OR MIT))", "Unexpected token at (21:21)"); Test ("custom-plop", "Invalid license ID: 'custom-plop' (1:11)", Allow_Custom => False); Test ("custom", "Invalid license ID: 'custom' (1:6)", Allow_Custom => True); Test ("custom-", "Invalid license ID: 'custom-' (1:7)", Allow_Custom => True); Test ("custom-plop", Allow_Custom => True); Test ("custom-plop+", Allow_Custom => True); Test ("custom-test:test", "Invalid character at 12", Allow_Custom => True); Test ("CuStoM-test-1.0.3", Allow_Custom => True); Test ("custom-test AND custom-plop", Allow_Custom => True); Put_Line ("PASS:" & Pass_Cnt'Img); Put_Line ("FAIL:" & Fail_Cnt'Img); if Fail_Cnt /= 0 then Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure); end if; end Main; alire-1.2.1/deps/spdx/tests/tests.gpr000066400000000000000000000004071375715564200175560ustar00rootroot00000000000000with "../spdx.gpr"; project Tests is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Main use ("main.adb"); package Compiler is for Switches ("Ada") use ("-gnata"); end Compiler; end Tests; pax_global_header00006660000000000000000000000064141163543610014516gustar00rootroot0000000000000052 comment=86e7302d29f360f98f568b6015755229949b2194 alire-1.2.1/deps/stopwatch/000077500000000000000000000000001411635436100155625ustar00rootroot00000000000000alire-1.2.1/deps/stopwatch/.gitignore000066400000000000000000000000311411635436100175440ustar00rootroot00000000000000obj/ lib/ alire/ config/ alire-1.2.1/deps/stopwatch/LICENSE000066400000000000000000000020631411635436100165700ustar00rootroot00000000000000MIT License Copyright (c) 2021 Alejandro R Mosteo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. alire-1.2.1/deps/stopwatch/README.md000066400000000000000000000000511411635436100170350ustar00rootroot00000000000000# stopwatch A type to track elapsed time alire-1.2.1/deps/stopwatch/alire.toml000066400000000000000000000004341411635436100175540ustar00rootroot00000000000000name = "stopwatch" description = "Keep track of elapsed time" version = "0.1.0" tags = ["timer", "stopwatch", "chronometer"] authors = ["Alejandro R. Mosteo"] maintainers = ["Alejandro R. Mosteo "] maintainers-logins = ["mosteo"] configuration.disabled = true alire-1.2.1/deps/stopwatch/src/000077500000000000000000000000001411635436100163515ustar00rootroot00000000000000alire-1.2.1/deps/stopwatch/src/stopwatch.adb000066400000000000000000000037311411635436100210410ustar00rootroot00000000000000with Ada.Text_IO; package body Stopwatch is ----------- -- Reset -- ----------- procedure Reset (This : in out Instance) is begin This := (others => <>); end Reset; ------------- -- Elapsed -- ------------- function Elapsed (This : Instance) return Duration is begin return This.Elapsed + (if This.Is_Held then 0.0 else Clock - This.Start); end Elapsed; ---------- -- Hold -- ---------- procedure Hold (This : in out Instance; Enable : Boolean := True) is begin if Enable and then not This.Is_Held then This.Held := True; This.Elapsed := This.Elapsed + (Clock - This.Start); elsif not Enable and then This.Is_Held then This.Held := False; This.Start := Clock; end if; end Hold; ----------- -- Image -- ----------- function Image (This : Instance; Decimals : Natural := 2) return String is (Image (Elapsed (This), Decimals)); ----------- -- Image -- ----------- function Image (Elapsed : Duration; Decimals : Natural := 2) return String is package FIO is new Ada.Text_IO.Fixed_IO (Duration); package IIO is new Ada.Text_IO.Integer_IO (Natural); Buffer : String (1 .. 32) := (others => ' '); begin if Decimals > 0 then FIO.Put (Buffer, Elapsed, Aft => Decimals); else IIO.Put (Buffer, Natural (Elapsed)); end if; -- Locate first non-blank and return from there, as Put is right-aligned for I in Buffer'Range loop if Buffer (I) /= ' ' then return Buffer (I .. Buffer'Last); end if; end loop; raise Program_Error with "Put did not put anything"; end Image; ------------- -- Is_Held -- ------------- function Is_Held (This : Instance) return Boolean is (This.Held); procedure Release (This : in out Instance) is begin This.Hold (Enable => False); end Release; end Stopwatch; alire-1.2.1/deps/stopwatch/src/stopwatch.ads000066400000000000000000000020231411635436100210530ustar00rootroot00000000000000private with Ada.Calendar; package Stopwatch is type Instance is tagged private; procedure Reset (This : in out Instance); function Elapsed (This : Instance) return Duration; procedure Hold (This : in out Instance; Enable : Boolean := True); -- Stop counting time, or re-start if not Enable procedure Release (This : in out Instance); -- Equivalent to Hold (Enable => False) function Is_Held (This : Instance) return Boolean; function Image (This : Instance; Decimals : Natural := 2) return String; -- Elapsed time in seconds, without leading space, without units function Image (Elapsed : Duration; Decimals : Natural := 2) return String; -- Convenience to format durations even without a stopwatch private use Ada.Calendar; type Instance is tagged record Start : Time := Clock; -- Last moment the timer was released/started Held : Boolean := False; Elapsed : Duration := 0.0; -- Track elapsed time when held end record; end Stopwatch; alire-1.2.1/deps/stopwatch/stopwatch.gpr000066400000000000000000000055141411635436100203150ustar00rootroot00000000000000project Stopwatch is for Library_Name use "Stopwatch"; for Library_Version use "0.0.0"; for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Library_Dir use "lib"; type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := external ("STOPWATCH_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); for Library_Kind use Library_Type; type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("STOPWATCH_COMPILE_CHECKS", "disabled"); Runtime_Checks : Enabled_Kind := External ("STOPWATCH_RUNTIME_CHECKS", "disabled"); Style_Checks : Enabled_Kind := External ("STOPWATCH_STYLE_CHECKS", "disabled"); Contracts_Checks : Enabled_Kind := External ("STOPWATCH_CONTRACTS", "disabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("STOPWATCH_BUILD_MODE", "optimize"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Supress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-d", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnatyO"); -- Overriding subprograms explicitly marked as such when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => null; end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnatw.X", -- Disable warnings for No_Exception_Propagation "-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Stopwatch; pax_global_header00006660000000000000000000000064142112012700014500gustar00rootroot0000000000000052 comment=8b9dff0f450394b07ea71f0eb9b39d9c20e21f9c alire-1.2.1/deps/toml_slicer/000077500000000000000000000000001421120127000160445ustar00rootroot00000000000000alire-1.2.1/deps/toml_slicer/.gitignore000066400000000000000000000000451421120127000200330ustar00rootroot00000000000000obj/ lib/ alire/ alire.lock config/ alire-1.2.1/deps/toml_slicer/LICENSE000066400000000000000000000020631421120127000170520ustar00rootroot00000000000000MIT License Copyright (c) 2021 Alejandro R Mosteo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. alire-1.2.1/deps/toml_slicer/alire.toml000066400000000000000000000003401421120127000200320ustar00rootroot00000000000000name = "toml_slicer" description = "Edit TOML files directly without parsing" version = "0.1.0" authors = ["Alejandro R. Mosteo"] maintainers = ["Alejandro R. Mosteo "] maintainers-logins = ["mosteo"] alire-1.2.1/deps/toml_slicer/src/000077500000000000000000000000001421120127000166335ustar00rootroot00000000000000alire-1.2.1/deps/toml_slicer/src/toml_slicer.adb000066400000000000000000000247721421120127000216330ustar00rootroot00000000000000with AAA.Filesystem; with AAA.Strings; with AAA.Text_IO; with Ada.Text_IO; package body TOML_Slicer is Debug : constant Boolean := False; --------------- -- Debug_Put -- --------------- procedure Put_Debug (Line : String) is begin if Debug then Ada.Text_IO.Put_Line ("[TOML_Slicer debug] " & Line); end if; end Put_Debug; ------------------ -- Remove_Array -- ------------------ procedure Remove_Array (File_Name : String; Array_Name : String; Backup : Boolean; Backup_Dir : String := ".") is ------------ -- Remove -- ------------ procedure Remove (Lines : in out AAA.Strings.Vector) is use AAA.Strings; Starter_1 : constant String := "[[" & Array_Name & "]]"; Starter_2 : constant String := "[[" & Array_Name & "."; Starter_3 : constant String := "[" & Array_Name & "."; ------------------ -- Out_Of_Array -- ------------------ function Out_Of_Array (Line : String) return Boolean is begin -- Check this is a simple nested table field or empty line if Line'Length = 0 or else Line (Line'First) /= '[' then return False; end if; -- Otherwise, check we're not entering a different array if Has_Prefix (Line, Starter_1) or else Has_Prefix (Line, Starter_2) or else Has_Prefix (Line, Starter_3) then -- Still fields/entries of the same array, -- either a subtable or a nested array. See -- https://toml.io/en/v1.0.0#array-of-tables return False; else return True; end if; end Out_Of_Array; Armed : Boolean := False; -- True when we are inside [[array]] I : Positive := 1; begin while I <= Lines.Last_Index loop declare Line : constant String := Replace (Lines (I), " ", ""); begin if Armed then if not Out_Of_Array (Line) then Put_Debug ("DELETE: " & Line); Lines.Delete (I); else Put_Debug ("DISARM: " & Line); Armed := False; I := I + 1; end if; else -- not armed if Has_Prefix (Line, Starter_1) or else Has_Prefix (Line, Starter_2) -- Starter_3 would be a nested table but not array then Put_Debug ("ARMED: " & Line); Armed := True; Lines.Delete (I); else Put_Debug ("NOT ARM: " & Line); I := I + 1; end if; end if; end; end loop; end Remove; Replacer : constant AAA.Filesystem.Replacer := AAA.Filesystem.New_Replacement (File_Name, Backup => Backup, Backup_Dir => Backup_Dir); begin declare File : constant AAA.Text_IO.File := AAA.Text_IO.Load (Replacer.Editable_Name, Backup => False); -- Replacer takes care of backup begin Remove (File.Lines.all); end; -- File goes out of scope here and rewrites the contents, so the -- replacer keeps the already modified file. Replacer.Replace; -- All went well, keep the changes end Remove_Array; ---------------------------- -- Remove_Line_From_Array -- ---------------------------- procedure Remove_Line_From_Array (File_Name : String; Array_Name : String; Entry_Name : String; Cleanup : Boolean; Backup : Boolean; Backup_Dir : String := ".") is ------------ -- Remove -- ------------ procedure Remove (Lines : in out AAA.Strings.Vector) -- Remove Entry_Name from Lines is Enter_Marker : constant String := "[[" & Array_Name & "]]"; -- We must see a line like this before being able to remove a dep. Target : constant String := Entry_Name & "="; -- A line starting with Target is a candidate for deletion Armed : Boolean := False; -- True when we are inside [[array]] Found : Boolean := False; -- True when the entry was found ------------------- -- Remove_Target -- ------------------- procedure Remove_Target is use AAA.Strings; begin for I in Lines.First_Index .. Lines.Last_Index loop declare Line : constant String := Replace (Lines (I), " ", ""); begin if Armed and then Has_Prefix (Line, Target) then Found := True; Lines.Delete (I); exit; elsif Has_Prefix (Line, "[[") then -- Detect a plain [[array]] with optional comment Armed := Line = Enter_Marker or else Has_Prefix (Line, Enter_Marker & '#'); elsif Armed and then Line /= "" and then Line (Line'First) /= '[' -- not a table or different array then -- We are seeing a different entry in the same array -- entry; we can still remove our target if later found -- in this entry. null; elsif Line = "" or else Has_Prefix (Line, "#") then -- We still can remove an entry found in this array entry null; else -- Any other sighting complicates matters and we won't -- touch it. Armed := False; -- TODO: be able to remove a table in the array named as -- Entry, i.e., something like: -- [[array]] -- [array.entry] or [array.entry.etc] -- etc -- Or, be able to remove something like -- [[array]] -- entry.field = ... end if; end; end loop; if not Found then raise Slicing_Error with "Could not find removable entry " & Entry_Name & " in array " & Array_Name & " in file " & File_Name; return; end if; end Remove_Target; ------------------------- -- Remove_Empty_Arrays -- ------------------------- procedure Remove_Empty_Arrays is -- This might probably be done with multiline regular expressions Deletable : Natural := 0; -- Tracks how many empty lines we have seen since the last [[ Can_Delete : Boolean := True; -- We can delete as long as we are only seeing empty lines use AAA.Strings; begin -- Traverse lines backwards for I in reverse Lines.First_Index .. Lines.Last_Index loop declare Line : constant String := Replace (Lines (I), " ", ""); begin if Can_Delete then -- Look for empty lines or the opening [[array]] if Line = "" then Deletable := Deletable + 1; elsif Line = Enter_Marker or else Has_Prefix (Line, Enter_Marker & '#') then -- Now we can delete the empty [[array]] plus any -- following empty lines. for J in 0 .. Deletable loop -- 0 for the current line Lines.Delete (I); end loop; -- Restart, we can still delete previous entries Deletable := 0; else -- We found something else, so do not remove entry Can_Delete := False; Deletable := 0; end if; else -- Look for a [[ that starts another array entry. We -- cannot rely on simply [ for tables, these could be -- nested array tables. if Has_Prefix (Line, "[[") then Can_Delete := True; Deletable := 0; -- We will look in next iterations for a precedent -- empty array entry. end if; end if; end; end loop; end Remove_Empty_Arrays; begin -- First pass, remove a detected entries in the proper location. -- Note that this only removes the entry line, but not the enclosing -- [[array]]. It is ok to have such an empty array entry. Empty array -- entries are cleaned up afterwards. Remove_Target; -- Second pass, remove empty [[array]] array entries. This ensures -- that trivial add/remove of array entries cannot grow the file -- indefinitely with empty [[]] entries. if Cleanup then Remove_Empty_Arrays; end if; end Remove; Replacer : constant AAA.Filesystem.Replacer := AAA.Filesystem.New_Replacement (File_Name, Backup => Backup, Backup_Dir => Backup_Dir); begin declare File : constant AAA.Text_IO.File := AAA.Text_IO.Load (Replacer.Editable_Name, Backup => False); -- Replacer takes care of backup begin Remove (File.Lines.all); end; Replacer.Replace; -- All went well, keep the changes end Remove_Line_From_Array; end TOML_Slicer; alire-1.2.1/deps/toml_slicer/src/toml_slicer.ads000066400000000000000000000024451421120127000216450ustar00rootroot00000000000000package TOML_Slicer is -- Procedures to directly edit a TOML file without parsing it. Heavily -- incomplete and tailored to Alire needs. Slicing_Error : exception; -- Raised when the requested operation could not be completed. Original -- file remains untouched. procedure Remove_Array (File_Name : String; Array_Name : String; Backup : Boolean; Backup_Dir : String := "."); -- Remove all top-level array-of-tables [[Array_Name]] entries and the -- array itself. If Backup, a "filename.prev" file will be copied into -- Backup_Dir with the original contents. It will procedure Remove_Line_From_Array (File_Name : String; Array_Name : String; Entry_Name : String; Cleanup : Boolean; Backup : Boolean; Backup_Dir : String := "."); -- Removes a line starting with Entry_Name = ... from [[Array_Name]]. If -- Cleanup, it will remove empty array entries (all of them). If Backup, -- a "filename.prev" file will be copied into Backup_Dir with the original -- contents. end TOML_Slicer; alire-1.2.1/deps/toml_slicer/toml_slicer.gpr000066400000000000000000000056261421120127000211030ustar00rootroot00000000000000with "aaa"; project Toml_Slicer is for Library_Name use "Toml_Slicer"; for Library_Version use "0.0.0"; for Source_Dirs use ("src"); for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; for Library_Dir use "lib"; type Library_Type_Type is ("relocatable", "static", "static-pic"); Library_Type : Library_Type_Type := external ("TOML_SLICER_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); for Library_Kind use Library_Type; type Enabled_Kind is ("enabled", "disabled"); Compile_Checks : Enabled_Kind := External ("TOML_SLICER_COMPILE_CHECKS", "enabled"); Runtime_Checks : Enabled_Kind := External ("TOML_SLICER_RUNTIME_CHECKS", "enabled"); Style_Checks : Enabled_Kind := External ("TOML_SLICER_STYLE_CHECKS", "enabled"); Contracts_Checks : Enabled_Kind := External ("TOML_SLICER_CONTRACTS", "enabled"); type Build_Kind is ("debug", "optimize"); Build_Mode : Build_Kind := External ("TOML_SLICER_BUILD_MODE", "debug"); Compile_Checks_Switches := (); case Compile_Checks is when "enabled" => Compile_Checks_Switches := ("-gnatwa", -- All warnings "-gnatVa", -- All validity checks "-gnatwe"); -- Warnings as errors when others => null; end case; Runtime_Checks_Switches := (); case Runtime_Checks is when "enabled" => null; when others => Runtime_Checks_Switches := ("-gnatp"); -- Supress checks end case; Style_Checks_Switches := (); case Style_Checks is when "enabled" => Style_Checks_Switches := ("-gnatyg", -- GNAT Style checks "-gnaty-d", -- Disable no DOS line terminators "-gnatyM80", -- Maximum line length "-gnaty-s", -- Relax Fwd Declarations "-gnatyO"); -- Overriding subprograms explicitly marked as such when others => null; end case; Contracts_Switches := (); case Contracts_Checks is when "enabled" => Contracts_Switches := ("-gnata"); -- Enable assertions and contracts when others => null; end case; Build_Switches := (); case Build_Mode is when "optimize" => Build_Switches := ("-O3", -- Optimization "-gnatn"); -- Enable inlining when "debug" => Build_Switches := ("-g", -- Debug info "-Og"); -- No optimization end case; package Compiler is for Default_Switches ("Ada") use Compile_Checks_Switches & Build_Switches & Runtime_Checks_Switches & Style_Checks_Switches & Contracts_Switches & ("-gnatw.X", -- Disable warnings for No_Exception_Propagation "-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities end Compiler; package Binder is for Switches ("Ada") use ("-Es"); -- Symbolic traceback end Binder; end Toml_Slicer; pax_global_header00006660000000000000000000000064140273505250014515gustar00rootroot0000000000000052 comment=b61eba59099b3ab39e59e228fe4529927f9e849e alire-1.2.1/deps/uri-ada/000077500000000000000000000000001402735052500150675ustar00rootroot00000000000000alire-1.2.1/deps/uri-ada/.github/000077500000000000000000000000001402735052500164275ustar00rootroot00000000000000alire-1.2.1/deps/uri-ada/.github/workflows/000077500000000000000000000000001402735052500204645ustar00rootroot00000000000000alire-1.2.1/deps/uri-ada/.github/workflows/build.yml000066400000000000000000000006331402735052500223100ustar00rootroot00000000000000name: Build on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Set up GNAT toolchain run: > sudo apt-get update && sudo apt-get install gnat gprbuild - name: Build run: gprbuild -j0 -p - name: Test run: bin/uri-test alire-1.2.1/deps/uri-ada/.gitignore000066400000000000000000000000361402735052500170560ustar00rootroot00000000000000*.ali *.o alire/ bin lib obj alire-1.2.1/deps/uri-ada/LICENSE000066400000000000000000000020631402735052500160750ustar00rootroot00000000000000MIT License Copyright (c) 2020 Alejandro R Mosteo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. alire-1.2.1/deps/uri-ada/README.md000066400000000000000000000003421402735052500163450ustar00rootroot00000000000000[![build](https://github.com/mosteo/uri-ada/workflows/Build/badge.svg)](https://github.com/mosteo/uri-ada/actions) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) # uri-ada URI parsing for Ada alire-1.2.1/deps/uri-ada/alire.toml000066400000000000000000000004511402735052500170600ustar00rootroot00000000000000name = "uri_ada" description = "Processing of URI strings" version = "1.0-dev" licenses = "LGPL-3.0-only" authors = ["Alejandro R. Mosteo"] maintainers = ["Alejandro R. Mosteo "] maintainers-logins = ["mosteo"] tags = ["uri", "url", "utility"] project-files = ["uri.gpr"] alire-1.2.1/deps/uri-ada/src/000077500000000000000000000000001402735052500156565ustar00rootroot00000000000000alire-1.2.1/deps/uri-ada/src/uri-test.adb000066400000000000000000000104111402735052500200770ustar00rootroot00000000000000-- with Ada.Text_IO; use Ada.Text_IO; procedure URI.Test is T_1 : constant String := "http://anon:1234@www.dummy.com/highway/to/?sure&really#hell"; T_2 : constant String := "urn:example:animal:ferret:nose"; begin -- Individual parts pragma Assert (Extract ("", Scheme) = ""); pragma Assert (Extract ("file:", Scheme) = "file"); pragma Assert (Extract (" file:", Scheme) = "file"); -- leading whitespace pragma Assert (Extract ("#space ", Fragment) = "space"); -- lagging whitespace pragma Assert (Extract ("#space", Path) = ""); -- Empty path pragma Assert (Extract (T_1, Scheme) = "http"); pragma Assert (Extract (T_1, Authority) = "anon:1234@www.dummy.com"); pragma Assert (Extract (T_1, Path) = "/highway/to/"); pragma Assert (Extract (T_1, Query) = "sure&really"); pragma Assert (Extract (T_1, Fragment) = "hell"); pragma Assert (Extract (T_2, Scheme) = "urn"); pragma Assert (Extract (T_2, Authority) = ""); pragma Assert (Extract (T_2, Path) = "example:animal:ferret:nose"); pragma Assert (Extract (T_2, Query) = ""); pragma Assert (Extract (T_2, Fragment) = ""); -- Bizarre individual parts pragma Assert (Extract ("git+http:", Scheme) = "git+http"); pragma Assert (Extract ("http::nowhere", Scheme) = "http"); pragma Assert (Extract ("http::nowhere", Path) = ":nowhere"); pragma Assert (Extract ("///auth", Authority) = ""); pragma Assert (Extract ("///auth", Path) = "/auth"); pragma Assert (Extract ("//+auth", Authority) = "+auth"); pragma Assert (Extract ("//?auth", Authority) = ""); pragma Assert (Extract ("//#auth", Authority) = ""); pragma Assert (Extract ("//../uh/oh", Authority) = ".."); pragma Assert (Extract ("//?", Path) = ""); pragma Assert (Extract ("///+asdf?", Path) = "/+asdf"); pragma Assert (Extract ("//../uh/oh", Path) = "/uh/oh"); pragma Assert (Extract ("??", Query) = "?"); pragma Assert (Extract ("?#", Query) = ""); pragma Assert (Extract ("??&#?", Query) = "?&"); pragma Assert (Extract ("?&#?", Query) = "&"); pragma Assert (Extract ("??&#?", Fragment) = "?"); pragma Assert (Extract ("#", Fragment) = ""); pragma Assert (Extract ("##", Fragment) = "#"); -- Counterintuitive Authority/Path combos pragma Assert (Extract ("file://hello.txt", Authority) = "hello.txt"); pragma Assert (Extract ("file://hello.txt", Path) = ""); pragma Assert (Permissive_Path ("file://hello.txt") = "hello.txt"); pragma Assert (Extract ("file:///hello.txt", Authority) = ""); pragma Assert (Extract ("file:///hello.txt", Path) = "/hello.txt"); pragma Assert (Permissive_Path ("file:///hello.txt") = "/hello.txt"); pragma Assert (Extract ("file:../hello.txt", Authority) = ""); pragma Assert (Extract ("file:../hello.txt", Path) = "../hello.txt"); pragma Assert (Permissive_Path ("file:../hello.txt") = "../hello.txt"); pragma Assert (Extract ("file://../hello.txt", Authority) = ".."); pragma Assert (Extract ("file://../hello.txt", Path) = "/hello.txt"); pragma Assert (Permissive_Path ("file://../hello.txt") = "../hello.txt"); pragma Assert (Extract ("file:/hello.txt", Authority) = ""); pragma Assert (Extract ("file:/hello.txt", Path) = "/hello.txt"); pragma Assert (Permissive_Path ("file:/hello.txt") = "/hello.txt"); -- Slices pragma Assert (Extract ("file:///path/to", Scheme, Path) = "file:/path/to"); pragma Assert (Extract ("file:///path/to", Authority, Authority) = ""); pragma Assert (Extract (T_1, Scheme, Fragment) = T_1); pragma Assert (Extract (T_1, Authority, Query) = "anon:1234@www.dummy.com/highway/to/?sure&really"); pragma Assert (Extract (T_1, Path, Query) = "/highway/to/?sure&really"); pragma Assert (Extract (T_1, Scheme, Authority) = "http://anon:1234@www.dummy.com"); pragma Assert (Extract (T_1, Authority, Path) = "anon:1234@www.dummy.com/highway/to/"); pragma Assert (Extract (T_2, Scheme, Fragment) = T_2); pragma Assert (Extract (T_2, Authority, Query) = "example:animal:ferret:nose"); pragma Assert (Extract (T_2, Path, Query) = "example:animal:ferret:nose"); pragma Assert (Extract (T_2, Scheme, Authority) = "urn"); pragma Assert (Extract (T_2, Scheme, Path) = T_2); pragma Assert (Extract (T_2, Authority, Path) = "example:animal:ferret:nose"); end URI.Test; alire-1.2.1/deps/uri-ada/src/uri.adb000066400000000000000000000050461402735052500171320ustar00rootroot00000000000000with Ada.Containers.Indefinite_Ordered_Maps; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with GNAT.Regpat; package body URI is package Part_Maps is new Ada.Containers.Indefinite_Ordered_Maps (Parts, String); subtype Part_Map is Part_Maps.Map; ----------- -- Crack -- ----------- -- ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? -- 12 3 4 5 6 7 8 9 -- -- scheme = $2 -- authority = $4 -- path = $5 -- query = $7 -- fragment = $9 function Crack (This : String) return Part_Map is use GNAT.Regpat; Cracker : constant Pattern_Matcher := Compile ("^\s*(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#([^\s]*))?", Case_Insensitive + Single_Line); Matches : Match_Array (0 .. 9) := (others => No_Match); function Part (I : Positive) return String is (if Matches (I) /= No_Match then This (Matches (I).First .. Matches (I).Last) else ""); begin Match (Cracker, This, Matches); return Map : Part_Map do Map.Insert (Scheme, Part (2)); Map.Insert (Authority, Part (4)); Map.Insert (Path, Part (5)); Map.Insert (Query, Part (7)); Map.Insert (Fragment, Part (9)); end return; end Crack; ------------- -- Extract -- ------------- function Extract (This : String; Part : Parts) return String is (Extract (This, First => Part, Last => Part)); ------------- -- Extract -- ------------- function Extract (This : String; First, Last : Parts) return String is Slice : Unbounded_String; Parts : constant Part_Map := Crack (This); begin for I in First .. Last loop if Parts.Contains (I) then -- prefixes if I /= First and then Parts (I) /= "" and then Slice /= "" then case I is when Scheme => null; when Authority => Append (Slice, "//"); when Path => null; when Query => Append (Slice, "?"); when Fragment => Append (Slice, "#"); end case; end if; Append (Slice, Parts (I)); -- postfixes if I = Scheme and then Parts (I) /= "" and then Extract (This, Authority, Last) /= "" then Append (Slice, ":"); end if; end if; end loop; return To_String (Slice); end Extract; end URI; alire-1.2.1/deps/uri-ada/src/uri.ads000066400000000000000000000052311402735052500171470ustar00rootroot00000000000000package URI with Preelaborate is -- Helper functions to identify URLs and their components. -- -- See https://tools.ietf.org/html/rfc3986 for full details. -- -- http://user:pass@www.here.com:80/dir1/dir2/xyz.html?p=8&x=doh#anchor -- | | | | | | | -- protocol host port path file parameters fragment -- -- foo://example.com:8042/over/there?name=ferret#nose -- \_/ \______________/\_________/ \_________/ \__/ -- | | | | | -- scheme authority path query fragment -- | _____________________|__ -- / \ / \ -- urn:example:animal:ferret:nose type Parts is (Scheme, Authority, Path, Query, Fragment); --------------- -- Low level -- --------------- -- The following functions will return "" for any part not recognized. Note -- that no part is mandatory, so any "malformed" URI will be recognized as -- a mere Path. function Extract (This : String; Part : Parts) return String; -- Return a specific part of the URL, or "" if not present function Extract (This : String; First, Last : Parts) return String; -- Return a slice of parts, or "" if none exist in the slice. Note that -- appropriate separators will be included between parts: ":" after -- existing scheme, "//" if authority exists, "?" if query exists, "#" if -- fragment exists. Note that separators will not be included before First -- nor after Last parts. Note that Scheme .. Path of "file:///path/to" will -- return "file:/path/to" because authority is empty. -- -- NOTES on "file:" URIs. Since the Authority only ends when a third '/' is -- found, the following URIs may have unexpected interpretations (but these -- are the correct ones!): -- -- file://hello.txt => authority: hello.txt, path: "" -- file:///hello.txt => authority: "", path: /hello.txt -- file:../relative => authority: "", path: ../relative -- file://../relative => authority: "..", path: /relative -- file:/absolute => authority: "", path: /absolute -- -- TL;DR: to ensure proper interpretation of malformed file: URLs, take -- both the slice Authority .. Path as a whole to be the complete path. -- Or use Permissive_Path below. ---------------- -- High level -- ---------------- function Scheme (This : String) return String is (Extract (This, Scheme)); function Permissive_Path (This : String) return String is (Extract (This, Authority, Path)); end URI; alire-1.2.1/deps/uri-ada/uri.gpr000066400000000000000000000024761402735052500164110ustar00rootroot00000000000000project URI is for Create_Missing_Dirs use "True"; for Source_Dirs use ("src"); for Exec_Dir use "bin"; type Build_Modes is ("On_Demand", "Static_Lib", "Shared_Lib"); Build_Mode : Build_Modes := External ("URI_BUILD_MODE", "On_Demand"); case Build_Mode is when "On_Demand" => for Main use ("uri-test.adb" ); for Object_Dir use "obj"; when "Static_Lib" => for Library_Kind use "static-pic"; for Library_Name use "uriada"; for Library_Dir use "lib"; for Object_Dir use "obj/static"; when "Shared_Lib" => for Library_Kind use "dynamic"; for Library_Name use "uriada"; for Library_Dir use "lib"; for Object_Dir use "obj/shared"; end case; package Builder is for Switches ("ada") use ("-s", "-m", "-j0", "-g"); end Builder; package Compiler is for Switches ("ada") use ("-gnatVa", "-gnatwa", "-g", "-O2", "-gnato", "-fstack-check", "-gnata"); end Compiler; package Binder is for Switches ("ada") use ("-Es"); end Binder; package Ide is for Vcs_Kind use "Git"; end Ide; package Linker is for Switches ("ada") use ("-g"); end Linker; end URI; pax_global_header00006660000000000000000000000064133074763140014522gustar00rootroot0000000000000052 comment=1fcbd0b9303d044d8f09a8ef652afa8c0400ee8b alire-1.2.1/deps/xmlezout/000077500000000000000000000000001330747631400154415ustar00rootroot00000000000000alire-1.2.1/deps/xmlezout/.gitignore000066400000000000000000000000421330747631400174250ustar00rootroot00000000000000*.ali *cswi *.o *.stderr *.stdout alire-1.2.1/deps/xmlezout/README000066400000000000000000000157211330747631400163270ustar00rootroot00000000000000XML EZ_Out Version 1.06 ============ XML EZ_Out is a small set of packages intended to aid the creation of XML-formatted output from within Ada programs. It basically wraps the tags and data provided to it with XML syntax and writes them to a user-supplied medium. This medium can be any sort of writable entity, such as a file, a memory buffer, or even a communications link, such as a socket. The only functionality required of the medium is that it supply a meaningful "Put" (for writing a string) and "New_Line" procedure. Usage ===== IMPORTANT!! XML EZ_Out package instantiations are explicitly designed to be made directly visible with the aid of a "use" clause! Declining to use a "use" will make using EZ_Out inordinately verbose and awkward to use. So use "use", and get a waiver from your programming standard if you have to! The key facilitator of making XML EZ_Out usage readable when generating XML documentation is the overloading of a number of variations of the "=" function. By doing this, a simple XML element having no content, such as: can be generated as: Output_Tag(F, "player", ("lastName" = "Cuddyer", "firstName" = "Michael", "team" = "Twins")); To simplify the specification of the attributes, variations of "=" are provided. Given these declarations: Batting_Average : Float; At_Bats : Natural; One can directly reference the variables: Output_Tag(F, "stats", ("battingAvg" = Batting_Average, "atBats" = At_Bats)); Elements that contain a number of nested sub-elements begin with a Start_Element call and are terminated with an End_Element invocation. Attribute/value pairs can be specified in the Start_Element call, which is then followed by calls to Output_Tag, more Start_Element/End_Element calls, and an Output_Content for any data that makes up the textual body of the element. The only functions that you really need to know to use XML EZ_Out are: Output_XML_Header Output_Processing_Instruction Output_Element Output_Tag Start_Element End_Element Output_Content The "use" of the instantiated package will take of the rest. For an example set of intantiations and usages of the file and buffering capabilities of XML EZ_Out, see the tmeztf.adb program. The generic specification for EZ_Out is: generic type Output_Medium is limited private; with procedure Put(F : in Output_Medium; S : in String) is <>; with procedure New_Line (F : in Output_Medium; Spacing : in Ada.Text_IO.Positive_Count := 1) is <>; -- DEPRECATED -- Control formatting by setting the Current_Format variable in the -- package spec. -- -- Specify whether the XML that is created is to have indenting and -- line breaks. Format : Formatting_Options := Spread_Indented; -- DEPRECATED -- The maximum element nesting depth of an XML document Max_Element_Nesting : Positive := 200; package McKae.XML.EZ_Out.Generic_Medium; Output_Medium is whatever entity is going to received the formatted XML output. As mentioned previously, it can be a file, a stream, a buffer, a socket, whatever. All interaction with it takes place solely through the supplied Put and New_Line procedures, which are obviously modeled after the Ada.Text_IO versions. The Format parameter is now deprecated. Its functionality is now provided by the Current_Format variable in the package specification. The value for the generic Format parameter is now simply used as the inital setting for Current_Format. Format may be removed in some future release. Format, or better yet, its replacement, Current_Format, can be set to either Continuous_Stream or Spread_Indented. Continuous_Stream simply produces a continuous stream of XML content, with no indentation or line breaks. This mode reduces bandwidth and storage requirements, at the cost of not being the easiest to read in its raw form. Spread_Indented provides a more human-readable arrangement of the content. Max_Element_Nesting is used to set the size of an internal stack that keeps track of the start and end tags of the document under construction. Documents probably aren't going to exceed the default 200-level nesting very often, but if that happens, simply increase it. To see the exceptions that can be raised by misusing XML EZ_Out, check the definitions in McKae.XML.EZ_Out. Auxiliary Packages ================== Two auxiliary packages are provided with this distribution: McKae.XML.EZ_Out.Text_File, and McKae.XML.EZ_Out.String_Stream. Text_File is simply an instantiation of the core Generic_Medium package with Ada.Text_IO.File_Type, providing a ready-to-go package for writing XML to ordinary text files. String_Stream uses an in-memory buffer to hold the generated XML text, with a Get_String function for retrieving the entire generated document as a string with one call. Caveats ======= Be aware that XML EZ_Out does no validation of the XML content it is being asked to output, and it is possible to generate malformed documents. That includes the handling of character encoding. While XML_EZ_Out will claim the document is "UTF-8" or otherwise as set by the application, it is up to the application to ensure that correct content is provided in the strings that are passed to its various subprograms. Used appropriately, though, it can provide a clear and readable means to aid the dynamic generation of XML content by Ada programs. Revision History ================ Changes since 1.05: o Fixed bug where calling Output_Content with a negative integer or float argument would drop the leading minus sign o Added ability to completely deallocate memory used by the String_Stream package. [Patch provided by Xavier Grave.] Changes since 1.04: o Deprecated the Format generic parameter, replacing it with a Current_Format variable in the package specification. o Added a package variable Default_Output_Null_Attributes. If True, attributes whose value is an empty string will be output with that empty string as the attribute's value. If False (which is the default), output of the attribute is omitted. [Requested by Niklas Holsti.] Changes since 1.03: o Added quote and apostrophe substitution (""" and '") within attribute values. Changes since 1.02: o Corrected bug in "&" for "&" substition. Changes since 1.01: o Added attribute specification functions ("=") for single character values. Changes since 1.00: o Fixed problem with attributes being given negative numeric values. The minus sign was being dropped. o If an attribute value is an empty string ("") or Null_Unbounded_String, then generation of that attribute specification is skipped. ================== Marc A. Criley McKae Technologies www.mckae.com Last updated: 23 Sep 2006 alire-1.2.1/deps/xmlezout/mckae-xml-ez_out-generic_medium.adb000066400000000000000000000574561330747631400242650ustar00rootroot00000000000000------------------------------------------------------------------------ -- -- -- McKae Software Utilities -- -- -- -- Copyright (C) 2005-2009 McKae Technologies -- -- -- -- The McKae software utilities are free software; you can -- -- redistribute it and/or modify it under terms of the GNU General -- -- Public License as published by the Free Software Foundation; -- -- either version 2, or (at your option) any later version. McKae -- -- Software Utilities are distributed in the hope that they 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. You should -- -- have received a copy of the GNU General Public License distributed -- -- with DTraq; see file COPYING. If not, write to the Free Software -- -- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -- -- USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- -- -- -- The McKae Software Utilities are maintained by McKae Technologies -- -- (http://www.mckae.com). -- ------------------------------------------------------------------------ with Ada.Strings.Fixed; use Ada.Strings.Fixed; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package body McKae.XML.EZ_Out.Generic_Medium is ------------------------------------------------------------------------ -- A very basic bounded stack implementation for keeping track of -- nested XML elements. type Stack_Size is new Natural range 0 .. Max_Element_Nesting; subtype Stack_Indices is Stack_Size range 1 .. Stack_Size'Last; type Element_Stacks is array (Stack_Indices) of Unbounded_String; Tag_Stack : Element_Stacks; Top_Of_Stack : Stack_Size := 0; procedure Push(Tag : Unbounded_String) is begin if Top_Of_Stack /= Stack_Size'Last then Top_Of_Stack := Top_Of_Stack + 1; Tag_Stack(Top_Of_Stack) := Tag; else raise Nesting_Too_Deep; end if; end Push; procedure Pop(Tag : out Unbounded_String) is begin if Top_Of_Stack /= 0 then Tag := Tag_Stack(Top_Of_Stack); Top_Of_Stack := Top_Of_Stack - 1; else raise Element_Not_Open; end if; end Pop; ------------------------------------------------------------------------ type XML_Component_Kind is (Header_Component, Start_Tag_Component, Content_Component, End_Tag_Component); Tab_Size : constant Natural := 3; ------------------------------------------------------------------------ -- Constructed Put_Line from provided primitives procedure Put_Line(F : in Output_Medium; S : in String) is begin Put(F, S); New_Line(F); end Put_Line; ------------------------------------------------------------------------ procedure Replace_Special (C : in String; R : in String; S : in out Unbounded_String) is P : Natural := 0; begin if Index(R, C) /= 0 then -- The string to be replaced is present within the replacing -- string (e.g., "&" by "&"), so the replacement has to -- take this into account. P := 1; while (P + C'Length - 1) <= Length(S) loop if Slice(S, P, P + C'Length - 1) = C then Replace_Slice(S, P, P + C'Length - 1, R); P := P + R'Length; -- Skip over replacement string else P := P + 1; end if; end loop; else -- The string to be replaced is not present within the -- replacing string, so a simple find and replace can be -- done. loop P := Index(S, C); exit when P = 0; Replace_Slice(S, P, P + C'Length - 1, R); end loop; end if; end Replace_Special; ------------------------------------------------------------------------ function Replace_Specials (S : Unbounded_String; Subst : Boolean; Replace_Quotes : Boolean := False; Replace_Apos : Boolean := False) return Unbounded_String is New_S : Unbounded_String := S; begin if Subst then -- Ampersands must be replaced first, since the replacement -- strings contain ampersands Replace_Special("&", "&", New_S); Replace_Special("<", "<", New_S); Replace_Special("]]>", "]]>", New_S); if Replace_Quotes then Replace_Special("""", """, New_S); end if; if Replace_Apos then Replace_Special("'", "'", New_S); end if; end if; return New_S; end Replace_Specials; ------------------------------------------------------------------------ -- Output the string in accordance with the specified format option. procedure Formatted_Put(F : in Output_Medium; S : in Unbounded_String; K : in XML_Component_Kind) is -- The number of items in the element nesting stack is directly -- proportional to the amount of required indenting Indentation : constant Natural := Natural(Top_Of_Stack) * 3; Value : constant String := To_String(S); begin case K is when Header_Component => pragma Assert(Top_Of_Stack = 0); case Current_Format is when Continuous_Stream => Put(F, Value); when Spread_Indented => Put_Line(F, Value); end case; when Start_Tag_Component => case Current_Format is when Continuous_Stream => Put(F, value); when Spread_Indented => Put(F, Indentation * ' '); Put_Line(F, value); end case; when Content_Component => case Current_Format is when Continuous_Stream => Put(F, value); when Spread_Indented => Put(F, Indentation * ' '); Put_Line(F, value); end case; when End_Tag_Component => case Current_Format is when Continuous_Stream => Put(F, value); when Spread_Indented => Put(F, Indentation * ' '); Put_Line(F, value); end case; end case; end Formatted_Put; ------------------------------------------------------------------------ -- Output a standard XML header line, as amended by the supplied -- arguments. To omit the attribute, pass an empty string. -- procedure Output_XML_Header (F : in Output_Medium; Standalone : in Standalone_Values := Omit; Encoding : in String := "UTF-8"; Version : in String := "1.0") is Header : Unbounded_String := To_Unbounded_String(""); Formatted_Put(F, Header, Header_Component); else raise Invalid_Construction; end if; end Output_XML_Header; ------------------------------------------------------------------------ -- Add a processing instruction to the XML document. procedure Output_Processing_Instruction (F : in Output_Medium; Target : in String; Data : in String) is begin if Top_Of_Stack = 0 then Formatted_Put(F, To_Unbounded_String(""), Header_Component); else raise Invalid_Construction; end if; end Output_Processing_Instruction; ------------------------------------------------------------------------ -- Generate an entire element designated with the given tag and -- containing the provided content and list of attributes procedure Output_Element (F : in Output_Medium; Tag : in String; Content : in String; Attrs : in Attributes_List := No_Attributes; Subst : in Boolean := True) is Tag_Start : Unbounded_String := "<" & To_Unbounded_String(Tag); Tag_End : Unbounded_String := ""; begin if Attrs /= No_Attributes then for A in Attrs'Range loop if (Attrs (A).Value /= Null_Unbounded_String) or Default_Output_Null_Attributes then Append(Tag_Start, " " & Attrs(A).Attr & "=""" & Replace_Specials(Attrs(A).Value, Subst, Replace_Quotes => True, Replace_Apos => True) & """"); end if; end loop; end if; Append(Tag_Start, ">"); Formatted_Put(F, Tag_Start, Start_Tag_Component); Formatted_Put(F, Replace_Specials(To_Unbounded_String(Content), Subst), Content_Component); Formatted_Put(F, Tag_End, End_Tag_Component); end Output_Element; ------------------------------------------------------------------------ -- Generate an entire element designated with the given tag and -- containing the provided content single attribute specification procedure Output_Element (F : in Output_Medium; Tag : in String; Content : in String; Attrs : in Attribute_Value_Pairs; Subst : in Boolean := True) is begin Output_Element(F, Tag, Content, Attributes_List'(1 => Attrs), Subst); end Output_Element; ------------------------------------------------------------------------ -- Generate an entire element designated with the given tag and -- containing zero or more attributes. By default the element is -- created using the compact, no-end-tag notation; to force -- generation of an element that has both start and end tags and -- no content, set End_Tag to True. procedure Output_Tag (F : in Output_Medium; Tag : in String; Attrs : in Attributes_List := No_Attributes; End_Tag : in Boolean := False; Subst : in Boolean := True) is Tag_Start : Unbounded_String := "<" & To_Unbounded_String(Tag); Tag_End : Unbounded_String := ""; begin if Attrs /= No_Attributes then for A in Attrs'Range loop if (Attrs (A).Value /= Null_Unbounded_String) or Default_Output_Null_Attributes then Append(Tag_Start, " " & Attrs(A).Attr & "=""" & Replace_Specials(Attrs(A).Value, Subst, Replace_Quotes => True, Replace_Apos => True) & """"); end if; end loop; end if; if End_Tag then Append(Tag_Start, ">"); Formatted_Put(F, Tag_Start, Start_Tag_Component); Formatted_Put(F, Tag_End, End_Tag_Component); else Append(Tag_Start, "/>"); Formatted_Put(F, Tag_Start, Start_Tag_Component); end if; end Output_Tag; ------------------------------------------------------------------------ -- Generate an element tag with a single attribute specElementification. -- By default the element is created using the compact, no-end-tag -- notation; to force generation of an element that has both start -- and end tags and no content, set End_Tag to True. procedure Output_Tag (F : in Output_Medium; Tag : in String; Attrs : in Attribute_Value_Pairs; End_Tag : in Boolean := False; Subst : in Boolean := True) is begin Output_Tag(F, Tag, Attributes_List'(1 => Attrs), End_Tag, Subst); end Output_Tag; ------------------------------------------------------------------------ -- Initiate the generation of an XML element with the given tag and -- zero or more attribute specifications using an Attributes_List -- initializing aggregate. If there is only one attribute to be -- specified, the single attribute version of Start_Element may be -- used instead so as to avoid having to use named notation to -- specify the single element of the list. procedure Start_Element (F : in Output_Medium; Tag : in String; Attrs : in Attributes_List := No_Attributes; Subst : in Boolean := True) is Tag_Start : Unbounded_String := "<" & To_Unbounded_String(Tag); begin -- First output the tag and any attributes. if Attrs /= No_Attributes then for A in Attrs'Range loop if (Attrs (A).Value /= Null_Unbounded_String) or Default_Output_Null_Attributes then Append(Tag_Start, " " & Attrs(A).Attr & "=""" & Replace_Specials(Attrs(A).Value, Subst, Replace_Quotes => True, Replace_Apos => True) & """"); end if; end loop; end if; Append(Tag_Start, ">"); Formatted_Put(F, Tag_Start, Start_Tag_Component); Push(To_Unbounded_String(Tag)); end Start_Element; ------------------------------------------------------------------------ -- Initiate the generation of an XML element with the given tag and -- a single attribute specification. procedure Start_Element (F : in Output_Medium; Tag : in String; Attrs : in Attribute_Value_Pairs; Subst : in Boolean := True) is begin Start_Element(F, Tag, Attributes_List'(1 => Attrs), Subst); end Start_Element; ------------------------------------------------------------------------ -- Indicate the completion of the output of an XML element. If a -- Tag is specified, compare it against the element tag that is -- currently open, and raise Element_End_Mismatch if the two do -- not match. If there is no open element, then raise -- Element_Not_Open. procedure End_Element (F : in Output_Medium; Tag : in String := "") is Open_Tag : Unbounded_String; begin Pop(Open_Tag); -- Validate the tag only if one was supplied if (Tag = "") or else (Tag = To_String(Open_Tag)) then Formatted_Put(F, "", End_Tag_Component); else raise Element_End_Mismatch; end if; end End_Element; ------------------------------------------------------------------------ -- Place the text, as is, as the content of the currently open XML -- element. Output_Content can be called repeatedly, and will -- simply continue to append the additional content. If there is -- no open element, raise Element_Not_Open. procedure Output_Content (F : in Output_Medium; S : in String; Subst : in Boolean := True) is begin Formatted_Put(F, Replace_Specials(To_Unbounded_String(S), Subst), Content_Component); end Output_Content; ------------------------------------------------------------------------ -- Place the numeric value, as a base 10 text representation, as -- the content of the currently open XML element. Output_Content -- can be called repeatedly, and will simply continue to append -- the additional content. If there is no open element, raise -- Element_Not_Open. procedure Output_Content(F : in Output_Medium; N : in Integer'Base) is N_Rep : constant String := Integer'Base'Image(N); Start_Index : constant Positive := Boolean'Pos(N >= 0) + 1; begin Output_Content(F, N_Rep(Start_Index .. N_Rep'Length)); end Output_Content; ------------------------------------------------------------------------ -- Place the text represenatation of the numeric value as the -- content of the currently open XML element. Output_Content can -- be called repeatedly, and will simply continue to append the -- additional content. If there is no open element, raise -- Element_Not_Open. procedure Output_Content(F : in Output_Medium; N : in Float'Base) is N_Rep : constant String := Float'Base'Image(N); Start_Index : constant Positive := Boolean'Pos(N >= 0.0) + 1; begin Output_Content(F, N_Rep(Start_Index .. N_Rep'Length)); end Output_Content; ------------------------------------------------------------------------ -- The following overloaded "=" functions are the only means by -- which to create attribute/value pairs. -- Attribute provided as String -- Associate an attribute with a string value. function "="(Attr : String; Value : String) return Attribute_Value_Pairs is begin return To_Unbounded_String(Attr) = To_Unbounded_String(Value); end "="; -- Associate an attribute with a string value. function "="(Attr : String; Value : Character) return Attribute_Value_Pairs is begin return To_Unbounded_String(Attr) = To_Unbounded_String((1 => Value)); end "="; -- Associate an attribute with a string value. function "="(Attr : String; Value : Unbounded_String) return Attribute_Value_Pairs is begin return To_Unbounded_String(Attr) = Value; end "="; -- Associate an attribute with an integral value. function "="(Attr : String; Value : Integer'Base) return Attribute_Value_Pairs is Value_Rep : constant String := Integer'Base'Image(Value); Is_Natural : constant Boolean := Value >= 0; begin if Is_Natural then return Attr = Value_Rep(2 .. Value_Rep'Last); else return Attr = Value_Rep; end if; end "="; -- Associate an attribute with a floating point value. function "="(Attr : String; Value : Float'Base) return Attribute_Value_Pairs is Value_Rep : constant String := Float'Base'Image(Value); Is_Nonnegative : constant Boolean := Value >= 0.0; begin if Is_Nonnegative then return Attr = Value_Rep(2 .. Value_Rep'Last); else return Attr = Value_Rep; end if; end "="; -- Associate an attribute with a floating point value. function "="(Attr : String; Value : Long_Float'Base) return Attribute_Value_Pairs is Value_Rep : constant String := Long_Float'Base'Image(Value); Is_Nonnegative : constant Boolean := Value >= 0.0; begin if Is_Nonnegative then return Attr = Value_Rep(2 .. Value_Rep'Last); else return Attr = Value_Rep; end if; end "="; -- Attribute provided as Unbounded_String -- Associate an attribute with a string value. function "="(Attr : Unbounded_String; Value : String) return Attribute_Value_Pairs is begin return Attr = To_Unbounded_String(Value); end "="; -- Associate an attribute with a string value. function "="(Attr : Unbounded_String; Value : Character) return Attribute_Value_Pairs is begin return Attr = To_Unbounded_String((1 => Value)); end "="; -- Associate an attribute with a string value. function "="(Attr : Unbounded_String; Value : Unbounded_String) return Attribute_Value_Pairs is begin return (Attr, Value); end "="; -- Associate an attribute with an integral value. function "="(Attr : Unbounded_String; Value : Integer'Base) return Attribute_Value_Pairs is Value_Rep : constant String := Integer'Base'Image(Value); Is_Natural : constant Boolean := Value >= 0; begin if Is_Natural then return Attr = To_Unbounded_String(Value_Rep(2 .. Value_Rep'Last)); else return Attr = To_Unbounded_String(Value_Rep); end if; end "="; -- Associate an attribute with a floating point value. function "="(Attr : Unbounded_String; Value : Float'Base) return Attribute_Value_Pairs is Value_Rep : constant String := Float'Base'Image(Value); Is_Nonnegative : constant Boolean := Value >= 0.0; begin if Is_Nonnegative then return Attr = To_Unbounded_String(Value_Rep(2 .. Value_Rep'Last)); else return Attr = To_Unbounded_String(Value_Rep); end if; end "="; -- Associate an attribute with a floating point value. function "="(Attr : Unbounded_String; Value : Long_Float'Base) return Attribute_Value_Pairs is Value_Rep : constant String := Long_Float'Base'Image(Value); Is_Nonnegative : constant Boolean := Value >= 0.0; begin if Is_Nonnegative then return Attr = To_Unbounded_String(Value_Rep(2 .. Value_Rep'Last)); else return Attr = To_Unbounded_String(Value_Rep); end if; end "="; end McKae.XML.EZ_Out.Generic_Medium; alire-1.2.1/deps/xmlezout/mckae-xml-ez_out-generic_medium.ads000066400000000000000000000312611330747631400242700ustar00rootroot00000000000000------------------------------------------------------------------------ -- -- -- McKae Software Utilities -- -- -- -- Copyright (C) 2005 McKae Technologies -- -- -- -- The McKae software utilities are free software; you can -- -- redistribute it and/or modify it under terms of the GNU General -- -- Public License as published by the Free Software Foundation; -- -- either version 2, or (at your option) any later version. McKae -- -- Software Utilities are distributed in the hope that they 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. You should -- -- have received a copy of the GNU General Public License distributed -- -- with DTraq; see file COPYING. If not, write to the Free Software -- -- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -- -- USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- -- -- -- The McKae Software Utilities are maintained by McKae Technologies -- -- (http://www.mckae.com). -- ------------------------------------------------------------------------ with Ada.Text_IO; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; generic type Output_Medium is limited private; with procedure Put(F : in Output_Medium; S : in String) is <>; with procedure New_Line (F : in Output_Medium; Spacing : in Ada.Text_IO.Positive_Count := 1) is <>; -- DEPRECATED -- Control formatting by setting the Current_Format variable in the -- package spec. -- -- Specify whether the XML that is created is to have indenting and -- line breaks. Format : Formatting_Options := Spread_Indented; -- DEPRECATED -- The maximum element nesting depth of an XML document Max_Element_Nesting : Positive := 200; package McKae.XML.EZ_Out.Generic_Medium is ------------------------------------------------------------------- -- This package provides the means to easily write XML elements and -- associated attributes to a provided medium that provides the -- required interface. -- Note that this package is designed in such a way that -- instantiations of it are meant to be "used" by the application. -- When accompanied with a "use" clause, specifying the XML to be -- produced is very simple and clear. Insisting on using qualified -- names will make for very obtuse code. Likewise, "named -- parameter" notation would obscure the complementarity of the Ada -- and XML, so apply for a waiver from any such style standards. ------------------------------------------------------------------- -- The medium must be open and ready to accept content before -- invoking any of these XML output subprograms. -- If the medium raises any exceptions as a result of invoking the -- supplied Put or New_Line procedures, those exceptions will be -- passed through to the caller. ------------------------------------------------------------------- -- The identation format of the XML that is output. This can be -- altered at any time. Current_Format : Formatting_Options := Format; -- Whether to output an attribute if it has a null value. Default_Output_Null_Attributes : Boolean := False; ------------------------------------------------------------------- -- These procedures for outputting XML header elements cannot be -- invoked when there are any nested elements opening, i.e., -- Start_Element has been called. Doing so will result in the -- raising of an Invalid_Construction exception. -- Settings for the document header's standalone attribute. type Standalone_Values is (Yes, No, Omit); -- Output a standard XML header line, as amended by the supplied -- arguments. To omit the attribute, pass an empty string. -- procedure Output_XML_Header (F : in Output_Medium; Standalone : in Standalone_Values := Omit; Encoding : in String := "UTF-8"; Version : in String := "1.0"); -- Add a processing instruction to the XML document. procedure Output_Processing_Instruction (F : in Output_Medium; Target : in String; Data : in String); ------------------------------------------------------------------- -- Representation of attribute/value pairs type Attribute_Value_Pairs is private; -- List of attributes and corresponding values to associated with -- an element type Attributes_List is array(Natural range <>) of Attribute_Value_Pairs; -- Indicator that the element has no associated attributes No_Attributes : constant Attributes_List; -- Generate an entire element designated with the given tag and -- containing the provided content and list of attributes procedure Output_Element (F : in Output_Medium; Tag : in String; Content : in String; Attrs : in Attributes_List := No_Attributes; Subst : in Boolean := True); -- Generate an entire element designated with the given tag and -- containing the provided content single attribute specification procedure Output_Element (F : in Output_Medium; Tag : in String; Content : in String; Attrs : in Attribute_Value_Pairs; Subst : in Boolean := True); -- Generate an element tag containing zero or more attributes. By -- default the element is created using the compact, no-end-tag -- notation; to force generation of an element that has both start -- and end tags and no content, set End_Tag to True. procedure Output_Tag (F : in Output_Medium; Tag : in String; Attrs : in Attributes_List := No_Attributes; End_Tag : in Boolean := False; Subst : in Boolean := True); -- Generate an element tag with a single attribute specification. -- By default the element is created using the compact, no-end-tag -- notation; to force generation of an element that has both start -- and end tags and no content, set End_Tag to True. procedure Output_Tag (F : in Output_Medium; Tag : in String; Attrs : in Attribute_Value_Pairs; End_Tag : in Boolean := False; Subst : in Boolean := True); -- Initiate the generation of an XML element with the given tag and -- zero or more attribute specifications using an Attributes_List -- initializing aggregate. If there is only one attribute to be -- specified, the single attribute version of Start_Element may be -- used instead so as to avoid having to use named notation to -- specify the single element of the list. procedure Start_Element (F : in Output_Medium; Tag : in String; Attrs : in Attributes_List := No_Attributes; Subst : in Boolean := True); -- Initiate the generation of an XML element with the given tag and -- a single attribute specification. procedure Start_Element (F : in Output_Medium; Tag : in String; Attrs : in Attribute_Value_Pairs; Subst : in Boolean := True); -- Indicate the completion of the output of an XML element. If a -- Tag is specified, compare it against the element tag that is -- currently open, and raise Element_End_Mismatch if the two do -- not match. If there is no open element, then raise -- Element_Not_Open. procedure End_Element (F : in Output_Medium; Tag : in String := ""); -- Place the text, as is, as the content of the currently open XML -- element. Output_Content can be called repeatedly, and will -- simply continue to append the additional content. If there is -- no open element, raise Element_Not_Open. procedure Output_Content (F : in Output_Medium; S : in String; Subst : in Boolean := True); -- Place the numeric value, as a base 10 text representation, as -- the content of the currently open XML element. Output_Content -- can be called repeatedly, and will simply continue to append -- the additional content. If there is no open element, raise -- Element_Not_Open. procedure Output_Content(F : in Output_Medium; N : in Integer'Base); -- Place the text represenatation of the numeric value as the -- content of the currently open XML element. Output_Content can -- be called repeatedly, and will simply continue to append the -- additional content. If there is no open element, raise -- Element_Not_Open. procedure Output_Content(F : in Output_Medium; N : in Float'Base); -- The following overloaded "=" functions are the only means by -- which to create attribute/value pairs. -- Attribute provided as String -- Associate an attribute with a string value. function "="(Attr : String; Value : String) return Attribute_Value_Pairs; -- Associate an attribute with a character value. function "="(Attr : String; Value : Character) return Attribute_Value_Pairs; -- Associate an attribute with a string value. function "="(Attr : String; Value : Unbounded_String) return Attribute_Value_Pairs; -- Associate an attribute with an integral value. function "="(Attr : String; Value : Integer'Base) return Attribute_Value_Pairs; -- Associate an attribute with a floating point value. function "="(Attr : String; Value : Float'Base) return Attribute_Value_Pairs; -- Attribute provided as Unbounded_String -- Associate an attribute with a string value. function "="(Attr : Unbounded_String; Value : String) return Attribute_Value_Pairs; -- Associate an attribute with a character value. function "="(Attr : Unbounded_String; Value : Character) return Attribute_Value_Pairs; -- Associate an attribute with a string value. function "="(Attr : Unbounded_String; Value : Unbounded_String) return Attribute_Value_Pairs; -- Associate an attribute with an integral value. function "="(Attr : Unbounded_String; Value : Integer'Base) return Attribute_Value_Pairs; -- Associate an attribute with a floating point value. function "="(Attr : Unbounded_String; Value : Float'Base) return Attribute_Value_Pairs; private type Attribute_Value_Pairs is record Attr : Unbounded_String; Value : Unbounded_String; end record; No_Attributes : constant Attributes_List(1..0) := (others => (others => Null_Unbounded_String)); end McKae.XML.EZ_Out.Generic_Medium; alire-1.2.1/deps/xmlezout/mckae-xml-ez_out-string_stream.adb000066400000000000000000000113261330747631400241540ustar00rootroot00000000000000------------------------------------------------------------------------ -- -- -- McKae Software Utilities -- -- -- -- Copyright (C) 2005-2009 McKae Technologies -- -- -- -- The McKae software utilities are free software; you can -- -- redistribute it and/or modify it under terms of the GNU General -- -- Public License as published by the Free Software Foundation; -- -- either version 2, or (at your option) any later version. McKae -- -- Software Utilities are distributed in the hope that they 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. You should -- -- have received a copy of the GNU General Public License distributed -- -- with DTraq; see file COPYING. If not, write to the Free Software -- -- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -- -- USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- -- -- -- The McKae Software Utilities are maintained by McKae Technologies -- -- (http://www.mckae.com). -- ------------------------------------------------------------------------ with Mckae.XML.EZ_Out.Generic_Medium; with Ada.Strings.Fixed; with Ada.Text_IO; use Ada.Text_IO; with Unchecked_Deallocation; package body Mckae.XML.EZ_Out.String_Stream is package body String_Buffering is procedure Free is new Unchecked_Deallocation(String, Buffer_Ptr); -- A basic in-memory string buffering package for building XML -- documents with EZ_Out. This is not intended to be a robust, -- full-function memory buffering package. procedure Extend (F : in String_Buffer; To_Add : in Positive)is Temp_Buff : Buffer_Ptr := F.Buff; Size_Delta : Positive; Expansion_Factor : Positive; New_Size : Positive := F.Size + To_Add; begin if New_Size > F.Allocation then Size_Delta := New_Size - F.Allocation; Expansion_Factor := (Size_Delta / F.Expansion) + 1; F.Self.Sb.Allocation := F.Allocation + (Expansion_Factor * F.Expansion); F.Self.Sb.Buff := new String(1 .. F.Allocation); F.Self.Sb.Buff(1 .. F.Size) := Temp_Buff(1 .. F.Size); Free (Temp_Buff); end if; end Extend; -- Copy the given string into the buffer, expanding it if needed. procedure Put(F : in String_Buffer; S : in String) is begin if S'Length > 0 then Extend(F, S'Length); F.Buff(F.Size + 1 .. F.Size + S'Length) := S; F.Self.Sb.Size := F.Size + S'Length; end if; end Put; -- Insert a new line indicator into the buffer. procedure New_Line (F : in String_Buffer; Spacing : in Ada.Text_IO.Positive_Count := 1) is use Ada.Strings.Fixed; begin null; end New_Line; -- Clear the buffer procedure Clear(S : String_Buffer) is begin S.Self.Sb.Size := 0; end Clear; -- Free ressources in order to avoid memory leak procedure Full_Clear (S : in out String_Buffer) is begin Clear (S); Free (S.Buff); S.Buff := null; end Full_Clear; -- Return the current contents of the string buffer function Get_String(S : String_Buffer) return String is begin return S.Buff(1 .. S.Size); end Get_String; procedure Finalize (Object : in out String_Buffer) is begin Full_Clear (Object); end Finalize; end String_Buffering; end Mckae.XML.EZ_Out.String_Stream; alire-1.2.1/deps/xmlezout/mckae-xml-ez_out-string_stream.ads000066400000000000000000000175721330747631400242060ustar00rootroot00000000000000------------------------------------------------------------------------ -- -- -- McKae Software Utilities -- -- -- -- Copyright (C) 2005-2009 McKae Technologies -- -- -- -- The McKae software utilities are free software; you can -- -- redistribute it and/or modify it under terms of the GNU General -- -- Public License as published by the Free Software Foundation; -- -- either version 2, or (at your option) any later version. McKae -- -- Software Utilities are distributed in the hope that they 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. You should -- -- have received a copy of the GNU General Public License distributed -- -- with DTraq; see file COPYING. If not, write to the Free Software -- -- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -- -- USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- -- -- -- The McKae Software Utilities are maintained by McKae Technologies -- -- (http://www.mckae.com). -- ------------------------------------------------------------------------ with Ada.Finalization; with Ada.Text_IO; use Ada.Text_IO; with Mckae.XML.EZ_Out.Generic_Medium; package Mckae.XML.EZ_Out.String_Stream is -- A basic in-memory string-based XML document construction -- utility. This is not intended to be a robust, full-function -- memory buffering package. --------------------------------------------------------------------------- -- This nested package provides a basic string-based buffering -- capability. The purpose of the EZ_Out String_Stream package is -- to provide a simple means of constructing an XML document in a -- memory buffer. To do this, a memory buffering capability was -- needed--there were three approaches: -- -- o Locate and employ an existing memory buffering component, -- modifying it as needed to provide the required Put and New_Line -- functions -- o Write a McKae component to do memory buffering and reference -- it in this package. -- o Embed a memory buffering capability within the String_Stream -- package. -- -- The first option was discarded not because there's anything -- wrong with existing memory buffer components, but rather -- because of questions about which one should be chosen, what are -- its distribution and modification requirements, and so on. The -- truth of the matter is that this approach is what a project -- using EZ_Out for a project actually ought to do--take their -- memory buffering capability, enhance it with Put and New_Line -- functionality, and then instantiate EZ_Out.Generic_Medium with -- it. -- -- The second option was discarded because the focus of EZ_Out is -- on XML document generation, not providing a general purpose -- memory buffering component. While a limited capability one -- could have been created, it would be over-specific to EZ_Out -- and its (intentional) limitations would distract from its -- intended use as an EZ_Out adjunct package. -- -- This left the third option. By embedding the above-mentioned -- limited capability memory buffering capability within -- String_Stream, it's clearly associated as just an aspect of the -- String_Stream implementation, as any relevant capabilities -- are simply exported by the String_Stream package. package String_Buffering is -- There's little point in having a small buffer for building XML -- documents, so the minimum size and expansion is 500 characters. subtype Buffer_Size_Range is Positive range 500 .. Positive'Last; type String_Buffer (Initial_Size : Buffer_Size_Range := 5000; Expansion : Buffer_Size_Range := 5000) is limited private; -- Copy the given string into the buffer, expanding it if needed. procedure Put(F : in String_Buffer; S : in String); -- Insert a new line indicator into the buffer. However, in -- this case do nothing, since this buffering package is being -- instantiated for Continuous_Stream formatting. procedure New_Line (F : in String_Buffer; Spacing : in Ada.Text_IO.Positive_Count := 1); -- Clear the buffer. Note that this does not free any allocated -- resources. procedure Clear(S : String_Buffer); -- Free ressources in order to avoid memory leak procedure Full_Clear (S : in out String_Buffer); -- Return the current contents of the string buffer function Get_String(S : String_Buffer) return String; private -- Handle to the buffer type Buffer_Ptr is access all String; -- String buffer self-access ("Rosen Trick"); type String_Self_Access (SB : access String_Buffer) is limited null record; -- String buffer type definition. By default, a newly created -- string buffer is initialized to be empty. type String_Buffer (Initial_Size : Buffer_Size_Range := 5000; Expansion : Buffer_Size_Range := 5000) is new Ada.Finalization.Limited_Controlled with record Allocation : Buffer_Size_Range := Initial_Size; Size : Natural := 0; Buff : Buffer_Ptr := new String(1 .. Initial_Size); Self : String_Self_Access(String_Buffer'Access); end record; -- Release the string buffer's resources when the buffer goes -- out of scope procedure Finalize (Object : in out String_Buffer); end String_Buffering; --------------------------------------------------------------------------- subtype Buffer_Size_Range is String_Buffering.Buffer_Size_Range; subtype String_Buffer is String_Buffering.String_Buffer; -- Clear the buffer. Note that this does not free any allocated -- resources. procedure Clear(S : String_Buffer) renames String_Buffering.Clear; -- Free ressources in order to avoid memory leak procedure Full_Clear (S : in out String_Buffer) renames String_Buffering.Full_Clear; -- Return the current contents of the string buffer function Get_String(S : String_Buffer) return String renames String_Buffering.Get_String; --------------------------------------------------------------------------- -- "Use" this XML_String_Buffer package for constructing an EZ_Out -- XML document. package XML_String_Buffer is new Mckae.XML.EZ_Out.Generic_Medium (Output_Medium => String_Buffering.String_Buffer, Put => String_Buffering.Put, New_Line => String_Buffering.New_Line, Format => Continuous_Stream); --------------------------------------------------------------------------- end Mckae.XML.EZ_Out.String_Stream; alire-1.2.1/deps/xmlezout/mckae-xml-ez_out-text_file.ads000066400000000000000000000044771330747631400233100ustar00rootroot00000000000000------------------------------------------------------------------------ -- -- -- McKae Software Utilities -- -- -- -- Copyright (C) 2005 McKae Technologies -- -- -- -- The McKae software utilities are free software; you can -- -- redistribute it and/or modify it under terms of the GNU General -- -- Public License as published by the Free Software Foundation; -- -- either version 2, or (at your option) any later version. McKae -- -- Software Utilities are distributed in the hope that they 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. You should -- -- have received a copy of the GNU General Public License distributed -- -- with DTraq; see file COPYING. If not, write to the Free Software -- -- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -- -- USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- -- -- -- The McKae Software Utilities are maintained by McKae Technologies -- -- (http://www.mckae.com). -- ------------------------------------------------------------------------ with Mckae.XML.EZ_Out.Generic_Medium; with Ada.Text_IO; use Ada.Text_IO; package Mckae.XML.EZ_Out.Text_File is new Mckae.XML.EZ_Out.Generic_Medium (Output_Medium => Ada.Text_IO.File_Type); alire-1.2.1/deps/xmlezout/mckae-xml-ez_out.ads000066400000000000000000000063211330747631400213150ustar00rootroot00000000000000------------------------------------------------------------------------ -- -- -- McKae Software Utilities -- -- -- -- Copyright (C) 2005 McKae Technologies -- -- -- -- The McKae software utilities are free software; you can -- -- redistribute it and/or modify it under terms of the GNU General -- -- Public License as published by the Free Software Foundation; -- -- either version 2, or (at your option) any later version. McKae -- -- Software Utilities are distributed in the hope that they 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. You should -- -- have received a copy of the GNU General Public License distributed -- -- with DTraq; see file COPYING. If not, write to the Free Software -- -- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -- -- USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- -- -- -- The McKae Software Utilities are maintained by McKae Technologies -- -- (http://www.mckae.com). -- ------------------------------------------------------------------------ package McKae.XML.EZ_Out is -- This package is the parent package for a collection of packages -- that provide a simple means of XML output generation to a -- variety of output media. type Formatting_Options is (Continuous_Stream, -- No indenting, line breaks, or other -- extraneous whitespace. Spread_Indented -- Start and end tags are indented, and -- each resides on its own line. ); Element_Not_Open : exception; -- An attempt was made to end, or add content to, an element when -- there were no open elements awaiting text or completion. Element_End_Mismatch : exception; -- The specified end tag does not match that of the currently open -- element. Nesting_Too_Deep : exception; -- The number of open, nested elements has exceeded the maximum -- level that was specified. Invalid_Construction : exception; -- An attempt was made to create a malformed document, such as -- inserting a process instruction into an open element. end McKae.XML.EZ_Out; alire-1.2.1/deps/xmlezout/mckae-xml.ads000066400000000000000000000041741330747631400200160ustar00rootroot00000000000000------------------------------------------------------------------------ -- -- -- McKae Software Utilities -- -- -- -- Copyright (C) 2004 McKae Technologies -- -- -- -- The McKae software utilities are free software; you can -- -- redistribute it and/or modify it under terms of the GNU General -- -- Public License as published by the Free Software Foundation; -- -- either version 2, or (at your option) any later version. McKae -- -- Software Utilities are distributed in the hope that they 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. You should -- -- have received a copy of the GNU General Public License distributed -- -- with DTraq; see file COPYING. If not, write to the Free Software -- -- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -- -- USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- -- -- -- The McKae Software Utilities are maintained by McKae Technologies -- -- (http://www.mckae.com). -- ------------------------------------------------------------------------ package McKae.XML is pragma Pure; end McKae.XML; alire-1.2.1/deps/xmlezout/mckae.ads000066400000000000000000000041631330747631400172160ustar00rootroot00000000000000------------------------------------------------------------------------ -- -- -- McKae Software Utilities -- -- -- -- Copyright (C) 2003 McKae Technologies -- -- -- -- The McKae software utilities are free software; you can -- -- redistribute it and/or modify it under terms of the GNU General -- -- Public License as published by the Free Software Foundation; -- -- either version 2, or (at your option) any later version. McKae -- -- Software Utilities are distributed in the hope that they 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. You should -- -- have received a copy of the GNU General Public License distributed -- -- with DTraq; see file COPYING. If not, write to the Free Software -- -- Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, -- -- USA. -- -- -- -- As a special exception, if other files instantiate generics from -- -- this unit, or you link this unit with other files to produce an -- -- executable, this unit does not by itself cause the resulting -- -- executable to be covered by the GNU General Public License. This -- -- exception does not however invalidate any other reasons why the -- -- executable file might be covered by the GNU Public License. -- -- -- -- The McKae Software Utilities are maintained by McKae Technologies -- -- (http://www.mckae.com). -- ------------------------------------------------------------------------ package McKae is pragma Pure; end McKae; alire-1.2.1/deps/xmlezout/tmeztf.adb000066400000000000000000000145161330747631400174310ustar00rootroot00000000000000with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Text_Io; use Text_IO; with Mckae.Xml.Ez_Out.Generic_Medium; with Mckae.Xml.Ez_Out.Text_File; use Mckae.Xml.Ez_Out.Text_File; with Mckae.XML.Ez_Out.String_Stream; procedure Tmeztf is use Mckae.Xml.Ez_Out; use String_Stream; use XML_String_Buffer; package Ezcs is new Mckae.Xml.Ez_Out.Generic_Medium (File_Type, Put, New_Line, Continuous_Stream); use Ezcs; package Ezsi is new Mckae.Xml.Ez_Out.Generic_Medium (File_Type, Put, New_Line, Spread_Indented); use Ezsi; State : Unbounded_String := To_Unbounded_String("state"); Zip : Unbounded_String := To_Unbounded_String("zipcode"); MN : Unbounded_String := To_Unbounded_String("MN"); Bud : Unbounded_String := To_Unbounded_String("Bud"); Ss : Mckae.Xml.Ez_Out.String_Stream.String_Buffer (500, 500); begin Put_Line("Continuous Stream:"); New_Line; Ezcs.Output_Xml_Header(Standard_Output); Ezcs.Output_Processing_Instruction(Standard_Output, "stylesheet", "bob.xsl"); Ezcs.Start_Element(Standard_Output, "parent", "name" = "jones"); Ezcs.Output_Tag(Standard_Output, "child", ("name" = "jane", "sex" = 'F', "age" = 7, "height"=54.7)); Ezcs.Output_Tag(Standard_Output, "child", ("name" = "Tom", "sex" = 'M', "age" = 4, "height"=44.7)); Ezcs.Output_Tag(Standard_Output, "residence", (State = "AL", Zip = 35806, "temp" = -2)); Ezcs.Output_Element(Standard_Output, "child", "Third and last", ("name" = "Tom", "age" = 1, "height"=24.7)); Ezcs.End_Element(Standard_Output, "parent"); New_Line(2); Put_Line("Indented:"); New_Line; Ezsi.Output_Xml_Header(Standard_Output); Ezsi.Output_Processing_Instruction(Standard_Output, "stylesheet", "bob.xsl"); Ezsi.Output_Tag(Standard_Output, "fred", (("tom" = "harry"), ("mike" = 32))); Ezsi.Start_Element(Standard_Output, "parent", "name" = "jones"); Ezsi.Output_Tag(Standard_Output, "child", ("name" = "jane", "age" = 7, "height"=54.7)); Ezsi.Output_Tag(Standard_Output, "child", ("name" = "Tom", "age" = 4, "height"=44.7)); Ezsi.Output_Tag(Standard_Output, "associate", "name" = Bud); Ezsi.Start_Element(Standard_Output, "child", ("name" = "Tom", "age" = 1, "height"=24.7)); Ezsi.Output_Content(Standard_Output, "Keeping up the Joneses"); Ezsi.End_Element(Standard_Output); Ezsi.End_Element(Standard_Output, "parent"); New_Line; Put_Line("Text File output:"); New_Line; Text_File.Output_Xml_Header(Standard_Output); Text_File.Output_Processing_Instruction(Standard_Output, "stylesheet", "bob.xsl"); Text_File.Start_Element(Standard_Output, "parent", "name" = "jones"); Text_File.Output_Tag(Standard_Output, "child", ("name" = "jane", "age" = 7, "height"=54.7)); Text_File.Output_Tag(Standard_Output, "child", ("name" = "Tom", "age" = 4, "height"=44.7)); Text_File.Output_Element(Standard_Output, "child", "Third", ("name" = "Tom", "age" = 1, "height"=24.7)); Text_File.Output_Element(Standard_Output, "child", "Fourth & last", ("name" = "Tom", "age" = 1, "height"=24.7)); Text_File.Output_Tag(Standard_Output, "fred", (("tom" = "harry"), ("mike" = 32))); Text_File.Output_Tag(Standard_Output, "residence", (State = "", Zip = 55067)); -- Change the setting for outputting null-valued attributes. Text_File.Default_Output_Null_Attributes := True; Text_File.Output_Tag(Standard_Output, "undercover", (State = "", Zip = 55067)); Text_File.End_Element(Standard_Output, "parent"); New_Line(2); Put_Line("String stream output:"); New_Line; Xml_String_Buffer.Output_Xml_Header(Ss); Xml_String_Buffer.Output_Processing_Instruction(Ss, "stylesheet", "bob.xsl"); Xml_String_Buffer.Start_Element(Ss, "parent", "name" = "jones"); Xml_String_Buffer.Output_Tag(Ss, "child", ("name" = "jane", "age" = 7, "height"=54.7)); Xml_String_Buffer.Output_Tag(Ss, "child", ("name" = "Tom", "age" = 4, "height"=44.7)); Xml_String_Buffer.Output_Element(Ss, "child", "Third and last", ("name" = "Tom", "age" = 1, "height"=24.7)); Xml_String_Buffer.Output_Tag(Ss, "fred", (("tom" = "harry"), ("mike" = 32))); Xml_String_Buffer.End_Element(Ss, "parent"); Put_Line(String_Stream.Get_String(Ss)); end Tmeztf; alire-1.2.1/deps/xmlezout/xml_ez_out.gpr000066400000000000000000000002421330747631400203360ustar00rootroot00000000000000project Xml_Ez_Out is for Main use ("tmeztf.adb"); package Compiler is for Default_Switches ("ada") use ("-O2"); end Compiler; end Xml_Ez_Out; pax_global_header00006660000000000000000000000064132314176050014514gustar00rootroot0000000000000052 comment=ce78e7706c9d3f97605df48d8befca5407f8d328 alire-1.2.1/testsuite/fixtures/crates/libhello_git/000077500000000000000000000000001323141760500224315ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libhello_git/.gitignore000066400000000000000000000000741323141760500244220ustar00rootroot00000000000000# Object files lib obj *.o # Ada Library Information *.ali alire-1.2.1/testsuite/fixtures/crates/libhello_git/LICENSE000066400000000000000000000020561323141760500234410ustar00rootroot00000000000000MIT License Copyright (c) 2017 alire-project Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. alire-1.2.1/testsuite/fixtures/crates/libhello_git/README.md000066400000000000000000000000501323141760500237030ustar00rootroot00000000000000# libhello Demo "Hello, world!" library alire-1.2.1/testsuite/fixtures/crates/libhello_git/libhello.gpr000066400000000000000000000002421323141760500247330ustar00rootroot00000000000000project Libhello is for Source_Dirs use ("src"); for Object_Dir use "obj"; for Library_Name use "hello"; for Library_Dir use "lib"; end Libhello; alire-1.2.1/testsuite/fixtures/crates/libhello_git/src/000077500000000000000000000000001323141760500232205ustar00rootroot00000000000000alire-1.2.1/testsuite/fixtures/crates/libhello_git/src/libhello.adb000066400000000000000000000003561323141760500254660ustar00rootroot00000000000000with Ada.Text_IO; package body libhello is ----------------- -- Hello_World -- ----------------- procedure Hello_World is use Ada.Text_IO; begin Put_Line ("Hello, world!"); end Hello_World; end libhello; alire-1.2.1/testsuite/fixtures/crates/libhello_git/src/libhello.ads000066400000000000000000000000761323141760500255060ustar00rootroot00000000000000package libhello is procedure Hello_World; end libhello;